diff --git a/dist/js/select2.full.js b/dist/js/select2.full.js index 49cb11ee69..891255dc74 100644 --- a/dist/js/select2.full.js +++ b/dist/js/select2.full.js @@ -1386,9 +1386,14 @@ S2.define('select2/selection/base',[ var id = container.id + '-container'; var resultsId = container.id + '-results'; var searchHidden = this.options.get('minimumResultsForSearch') === Infinity; + var isRequired = this.options.get('required') === true; this.container = container; + if (isRequired) { + this.$selection.attr('aria-required', 'true') + } + this.$selection.on('focus', function (evt) { self.trigger('focus', evt); }); @@ -1545,6 +1550,11 @@ S2.define('select2/selection/single',[ SingleSelection.__super__.bind.apply(this, arguments); + var isRequired = this.options.get('required') === true; + if (isRequired) { + this.$selection.find('.select2-selection__rendered').attr('aria-required', 'true') + } + var id = container.id + '-container'; this.$selection.find('.select2-selection__rendered') @@ -4405,7 +4415,6 @@ S2.define('select2/dropdown/attachBody',[ var parentOffset = $offsetParent.offset(); - css.top -= parentOffset.top; css.left -= parentOffset.left; if (!isCurrentlyAbove && !isCurrentlyBelow) { @@ -4420,7 +4429,7 @@ S2.define('select2/dropdown/attachBody',[ if (newDirection == 'above' || (isCurrentlyAbove && newDirection !== 'below')) { - css.top = container.top - parentOffset.top - dropdown.height; + css.top = container.top - dropdown.height; } if (newDirection != null) { @@ -5064,6 +5073,10 @@ S2.define('select2/options',[ this.options.disabled = $e.prop('disabled'); } + if (!this.options.required) { + this.options.required = $e.prop('required'); + } + if (this.options.language == null) { if ($e.prop('lang')) { this.options.language = $e.prop('lang').toLowerCase(); diff --git a/dist/js/select2.js b/dist/js/select2.js index 3f27bbd403..f2d27cff86 100644 --- a/dist/js/select2.js +++ b/dist/js/select2.js @@ -1386,9 +1386,14 @@ S2.define('select2/selection/base',[ var id = container.id + '-container'; var resultsId = container.id + '-results'; var searchHidden = this.options.get('minimumResultsForSearch') === Infinity; + var isRequired = this.options.get('required') === true; this.container = container; + if (isRequired) { + this.$selection.attr('aria-required', 'true') + } + this.$selection.on('focus', function (evt) { self.trigger('focus', evt); }); @@ -1545,6 +1550,11 @@ S2.define('select2/selection/single',[ SingleSelection.__super__.bind.apply(this, arguments); + var isRequired = this.options.get('required') === true; + if (isRequired) { + this.$selection.find('.select2-selection__rendered').attr('aria-required', 'true') + } + var id = container.id + '-container'; this.$selection.find('.select2-selection__rendered') @@ -4405,7 +4415,6 @@ S2.define('select2/dropdown/attachBody',[ var parentOffset = $offsetParent.offset(); - css.top -= parentOffset.top; css.left -= parentOffset.left; if (!isCurrentlyAbove && !isCurrentlyBelow) { @@ -4420,7 +4429,7 @@ S2.define('select2/dropdown/attachBody',[ if (newDirection == 'above' || (isCurrentlyAbove && newDirection !== 'below')) { - css.top = container.top - parentOffset.top - dropdown.height; + css.top = container.top - dropdown.height; } if (newDirection != null) { @@ -5064,6 +5073,10 @@ S2.define('select2/options',[ this.options.disabled = $e.prop('disabled'); } + if (!this.options.required) { + this.options.required = $e.prop('required'); + } + if (this.options.language == null) { if ($e.prop('lang')) { this.options.language = $e.prop('lang').toLowerCase(); diff --git a/dist/js/selectWoo.full.js b/dist/js/selectWoo.full.js index 3bb1e66a46..9a50448cd8 100644 --- a/dist/js/selectWoo.full.js +++ b/dist/js/selectWoo.full.js @@ -1,5 +1,5 @@ /*! - * SelectWoo 1.0.10 + * SelectWoo 1.0.11 * https://github.com/woocommerce/selectWoo * * Released under the MIT license @@ -1386,9 +1386,14 @@ S2.define('select2/selection/base',[ var id = container.id + '-container'; var resultsId = container.id + '-results'; var searchHidden = this.options.get('minimumResultsForSearch') === Infinity; + var isRequired = this.options.get('required') === true; this.container = container; + if (isRequired) { + this.$selection.attr('aria-required', 'true') + } + this.$selection.on('focus', function (evt) { self.trigger('focus', evt); }); @@ -1545,6 +1550,11 @@ S2.define('select2/selection/single',[ SingleSelection.__super__.bind.apply(this, arguments); + var isRequired = this.options.get('required') === true; + if (isRequired) { + this.$selection.find('.select2-selection__rendered').attr('aria-required', 'true') + } + var id = container.id + '-container'; this.$selection.find('.select2-selection__rendered') @@ -5063,6 +5073,10 @@ S2.define('select2/options',[ this.options.disabled = $e.prop('disabled'); } + if (!this.options.required) { + this.options.required = $e.prop('required'); + } + if (this.options.language == null) { if ($e.prop('lang')) { this.options.language = $e.prop('lang').toLowerCase(); diff --git a/dist/js/selectWoo.js b/dist/js/selectWoo.js index b602cbb0af..13a939b788 100644 --- a/dist/js/selectWoo.js +++ b/dist/js/selectWoo.js @@ -1,5 +1,5 @@ /*! - * SelectWoo 1.0.10 + * SelectWoo 1.0.11 * https://github.com/woocommerce/selectWoo * * Released under the MIT license @@ -1386,9 +1386,14 @@ S2.define('select2/selection/base',[ var id = container.id + '-container'; var resultsId = container.id + '-results'; var searchHidden = this.options.get('minimumResultsForSearch') === Infinity; + var isRequired = this.options.get('required') === true; this.container = container; + if (isRequired) { + this.$selection.attr('aria-required', 'true') + } + this.$selection.on('focus', function (evt) { self.trigger('focus', evt); }); @@ -1545,6 +1550,11 @@ S2.define('select2/selection/single',[ SingleSelection.__super__.bind.apply(this, arguments); + var isRequired = this.options.get('required') === true; + if (isRequired) { + this.$selection.find('.select2-selection__rendered').attr('aria-required', 'true') + } + var id = container.id + '-container'; this.$selection.find('.select2-selection__rendered') @@ -5063,6 +5073,10 @@ S2.define('select2/options',[ this.options.disabled = $e.prop('disabled'); } + if (!this.options.required) { + this.options.required = $e.prop('required'); + } + if (this.options.language == null) { if ($e.prop('lang')) { this.options.language = $e.prop('lang').toLowerCase(); diff --git a/docs/accessibility-testing/index.html b/docs/accessibility-testing/index.html index d781a11675..9218df4459 100644 --- a/docs/accessibility-testing/index.html +++ b/docs/accessibility-testing/index.html @@ -12,5 +12,6 @@

SelectWoo Accessibility Testing Samples

  • Single select with ajax
  • Multiselect
  • Multiselect with ajax
  • +
  • Single select with required option
  • \ No newline at end of file diff --git a/docs/accessibility-testing/samples/required.html b/docs/accessibility-testing/samples/required.html new file mode 100644 index 0000000000..06f64747bc --- /dev/null +++ b/docs/accessibility-testing/samples/required.html @@ -0,0 +1,24 @@ + + Single select with required option + + + + + + + + +

    Required attribute

    + + + + + + + diff --git a/docs/accessibility-testing/selectWoo.full.js b/docs/accessibility-testing/selectWoo.full.js index d973690988..9e065c9897 100644 --- a/docs/accessibility-testing/selectWoo.full.js +++ b/docs/accessibility-testing/selectWoo.full.js @@ -1,5 +1,5 @@ /*! - * SelectWoo 1.0.1 + * SelectWoo 1.0.11 * https://github.com/woocommerce/selectWoo * * Released under the MIT license @@ -36,53 +36,53 @@ // The inner file should be wrapped (by `banner.start.js`) in a function that // returns the AMD loader references. 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) { - var S2 = jQuery.fn.select2.amd; - } -var S2;(function () { if (!S2 || !S2.requirejs) { -if (!S2) { S2 = {}; } else { require = S2; } -/** - * @license almond 0.3.3 Copyright jQuery Foundation and other contributors. - * Released under MIT license, http://github.com/requirejs/almond/LICENSE - */ + // 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) { + var S2 = jQuery.fn.select2.amd; + } + var S2;(function () { if (!S2 || !S2.requirejs) { + if (!S2) { S2 = {}; } else { require = S2; } + /** + * @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. -/*global setTimeout: false */ - -var requirejs, require, define; -(function (undef) { - var main, req, makeMap, handlers, - defined = {}, - waiting = {}, - config = {}, - defining = {}, - hasOwn = Object.prototype.hasOwnProperty, - aps = [].slice, - jsSuffixRegExp = /\.js$/; - - function hasProp(obj, prop) { - return hasOwn.call(obj, prop); - } + /*global setTimeout: false */ + + var requirejs, require, define; + (function (undef) { + var main, req, makeMap, handlers, + defined = {}, + waiting = {}, + config = {}, + defining = {}, + hasOwn = Object.prototype.hasOwnProperty, + aps = [].slice, + jsSuffixRegExp = /\.js$/; + + function hasProp(obj, prop) { + return hasOwn.call(obj, prop); + } - /** - * Given a relative module name, like ./something, normalize it to - * a real name that can be mapped to a path. - * @param {String} name the relative name - * @param {String} baseName a real name that the name arg is relative - * to. - * @returns {String} normalized name - */ - function normalize(name, baseName) { - var nameParts, nameSegment, mapValue, foundMap, lastIndex, + /** + * Given a relative module name, like ./something, normalize it to + * a real name that can be mapped to a path. + * @param {String} name the relative name + * @param {String} baseName a real name that the name arg is relative + * to. + * @returns {String} normalized name + */ + function normalize(name, baseName) { + var nameParts, nameSegment, mapValue, foundMap, lastIndex, foundI, foundStarMap, starI, i, j, part, normalizedBaseParts, baseParts = baseName && baseName.split("/"), map = config.map, starMap = (map && map['*']) || {}; - //Adjust any relative paths. - if (name) { + //Adjust any relative paths. + if (name) { name = name.split('/'); lastIndex = name.length - 1; @@ -91,101 +91,101 @@ var requirejs, require, define; // 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, ''); + name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, ''); } // 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); + //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; - } + 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('/'); - } + } - //Apply map config if available. - if ((baseParts || starMap) && map) { + //Apply map config if available. + if ((baseParts || starMap) && map) { nameParts = name.split('/'); for (i = nameParts.length; i > 0; i -= 1) { - nameSegment = nameParts.slice(0, i).join("/"); - - if (baseParts) { - //Find the longest baseName segment match in the config. - //So, do joins on the biggest to smallest lengths of baseParts. - for (j = baseParts.length; j > 0; j -= 1) { - mapValue = map[baseParts.slice(0, j).join('/')]; - - //baseName segment has config, find if it has one for - //this name. - if (mapValue) { - mapValue = mapValue[nameSegment]; - if (mapValue) { - //Match, update name to the new value. - foundMap = mapValue; - foundI = i; - break; - } - } + nameSegment = nameParts.slice(0, i).join("/"); + + if (baseParts) { + //Find the longest baseName segment match in the config. + //So, do joins on the biggest to smallest lengths of baseParts. + for (j = baseParts.length; j > 0; j -= 1) { + mapValue = map[baseParts.slice(0, j).join('/')]; + + //baseName segment has config, find if it has one for + //this name. + if (mapValue) { + mapValue = mapValue[nameSegment]; + if (mapValue) { + //Match, update name to the new value. + foundMap = mapValue; + foundI = i; + break; } + } } - - if (foundMap) { - break; - } - - //Check for a star map match, but just hold on to it, - //if there is a shorter segment match later in a matching - //config, then favor over this star map. - if (!foundStarMap && starMap && starMap[nameSegment]) { - foundStarMap = starMap[nameSegment]; - starI = i; - } + } + + if (foundMap) { + break; + } + + //Check for a star map match, but just hold on to it, + //if there is a shorter segment match later in a matching + //config, then favor over this star map. + if (!foundStarMap && starMap && starMap[nameSegment]) { + foundStarMap = starMap[nameSegment]; + starI = i; + } } if (!foundMap && foundStarMap) { - foundMap = foundStarMap; - foundI = starI; + foundMap = foundStarMap; + foundI = starI; } if (foundMap) { - nameParts.splice(0, foundI, foundMap); - name = nameParts.join('/'); + nameParts.splice(0, foundI, foundMap); + name = nameParts.join('/'); } - } + } - return name; - } + return name; + } - function makeRequire(relName, forceSync) { - return function () { + function makeRequire(relName, forceSync) { + return function () { //A version of a require function that passes a moduleName //value for items that may need to //look up paths relative to the moduleName @@ -195,238 +195,238 @@ var requirejs, require, define; //one arg, it is the array form without a callback. Insert //a null so that the following concat is correct. if (typeof args[0] !== 'string' && args.length === 1) { - args.push(null); + args.push(null); } return req.apply(undef, args.concat([relName, forceSync])); - }; - } + }; + } - function makeNormalize(relName) { - return function (name) { + function makeNormalize(relName) { + return function (name) { return normalize(name, relName); - }; - } + }; + } - function makeLoad(depName) { - return function (value) { + function makeLoad(depName) { + return function (value) { defined[depName] = value; - }; - } + }; + } - function callDep(name) { - if (hasProp(waiting, name)) { + function callDep(name) { + if (hasProp(waiting, name)) { var args = waiting[name]; delete waiting[name]; defining[name] = true; main.apply(undef, args); - } + } - if (!hasProp(defined, name) && !hasProp(defining, name)) { + if (!hasProp(defined, name) && !hasProp(defining, name)) { throw new Error('No ' + name); + } + return defined[name]; } - return defined[name]; - } - //Turns a plugin!resource to [plugin, resource] - //with the plugin being undefined if the name - //did not have a plugin prefix. - function splitPrefix(name) { - var prefix, + //Turns a plugin!resource to [plugin, resource] + //with the plugin being undefined if the name + //did not have a plugin prefix. + function splitPrefix(name) { + var prefix, index = name ? name.indexOf('!') : -1; - if (index > -1) { + if (index > -1) { prefix = name.substring(0, index); name = name.substring(index + 1, name.length); + } + return [prefix, name]; } - 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) : []; - } + //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, relParts) { - var plugin, + /** + * 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, relParts) { + var plugin, parts = splitPrefix(name), prefix = parts[0], relResourceName = relParts[1]; - name = parts[1]; + name = parts[1]; - if (prefix) { + if (prefix) { prefix = normalize(prefix, relResourceName); plugin = callDep(prefix); - } + } - //Normalize according - if (prefix) { + //Normalize according + if (prefix) { if (plugin && plugin.normalize) { - name = plugin.normalize(name, makeNormalize(relResourceName)); + name = plugin.normalize(name, makeNormalize(relResourceName)); } else { - name = normalize(name, relResourceName); + name = normalize(name, relResourceName); } - } else { + } else { name = normalize(name, relResourceName); parts = splitPrefix(name); prefix = parts[0]; name = parts[1]; if (prefix) { - plugin = callDep(prefix); + plugin = callDep(prefix); } - } + } - //Using ridiculous property names for space reasons - return { + //Using ridiculous property names for space reasons + return { f: prefix ? prefix + '!' + name : name, //fullName n: name, pr: prefix, p: plugin + }; }; - }; - function makeConfig(name) { - return function () { + function makeConfig(name) { + return function () { return (config && config.config && config.config[name]) || {}; - }; - } + }; + } - handlers = { - require: function (name) { + handlers = { + require: function (name) { return makeRequire(name); - }, - exports: function (name) { + }, + exports: function (name) { var e = defined[name]; if (typeof e !== 'undefined') { - return e; + return e; } else { - return (defined[name] = {}); + return (defined[name] = {}); } - }, - module: function (name) { + }, + module: function (name) { return { - id: name, - uri: '', - exports: defined[name], - config: makeConfig(name) + id: name, + uri: '', + exports: defined[name], + config: makeConfig(name) }; - } - }; + } + }; - main = function (name, deps, callback, relName) { - var cjsModule, depName, ret, map, i, relParts, + main = function (name, deps, callback, relName) { + var cjsModule, depName, ret, map, i, relParts, args = [], callbackType = typeof callback, usingExports; - //Use name if no relName - relName = relName || name; - relParts = makeRelParts(relName); + //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') { + //Call the callback to define the module, if necessary. + if (callbackType === 'undefined' || callbackType === 'function') { //Pull out the defined dependencies and pass the ordered //values to the callback. //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], relParts); - depName = map.f; - - //Fast path CommonJS standard dependencies. - if (depName === "require") { - args[i] = handlers.require(name); - } else if (depName === "exports") { - //CommonJS module spec 1.1 - args[i] = handlers.exports(name); - usingExports = true; - } else if (depName === "module") { - //CommonJS module spec 1.1 - cjsModule = args[i] = handlers.module(name); - } else if (hasProp(defined, depName) || - hasProp(waiting, depName) || - hasProp(defining, depName)) { - args[i] = callDep(depName); - } else if (map.p) { - map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {}); - args[i] = defined[depName]; - } else { - throw new Error(name + ' missing ' + depName); - } + map = makeMap(deps[i], relParts); + depName = map.f; + + //Fast path CommonJS standard dependencies. + if (depName === "require") { + args[i] = handlers.require(name); + } else if (depName === "exports") { + //CommonJS module spec 1.1 + args[i] = handlers.exports(name); + usingExports = true; + } else if (depName === "module") { + //CommonJS module spec 1.1 + cjsModule = args[i] = handlers.module(name); + } else if (hasProp(defined, depName) || + hasProp(waiting, depName) || + hasProp(defining, depName)) { + args[i] = callDep(depName); + } else if (map.p) { + map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {}); + args[i] = defined[depName]; + } else { + throw new Error(name + ' missing ' + depName); + } } ret = callback ? callback.apply(defined[name], args) : undefined; if (name) { - //If setting exports via "module" is in play, - //favor that over return value and exports. After that, - //favor a non-undefined return value over exports use. - if (cjsModule && cjsModule.exports !== undef && - cjsModule.exports !== defined[name]) { - defined[name] = cjsModule.exports; - } else if (ret !== undef || !usingExports) { - //Use the return value from the function. - defined[name] = ret; - } + //If setting exports via "module" is in play, + //favor that over return value and exports. After that, + //favor a non-undefined return value over exports use. + if (cjsModule && cjsModule.exports !== undef && + cjsModule.exports !== defined[name]) { + defined[name] = cjsModule.exports; + } else if (ret !== undef || !usingExports) { + //Use the return value from the function. + defined[name] = ret; + } } - } else if (name) { + } else if (name) { //May just be an object definition for the module. Only //worry about defining if have a module name. defined[name] = callback; - } - }; + } + }; - requirejs = require = req = function (deps, callback, relName, forceSync, alt) { - if (typeof deps === "string") { + requirejs = require = req = function (deps, callback, relName, forceSync, alt) { + if (typeof deps === "string") { if (handlers[deps]) { - //callback in this case is really relName - return handlers[deps](callback); + //callback in this case is really relName + return handlers[deps](callback); } //Just return the module wanted. In this scenario, the //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, makeRelParts(callback)).f); - } else if (!deps.splice) { + } else if (!deps.splice) { //deps is a config object, not an array. config = deps; if (config.deps) { - req(config.deps, config.callback); + req(config.deps, config.callback); } if (!callback) { - return; + return; } if (callback.splice) { - //callback is an array, which means it is a dependency list. - //Adjust args if there are dependencies - deps = callback; - callback = relName; - relName = null; + //callback is an array, which means it is a dependency list. + //Adjust args if there are dependencies + deps = callback; + callback = relName; + relName = null; } else { - deps = undef; + deps = undef; } - } + } - //Support require(['a']) - callback = callback || function () {}; + //Support require(['a']) + callback = callback || function () {}; - //If relName is a function, it is an errback handler, - //so remove it. - if (typeof relName === 'function') { + //If relName is a function, it is an errback handler, + //so remove it. + if (typeof relName === 'function') { relName = forceSync; forceSync = alt; - } + } - //Simulate async callback; - if (forceSync) { + //Simulate async callback; + if (forceSync) { main(undef, deps, callback, relName); - } else { + } else { //Using a non-zero value because of concern for what old browsers //do, and latest browsers "upgrade" to 4 if lower value is used: //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout: @@ -434,5817 +434,5877 @@ var requirejs, require, define; //that works in almond on the global level, but not guaranteed and //unlikely to work in other AMD implementations. setTimeout(function () { - main(undef, deps, callback, relName); + main(undef, deps, callback, relName); }, 4); - } + } - return req; - }; + return req; + }; - /** - * Just drops the config on the floor, but returns req in case - * the config return value is used. - */ - req.config = function (cfg) { - return req(cfg); - }; + /** + * Just drops the config on the floor, but returns req in case + * the config return value is used. + */ + req.config = function (cfg) { + return req(cfg); + }; - /** - * Expose module registry for debugging and tooling - */ - requirejs._defined = defined; + /** + * Expose module registry for debugging and tooling + */ + requirejs._defined = defined; - define = function (name, deps, callback) { - if (typeof name !== 'string') { + define = function (name, deps, callback) { + if (typeof name !== 'string') { throw new Error('See almond README: incorrect module build, no module name'); - } + } - //This module may not have dependencies - if (!deps.splice) { + //This module may not have dependencies + if (!deps.splice) { //deps is not an array, so probably means //an object literal or factory function for //the value. Adjust args. callback = deps; deps = []; - } + } - if (!hasProp(defined, name) && !hasProp(waiting, name)) { + if (!hasProp(defined, name) && !hasProp(waiting, name)) { waiting[name] = [name, deps, callback]; - } - }; - - define.amd = { - jQuery: true - }; -}()); - -S2.requirejs = requirejs;S2.require = require;S2.define = define; -} -}()); -S2.define("almond", function(){}); - -/* global jQuery:false, $:false */ -S2.define('jquery',[],function () { - var _$ = jQuery || $; - - if (_$ == null && console && console.error) { - console.error( - 'Select2: An instance of jQuery or a jQuery-compatible library was not ' + - 'found. Make sure that you are including jQuery before Select2 on your ' + - 'web page.' - ); - } - - return _$; -}); - -S2.define('select2/utils',[ - 'jquery' -], function ($) { - var Utils = {}; + } + }; - Utils.Extend = function (ChildClass, SuperClass) { - var __hasProp = {}.hasOwnProperty; + define.amd = { + jQuery: true + }; + }()); - function BaseConstructor () { - this.constructor = ChildClass; + S2.requirejs = requirejs;S2.require = require;S2.define = define; } + }()); + S2.define("almond", function(){}); - for (var key in SuperClass) { - if (__hasProp.call(SuperClass, key)) { - ChildClass[key] = SuperClass[key]; - } - } + /* global jQuery:false, $:false */ + S2.define('jquery',[],function () { + var _$ = jQuery || $; - BaseConstructor.prototype = SuperClass.prototype; - ChildClass.prototype = new BaseConstructor(); - ChildClass.__super__ = SuperClass.prototype; + if (_$ == null && console && console.error) { + console.error( + 'Select2: An instance of jQuery or a jQuery-compatible library was not ' + + 'found. Make sure that you are including jQuery before Select2 on your ' + + 'web page.' + ); + } - return ChildClass; - }; + return _$; + }); - function getMethods (theClass) { - var proto = theClass.prototype; + S2.define('select2/utils',[ + 'jquery' + ], function ($) { + var Utils = {}; - var methods = []; + Utils.Extend = function (ChildClass, SuperClass) { + var __hasProp = {}.hasOwnProperty; - for (var methodName in proto) { - var m = proto[methodName]; + function BaseConstructor () { + this.constructor = ChildClass; + } - if (typeof m !== 'function') { - continue; - } + for (var key in SuperClass) { + if (__hasProp.call(SuperClass, key)) { + ChildClass[key] = SuperClass[key]; + } + } - if (methodName === 'constructor') { - continue; - } + BaseConstructor.prototype = SuperClass.prototype; + ChildClass.prototype = new BaseConstructor(); + ChildClass.__super__ = SuperClass.prototype; - methods.push(methodName); - } + return ChildClass; + }; - return methods; - } + function getMethods (theClass) { + var proto = theClass.prototype; - Utils.Decorate = function (SuperClass, DecoratorClass) { - var decoratedMethods = getMethods(DecoratorClass); - var superMethods = getMethods(SuperClass); + var methods = []; - function DecoratedClass () { - var unshift = Array.prototype.unshift; + for (var methodName in proto) { + var m = proto[methodName]; - var argCount = DecoratorClass.prototype.constructor.length; + if (typeof m !== 'function') { + continue; + } - var calledConstructor = SuperClass.prototype.constructor; + if (methodName === 'constructor') { + continue; + } - if (argCount > 0) { - unshift.call(arguments, SuperClass.prototype.constructor); + methods.push(methodName); + } - calledConstructor = DecoratorClass.prototype.constructor; + return methods; } - calledConstructor.apply(this, arguments); - } - - DecoratorClass.displayName = SuperClass.displayName; - - function ctr () { - this.constructor = DecoratedClass; - } + Utils.Decorate = function (SuperClass, DecoratorClass) { + var decoratedMethods = getMethods(DecoratorClass); + var superMethods = getMethods(SuperClass); - DecoratedClass.prototype = new ctr(); + function DecoratedClass () { + var unshift = Array.prototype.unshift; - for (var m = 0; m < superMethods.length; m++) { - var superMethod = superMethods[m]; + var argCount = DecoratorClass.prototype.constructor.length; - DecoratedClass.prototype[superMethod] = - SuperClass.prototype[superMethod]; - } + var calledConstructor = SuperClass.prototype.constructor; - var calledMethod = function (methodName) { - // Stub out the original method if it's not decorating an actual method - var originalMethod = function () {}; + if (argCount > 0) { + unshift.call(arguments, SuperClass.prototype.constructor); - if (methodName in DecoratedClass.prototype) { - originalMethod = DecoratedClass.prototype[methodName]; - } + calledConstructor = DecoratorClass.prototype.constructor; + } - var decoratedMethod = DecoratorClass.prototype[methodName]; + calledConstructor.apply(this, arguments); + } - return function () { - var unshift = Array.prototype.unshift; + DecoratorClass.displayName = SuperClass.displayName; - unshift.call(arguments, originalMethod); + function ctr () { + this.constructor = DecoratedClass; + } - return decoratedMethod.apply(this, arguments); - }; - }; + DecoratedClass.prototype = new ctr(); - for (var d = 0; d < decoratedMethods.length; d++) { - var decoratedMethod = decoratedMethods[d]; + for (var m = 0; m < superMethods.length; m++) { + var superMethod = superMethods[m]; - DecoratedClass.prototype[decoratedMethod] = calledMethod(decoratedMethod); - } + DecoratedClass.prototype[superMethod] = + SuperClass.prototype[superMethod]; + } - return DecoratedClass; - }; + var calledMethod = function (methodName) { + // Stub out the original method if it's not decorating an actual method + var originalMethod = function () {}; - var Observable = function () { - this.listeners = {}; - }; + if (methodName in DecoratedClass.prototype) { + originalMethod = DecoratedClass.prototype[methodName]; + } - Observable.prototype.on = function (event, callback) { - this.listeners = this.listeners || {}; + var decoratedMethod = DecoratorClass.prototype[methodName]; - if (event in this.listeners) { - this.listeners[event].push(callback); - } else { - this.listeners[event] = [callback]; - } - }; + return function () { + var unshift = Array.prototype.unshift; - Observable.prototype.trigger = function (event) { - var slice = Array.prototype.slice; - var params = slice.call(arguments, 1); + unshift.call(arguments, originalMethod); - this.listeners = this.listeners || {}; + return decoratedMethod.apply(this, arguments); + }; + }; - // Params should always come in as an array - if (params == null) { - params = []; - } + for (var d = 0; d < decoratedMethods.length; d++) { + var decoratedMethod = decoratedMethods[d]; - // If there are no arguments to the event, use a temporary object - if (params.length === 0) { - params.push({}); - } + DecoratedClass.prototype[decoratedMethod] = calledMethod(decoratedMethod); + } - // Set the `_type` of the first object to the event - params[0]._type = event; + return DecoratedClass; + }; - if (event in this.listeners) { - this.invoke(this.listeners[event], slice.call(arguments, 1)); - } + var Observable = function () { + this.listeners = {}; + }; - if ('*' in this.listeners) { - this.invoke(this.listeners['*'], arguments); - } - }; + Observable.prototype.on = function (event, callback) { + this.listeners = this.listeners || {}; - Observable.prototype.invoke = function (listeners, params) { - for (var i = 0, len = listeners.length; i < len; i++) { - listeners[i].apply(this, params); - } - }; + if (event in this.listeners) { + this.listeners[event].push(callback); + } else { + this.listeners[event] = [callback]; + } + }; - Utils.Observable = Observable; + Observable.prototype.trigger = function (event) { + var slice = Array.prototype.slice; + var params = slice.call(arguments, 1); - Utils.generateChars = function (length) { - var chars = ''; + this.listeners = this.listeners || {}; - for (var i = 0; i < length; i++) { - var randomChar = Math.floor(Math.random() * 36); - chars += randomChar.toString(36); - } + // Params should always come in as an array + if (params == null) { + params = []; + } - return chars; - }; + // If there are no arguments to the event, use a temporary object + if (params.length === 0) { + params.push({}); + } - Utils.bind = function (func, context) { - return function () { - func.apply(context, arguments); - }; - }; + // Set the `_type` of the first object to the event + params[0]._type = event; - Utils._convertData = function (data) { - for (var originalKey in data) { - var keys = originalKey.split('-'); + if (event in this.listeners) { + this.invoke(this.listeners[event], slice.call(arguments, 1)); + } - var dataLevel = data; + if ('*' in this.listeners) { + this.invoke(this.listeners['*'], arguments); + } + }; - if (keys.length === 1) { - continue; - } + Observable.prototype.invoke = function (listeners, params) { + for (var i = 0, len = listeners.length; i < len; i++) { + listeners[i].apply(this, params); + } + }; - for (var k = 0; k < keys.length; k++) { - var key = keys[k]; + Utils.Observable = Observable; - // Lowercase the first letter - // By default, dash-separated becomes camelCase - key = key.substring(0, 1).toLowerCase() + key.substring(1); + Utils.generateChars = function (length) { + var chars = ''; - if (!(key in dataLevel)) { - dataLevel[key] = {}; + for (var i = 0; i < length; i++) { + var randomChar = Math.floor(Math.random() * 36); + chars += randomChar.toString(36); } - if (k == keys.length - 1) { - dataLevel[key] = data[originalKey]; - } + return chars; + }; - dataLevel = dataLevel[key]; - } + Utils.bind = function (func, context) { + return function () { + func.apply(context, arguments); + }; + }; - delete data[originalKey]; - } + Utils._convertData = function (data) { + for (var originalKey in data) { + var keys = originalKey.split('-'); - return data; - }; + var dataLevel = data; - Utils.hasScroll = function (index, el) { - // Adapted from the function created by @ShadowScripter - // and adapted by @BillBarry on the Stack Exchange Code Review website. - // The original code can be found at - // http://codereview.stackexchange.com/q/13338 - // and was designed to be used with the Sizzle selector engine. + if (keys.length === 1) { + continue; + } - var $el = $(el); - var overflowX = el.style.overflowX; - var overflowY = el.style.overflowY; + for (var k = 0; k < keys.length; k++) { + var key = keys[k]; - //Check both x and y declarations - if (overflowX === overflowY && - (overflowY === 'hidden' || overflowY === 'visible')) { - return false; - } + // Lowercase the first letter + // By default, dash-separated becomes camelCase + key = key.substring(0, 1).toLowerCase() + key.substring(1); - if (overflowX === 'scroll' || overflowY === 'scroll') { - return true; - } + if (!(key in dataLevel)) { + dataLevel[key] = {}; + } - return ($el.innerHeight() < el.scrollHeight || - $el.innerWidth() < el.scrollWidth); - }; - - Utils.escapeMarkup = function (markup) { - var replaceMap = { - '\\': '\', - '&': '&', - '<': '<', - '>': '>', - '"': '"', - '\'': ''', - '/': '/' - }; + if (k == keys.length - 1) { + dataLevel[key] = data[originalKey]; + } - // Do not try to escape the markup if it's not a string - if (typeof markup !== 'string') { - return markup; - } + dataLevel = dataLevel[key]; + } - return String(markup).replace(/[&<>"'\/\\]/g, function (match) { - return replaceMap[match]; - }); - }; + delete data[originalKey]; + } - // Append an array of jQuery nodes to a given element. - Utils.appendMany = function ($element, $nodes) { - // jQuery 1.7.x does not support $.fn.append() with an array - // Fall back to a jQuery object collection using $.fn.add() - if ($.fn.jquery.substr(0, 3) === '1.7') { - var $jqNodes = $(); + return data; + }; - $.map($nodes, function (node) { - $jqNodes = $jqNodes.add(node); - }); + Utils.hasScroll = function (index, el) { + // Adapted from the function created by @ShadowScripter + // and adapted by @BillBarry on the Stack Exchange Code Review website. + // The original code can be found at + // http://codereview.stackexchange.com/q/13338 + // and was designed to be used with the Sizzle selector engine. + + var $el = $(el); + var overflowX = el.style.overflowX; + var overflowY = el.style.overflowY; + + //Check both x and y declarations + if (overflowX === overflowY && + (overflowY === 'hidden' || overflowY === 'visible')) { + return false; + } - $nodes = $jqNodes; - } + if (overflowX === 'scroll' || overflowY === 'scroll') { + return true; + } - $element.append($nodes); - }; + return ($el.innerHeight() < el.scrollHeight || + $el.innerWidth() < el.scrollWidth); + }; - // Determine whether the browser is on a touchscreen device. - Utils.isTouchscreen = function() { - if ('undefined' === typeof Utils._isTouchscreenCache) { - Utils._isTouchscreenCache = 'ontouchstart' in document.documentElement; - } - return Utils._isTouchscreenCache; - } + Utils.escapeMarkup = function (markup) { + var replaceMap = { + '\\': '\', + '&': '&', + '<': '<', + '>': '>', + '"': '"', + '\'': ''', + '/': '/' + }; - return Utils; -}); + // Do not try to escape the markup if it's not a string + if (typeof markup !== 'string') { + return markup; + } -S2.define('select2/results',[ - 'jquery', - './utils' -], function ($, Utils) { - function Results ($element, options, dataAdapter) { - this.$element = $element; - this.data = dataAdapter; - this.options = options; + return String(markup).replace(/[&<>"'\/\\]/g, function (match) { + return replaceMap[match]; + }); + }; - Results.__super__.constructor.call(this); - } + Utils.entityDecode = function (html) { + var txt = document.createElement('textarea'); + txt.innerHTML = html; + return txt.value; + } - Utils.Extend(Results, Utils.Observable); + // Append an array of jQuery nodes to a given element. + Utils.appendMany = function ($element, $nodes) { + // jQuery 1.7.x does not support $.fn.append() with an array + // Fall back to a jQuery object collection using $.fn.add() + if ($.fn.jquery.substr(0, 3) === '1.7') { + var $jqNodes = $(); - Results.prototype.render = function () { - var $results = $( - '' - ); + $.map($nodes, function (node) { + $jqNodes = $jqNodes.add(node); + }); - if (this.options.get('multiple')) { - $results.attr('aria-multiselectable', 'true'); - } + $nodes = $jqNodes; + } - this.$results = $results; + $element.append($nodes); + }; - return $results; - }; + // Determine whether the browser is on a touchscreen device. + Utils.isTouchscreen = function() { + if ('undefined' === typeof Utils._isTouchscreenCache) { + Utils._isTouchscreenCache = 'ontouchstart' in document.documentElement; + } + return Utils._isTouchscreenCache; + } - Results.prototype.clear = function () { - this.$results.empty(); - }; + return Utils; + }); - Results.prototype.displayMessage = function (params) { - var escapeMarkup = this.options.get('escapeMarkup'); + S2.define('select2/results',[ + 'jquery', + './utils' + ], function ($, Utils) { + function Results ($element, options, dataAdapter) { + this.$element = $element; + this.data = dataAdapter; + this.options = options; - this.clear(); - this.hideLoading(); + Results.__super__.constructor.call(this); + } - var $message = $( - '' - ); + Utils.Extend(Results, Utils.Observable); - var message = this.options.get('translations').get(params.message); + Results.prototype.render = function () { + var $results = $( + '' + ); - $message.append( - escapeMarkup( - message(params.args) - ) - ); + if (this.options.get('multiple')) { + $results.attr('aria-multiselectable', 'true'); + } - $message[0].className += ' select2-results__message'; + this.$results = $results; - this.$results.append($message); - }; + return $results; + }; - Results.prototype.hideMessages = function () { - this.$results.find('.select2-results__message').remove(); - }; + Results.prototype.clear = function () { + this.$results.empty(); + }; - Results.prototype.append = function (data) { - this.hideLoading(); + Results.prototype.displayMessage = function (params) { + var escapeMarkup = this.options.get('escapeMarkup'); - var $options = []; + this.clear(); + this.hideLoading(); - if (data.results == null || data.results.length === 0) { - if (this.$results.children().length === 0) { - this.trigger('results:message', { - message: 'noResults' - }); - } + var $message = $( + '' + ); - return; - } + var message = this.options.get('translations').get(params.message); - data.results = this.sort(data.results); + $message.append( + escapeMarkup( + message(params.args) + ) + ); - for (var d = 0; d < data.results.length; d++) { - var item = data.results[d]; + $message[0].className += ' select2-results__message'; - var $option = this.option(item); + this.$results.append($message); + }; - $options.push($option); - } + Results.prototype.hideMessages = function () { + this.$results.find('.select2-results__message').remove(); + }; - this.$results.append($options); - }; + Results.prototype.append = function (data) { + this.hideLoading(); - Results.prototype.position = function ($results, $dropdown) { - var $resultsContainer = $dropdown.find('.select2-results'); - $resultsContainer.append($results); - }; + var $options = []; - Results.prototype.sort = function (data) { - var sorter = this.options.get('sorter'); + if (data.results == null || data.results.length === 0) { + if (this.$results.children().length === 0) { + this.trigger('results:message', { + message: 'noResults' + }); + } - return sorter(data); - }; + return; + } - Results.prototype.highlightFirstItem = function () { - var $options = this.$results - .find('.select2-results__option[data-selected]'); + data.results = this.sort(data.results); - var $selected = $options.filter('[data-selected=true]'); + for (var d = 0; d < data.results.length; d++) { + var item = data.results[d]; - // 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'); - } + var $option = this.option(item); - this.ensureHighlightVisible(); - }; + $options.push($option); + } - Results.prototype.setClasses = function () { - var self = this; + this.$results.append($options); + }; - this.data.current(function (selected) { - var selectedIds = $.map(selected, function (s) { - return s.id.toString(); - }); + Results.prototype.position = function ($results, $dropdown) { + var $resultsContainer = $dropdown.find('.select2-results'); + $resultsContainer.append($results); + }; - var $options = self.$results - .find('.select2-results__option[data-selected]'); + Results.prototype.sort = function (data) { + var sorter = this.options.get('sorter'); - $options.each(function () { - var $option = $(this); + return sorter(data); + }; - var item = $.data(this, 'data'); + Results.prototype.highlightFirstItem = function () { + var $options = this.$results + .find('.select2-results__option[data-selected]'); - // id needs to be converted to a string when comparing - var id = '' + item.id; + var $selected = $options.filter('[data-selected=true]'); - if ((item.element != null && item.element.selected) || - (item.element == null && $.inArray(id, selectedIds) > -1)) { - $option.attr('data-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 { - $option.attr('data-selected', 'false'); + // If there are no selected options, highlight the first option + // in the dropdown + $options.first().trigger('mouseenter'); } - }); - }); - }; + this.ensureHighlightVisible(); + }; - Results.prototype.showLoading = function (params) { - this.hideLoading(); + Results.prototype.setClasses = function () { + var self = this; - var loadingMore = this.options.get('translations').get('searching'); + this.data.current(function (selected) { + var selectedIds = $.map(selected, function (s) { + return s.id.toString(); + }); - var loading = { - disabled: true, - loading: true, - text: loadingMore(params) - }; - var $loading = this.option(loading); - $loading.className += ' loading-results'; + var $options = self.$results + .find('.select2-results__option[data-selected]'); - this.$results.prepend($loading); - }; + $options.each(function () { + var $option = $(this); - Results.prototype.hideLoading = function () { - this.$results.find('.loading-results').remove(); - }; + var item = $.data(this, 'data'); - Results.prototype.option = function (data) { - var option = document.createElement('li'); - option.className = 'select2-results__option'; + // id needs to be converted to a string when comparing + var id = '' + item.id; - var attrs = { - 'role': 'option', - 'data-selected': 'false', - 'tabindex': -1 - }; + if ((item.element != null && item.element.selected) || + (item.element == null && $.inArray(id, selectedIds) > -1)) { + $option.attr('data-selected', 'true'); + } else { + $option.attr('data-selected', 'false'); + } + }); - if (data.disabled) { - delete attrs['data-selected']; - attrs['aria-disabled'] = 'true'; - } + }); + }; - if (data.id == null) { - delete attrs['data-selected']; - } + Results.prototype.showLoading = function (params) { + this.hideLoading(); - if (data._resultId != null) { - option.id = data._resultId; - } + var loadingMore = this.options.get('translations').get('searching'); - if (data.title) { - option.title = data.title; - } + var loading = { + disabled: true, + loading: true, + text: loadingMore(params) + }; + var $loading = this.option(loading); + $loading.className += ' loading-results'; - if (data.children) { - attrs['aria-label'] = data.text; - delete attrs['data-selected']; - } + this.$results.prepend($loading); + }; - for (var attr in attrs) { - var val = attrs[attr]; + Results.prototype.hideLoading = function () { + this.$results.find('.loading-results').remove(); + }; - option.setAttribute(attr, val); - } + Results.prototype.option = function (data) { + var option = document.createElement('li'); + option.className = 'select2-results__option'; - if (data.children) { - var $option = $(option); + var attrs = { + 'role': 'option', + 'data-selected': 'false', + 'tabindex': -1 + }; - var label = document.createElement('strong'); - label.className = 'select2-results__group'; + if (data.disabled) { + delete attrs['data-selected']; + attrs['aria-disabled'] = 'true'; + } - var $label = $(label); - this.template(data, label); - $label.attr('role', 'presentation'); + if (data.id == null) { + delete attrs['data-selected']; + } - var $children = []; + if (data._resultId != null) { + option.id = data._resultId; + } - for (var c = 0; c < data.children.length; c++) { - var child = data.children[c]; + if (data.title) { + option.title = data.title; + } - var $child = this.option(child); + if (data.children) { + attrs['aria-label'] = data.text; + delete attrs['data-selected']; + } - $children.push($child); - } + for (var attr in attrs) { + var val = attrs[attr]; - var $childrenContainer = $('', { - 'class': 'select2-results__options select2-results__options--nested', - 'role': 'listbox' - }); - $childrenContainer.append($children); - $option.attr('role', 'list'); + option.setAttribute(attr, val); + } - $option.append(label); - $option.append($childrenContainer); - } else { - this.template(data, option); - } + if (data.children) { + var $option = $(option); - $.data(option, 'data', data); + var label = document.createElement('strong'); + label.className = 'select2-results__group'; - return option; - }; + var $label = $(label); + this.template(data, label); + $label.attr('role', 'presentation'); - Results.prototype.bind = function (container, $container) { - var self = this; + var $children = []; - var id = container.id + '-results'; + for (var c = 0; c < data.children.length; c++) { + var child = data.children[c]; - this.$results.attr('id', id); + var $child = this.option(child); - container.on('results:all', function (params) { - self.clear(); - self.append(params.data); + $children.push($child); + } - if (container.isOpen()) { - self.setClasses(); - self.highlightFirstItem(); - } - }); + var $childrenContainer = $('', { + 'class': 'select2-results__options select2-results__options--nested', + 'role': 'listbox' + }); + $childrenContainer.append($children); + $option.attr('role', 'list'); - container.on('results:append', function (params) { - self.append(params.data); + $option.append(label); + $option.append($childrenContainer); + } else { + this.template(data, option); + } - if (container.isOpen()) { - self.setClasses(); - } - }); + $.data(option, 'data', data); - container.on('query', function (params) { - self.hideMessages(); - self.showLoading(params); - }); + return option; + }; - container.on('select', function () { - if (!container.isOpen()) { - return; - } + Results.prototype.bind = function (container, $container) { + var self = this; - self.setClasses(); - self.highlightFirstItem(); - }); + var id = container.id + '-results'; - container.on('unselect', function () { - if (!container.isOpen()) { - return; - } + this.$results.attr('id', id); - self.setClasses(); - self.highlightFirstItem(); - }); + container.on('results:all', function (params) { + self.clear(); + self.append(params.data); - container.on('open', function () { - // When the dropdown is open, aria-expended="true" - self.$results.attr('aria-expanded', 'true'); - self.$results.attr('aria-hidden', 'false'); + if (container.isOpen()) { + self.setClasses(); + self.highlightFirstItem(); + } + }); - self.setClasses(); - self.ensureHighlightVisible(); - }); + container.on('results:append', function (params) { + self.append(params.data); - container.on('close', function () { - // When the dropdown is closed, aria-expended="false" - self.$results.attr('aria-expanded', 'false'); - self.$results.attr('aria-hidden', 'true'); - self.$results.removeAttr('aria-activedescendant'); - }); + if (container.isOpen()) { + self.setClasses(); + } + }); - container.on('results:toggle', function () { - var $highlighted = self.getHighlightedResults(); + container.on('query', function (params) { + self.hideMessages(); + self.showLoading(params); + }); - if ($highlighted.length === 0) { - return; - } + container.on('select', function () { + if (!container.isOpen()) { + return; + } - $highlighted.trigger('mouseup'); - }); + self.setClasses(); + self.highlightFirstItem(); + }); - container.on('results:select', function () { - var $highlighted = self.getHighlightedResults(); + container.on('unselect', function () { + if (!container.isOpen()) { + return; + } - if ($highlighted.length === 0) { - return; - } - - var data = $highlighted.data('data'); - - if ($highlighted.attr('data-selected') == 'true') { - self.trigger('close', {}); - } else { - self.trigger('select', { - data: data + self.setClasses(); + self.highlightFirstItem(); }); - } - }); - - container.on('results:previous', function () { - var $highlighted = self.getHighlightedResults(); - var $options = self.$results.find('[data-selected]'); + container.on('open', function () { + // When the dropdown is open, aria-expended="true" + self.$results.attr('aria-expanded', 'true'); + self.$results.attr('aria-hidden', 'false'); - var currentIndex = $options.index($highlighted); + self.setClasses(); + self.ensureHighlightVisible(); + }); - // If we are already at te top, don't move further - if (currentIndex === 0) { - return; - } + container.on('close', function () { + // When the dropdown is closed, aria-expended="false" + self.$results.attr('aria-expanded', 'false'); + self.$results.attr('aria-hidden', 'true'); + self.$results.removeAttr('aria-activedescendant'); + }); - var nextIndex = currentIndex - 1; + container.on('results:toggle', function () { + var $highlighted = self.getHighlightedResults(); - // If none are highlighted, highlight the first - if ($highlighted.length === 0) { - nextIndex = 0; - } + if ($highlighted.length === 0) { + return; + } - var $next = $options.eq(nextIndex); + $highlighted.trigger('mouseup'); + }); - $next.trigger('mouseenter'); + container.on('results:select', function () { + var $highlighted = self.getHighlightedResults(); - var currentOffset = self.$results.offset().top; - var nextTop = $next.offset().top; - var nextOffset = self.$results.scrollTop() + (nextTop - currentOffset); + if ($highlighted.length === 0) { + return; + } - if (nextIndex === 0) { - self.$results.scrollTop(0); - } else if (nextTop - currentOffset < 0) { - self.$results.scrollTop(nextOffset); - } - }); + var data = $highlighted.data('data'); - container.on('results:next', function () { - var $highlighted = self.getHighlightedResults(); + if ($highlighted.attr('data-selected') == 'true') { + self.trigger('close', {}); + } else { + self.trigger('select', { + data: data + }); + } + }); - var $options = self.$results.find('[data-selected]'); + container.on('results:previous', function () { + var $highlighted = self.getHighlightedResults(); - var currentIndex = $options.index($highlighted); + var $options = self.$results.find('[data-selected]'); - var nextIndex = currentIndex + 1; + var currentIndex = $options.index($highlighted); - // If we are at the last option, stay there - if (nextIndex >= $options.length) { - return; - } + // If we are already at te top, don't move further + if (currentIndex === 0) { + return; + } - var $next = $options.eq(nextIndex); + var nextIndex = currentIndex - 1; - $next.trigger('mouseenter'); + // If none are highlighted, highlight the first + if ($highlighted.length === 0) { + nextIndex = 0; + } - var currentOffset = self.$results.offset().top + - self.$results.outerHeight(false); - var nextBottom = $next.offset().top + $next.outerHeight(false); - var nextOffset = self.$results.scrollTop() + nextBottom - currentOffset; + var $next = $options.eq(nextIndex); - if (nextIndex === 0) { - self.$results.scrollTop(0); - } else if (nextBottom > currentOffset) { - self.$results.scrollTop(nextOffset); - } - }); + $next.trigger('mouseenter'); - container.on('results:focus', function (params) { - params.element.addClass('select2-results__option--highlighted').attr('aria-selected', 'true'); - self.$results.attr('aria-activedescendant', params.element.attr('id')); - }); + var currentOffset = self.$results.offset().top; + var nextTop = $next.offset().top; + var nextOffset = self.$results.scrollTop() + (nextTop - currentOffset); - container.on('results:message', function (params) { - self.displayMessage(params); - }); + if (nextIndex === 0) { + self.$results.scrollTop(0); + } else if (nextTop - currentOffset < 0) { + self.$results.scrollTop(nextOffset); + } + }); - if ($.fn.mousewheel) { - this.$results.on('mousewheel', function (e) { - var top = self.$results.scrollTop(); + container.on('results:next', function () { + var $highlighted = self.getHighlightedResults(); - var bottom = self.$results.get(0).scrollHeight - top + e.deltaY; + var $options = self.$results.find('[data-selected]'); - var isAtTop = e.deltaY > 0 && top - e.deltaY <= 0; - var isAtBottom = e.deltaY < 0 && bottom <= self.$results.height(); + var currentIndex = $options.index($highlighted); - if (isAtTop) { - self.$results.scrollTop(0); + var nextIndex = currentIndex + 1; - e.preventDefault(); - e.stopPropagation(); - } else if (isAtBottom) { - self.$results.scrollTop( - self.$results.get(0).scrollHeight - self.$results.height() - ); + // If we are at the last option, stay there + if (nextIndex >= $options.length) { + return; + } - e.preventDefault(); - e.stopPropagation(); - } - }); - } + var $next = $options.eq(nextIndex); - this.$results.on('mouseup', '.select2-results__option[data-selected]', - function (evt) { - var $this = $(this); + $next.trigger('mouseenter'); - var data = $this.data('data'); + var currentOffset = self.$results.offset().top + + self.$results.outerHeight(false); + var nextBottom = $next.offset().top + $next.outerHeight(false); + var nextOffset = self.$results.scrollTop() + nextBottom - currentOffset; - if ($this.attr('data-selected') === 'true') { - if (self.options.get('multiple')) { - self.trigger('unselect', { - originalEvent: evt, - data: data - }); - } else { - self.trigger('close', {}); - } + if (nextIndex === 0) { + self.$results.scrollTop(0); + } else if (nextBottom > currentOffset) { + self.$results.scrollTop(nextOffset); + } + }); - return; - } + container.on('results:focus', function (params) { + params.element.addClass('select2-results__option--highlighted').attr('aria-selected', 'true'); + self.$results.attr('aria-activedescendant', params.element.attr('id')); + }); - self.trigger('select', { - originalEvent: evt, - data: data - }); - }); + container.on('results:message', function (params) { + self.displayMessage(params); + }); - this.$results.on('mouseenter', '.select2-results__option[data-selected]', - function (evt) { - var data = $(this).data('data'); + if ($.fn.mousewheel) { + this.$results.on('mousewheel', function (e) { + var top = self.$results.scrollTop(); - self.getHighlightedResults() - .removeClass('select2-results__option--highlighted') - .attr('aria-selected', 'false'); + var bottom = self.$results.get(0).scrollHeight - top + e.deltaY; - self.trigger('results:focus', { - data: data, - element: $(this) - }); - }); - }; + var isAtTop = e.deltaY > 0 && top - e.deltaY <= 0; + var isAtBottom = e.deltaY < 0 && bottom <= self.$results.height(); - Results.prototype.getHighlightedResults = function () { - var $highlighted = this.$results - .find('.select2-results__option--highlighted'); + if (isAtTop) { + self.$results.scrollTop(0); - return $highlighted; - }; + e.preventDefault(); + e.stopPropagation(); + } else if (isAtBottom) { + self.$results.scrollTop( + self.$results.get(0).scrollHeight - self.$results.height() + ); - Results.prototype.destroy = function () { - this.$results.remove(); - }; + e.preventDefault(); + e.stopPropagation(); + } + }); + } - Results.prototype.ensureHighlightVisible = function () { - var $highlighted = this.getHighlightedResults(); + this.$results.on('mouseup', '.select2-results__option[data-selected]', + function (evt) { + var $this = $(this); - if ($highlighted.length === 0) { - return; - } + var data = $this.data('data'); - var $options = this.$results.find('[data-selected]'); + if ($this.attr('data-selected') === 'true') { + if (self.options.get('multiple')) { + self.trigger('unselect', { + originalEvent: evt, + data: data + }); + } else { + self.trigger('close', {}); + } - var currentIndex = $options.index($highlighted); + return; + } - var currentOffset = this.$results.offset().top; - var nextTop = $highlighted.offset().top; - var nextOffset = this.$results.scrollTop() + (nextTop - currentOffset); + self.trigger('select', { + originalEvent: evt, + data: data + }); + }); - var offsetDelta = nextTop - currentOffset; - nextOffset -= $highlighted.outerHeight(false) * 2; + this.$results.on('mouseenter', '.select2-results__option[data-selected]', + function (evt) { + var data = $(this).data('data'); - if (currentIndex <= 2) { - this.$results.scrollTop(0); - } else if (offsetDelta > this.$results.outerHeight() || offsetDelta < 0) { - this.$results.scrollTop(nextOffset); - } - }; + self.getHighlightedResults() + .removeClass('select2-results__option--highlighted') + .attr('aria-selected', 'false'); - Results.prototype.template = function (result, container) { - var template = this.options.get('templateResult'); - var escapeMarkup = this.options.get('escapeMarkup'); + self.trigger('results:focus', { + data: data, + element: $(this) + }); + }); + }; - var content = template(result, container); + Results.prototype.getHighlightedResults = function () { + var $highlighted = this.$results + .find('.select2-results__option--highlighted'); - if (content == null) { - container.style.display = 'none'; - } else if (typeof content === 'string') { - container.innerHTML = escapeMarkup(content); - } else { - $(container).append(content); - } - }; - - return Results; -}); - -S2.define('select2/keys',[ - -], function () { - var KEYS = { - BACKSPACE: 8, - TAB: 9, - ENTER: 13, - SHIFT: 16, - CTRL: 17, - ALT: 18, - ESC: 27, - SPACE: 32, - PAGE_UP: 33, - PAGE_DOWN: 34, - END: 35, - HOME: 36, - LEFT: 37, - UP: 38, - RIGHT: 39, - DOWN: 40, - DELETE: 46 - }; - - return KEYS; -}); - -S2.define('select2/selection/base',[ - 'jquery', - '../utils', - '../keys' -], function ($, Utils, KEYS) { - function BaseSelection ($element, options) { - this.$element = $element; - this.options = options; - - BaseSelection.__super__.constructor.call(this); - } + return $highlighted; + }; - Utils.Extend(BaseSelection, Utils.Observable); + Results.prototype.destroy = function () { + this.$results.remove(); + }; - BaseSelection.prototype.render = function () { - var $selection = $( - '' - ); + Results.prototype.ensureHighlightVisible = function () { + var $highlighted = this.getHighlightedResults(); - this._tabindex = 0; + if ($highlighted.length === 0) { + return; + } - if (this.$element.data('old-tabindex') != null) { - this._tabindex = this.$element.data('old-tabindex'); - } else if (this.$element.attr('tabindex') != null) { - this._tabindex = this.$element.attr('tabindex'); - } + var $options = this.$results.find('[data-selected]'); - $selection.attr('title', this.$element.attr('title')); - $selection.attr('tabindex', this._tabindex); + var currentIndex = $options.index($highlighted); - this.$selection = $selection; + var currentOffset = this.$results.offset().top; + var nextTop = $highlighted.offset().top; + var nextOffset = this.$results.scrollTop() + (nextTop - currentOffset); - return $selection; - }; + var offsetDelta = nextTop - currentOffset; + nextOffset -= $highlighted.outerHeight(false) * 2; - BaseSelection.prototype.bind = function (container, $container) { - var self = this; + if (currentIndex <= 2) { + this.$results.scrollTop(0); + } else if (offsetDelta > this.$results.outerHeight() || offsetDelta < 0) { + this.$results.scrollTop(nextOffset); + } + }; - var id = container.id + '-container'; - var resultsId = container.id + '-results'; - var searchHidden = this.options.get('minimumResultsForSearch') === Infinity; + Results.prototype.template = function (result, container) { + var template = this.options.get('templateResult'); + var escapeMarkup = this.options.get('escapeMarkup'); - this.container = container; + var content = template(result, container); - this.$selection.on('focus', function (evt) { - self.trigger('focus', evt); - }); + if (content == null) { + container.style.display = 'none'; + } else if (typeof content === 'string') { + container.innerHTML = escapeMarkup(content); + } else { + $(container).append(content); + } + }; - this.$selection.on('blur', function (evt) { - self._handleBlur(evt); + return Results; }); - this.$selection.on('keydown', function (evt) { - self.trigger('keypress', evt); + S2.define('select2/keys',[ + + ], function () { + var KEYS = { + BACKSPACE: 8, + TAB: 9, + ENTER: 13, + SHIFT: 16, + CTRL: 17, + ALT: 18, + ESC: 27, + SPACE: 32, + PAGE_UP: 33, + PAGE_DOWN: 34, + END: 35, + HOME: 36, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, + DELETE: 46 + }; - if (evt.which === KEYS.SPACE) { - evt.preventDefault(); - } + return KEYS; }); - container.on('results:focus', function (params) { - self.$selection.attr('aria-activedescendant', params.data._resultId); - }); + S2.define('select2/selection/base',[ + 'jquery', + '../utils', + '../keys' + ], function ($, Utils, KEYS) { + function BaseSelection ($element, options) { + this.$element = $element; + this.options = options; - container.on('selection:update', function (params) { - self.update(params.data); - }); + BaseSelection.__super__.constructor.call(this); + } - container.on('open', function () { - // When the dropdown is open, aria-expanded="true" - self.$selection.attr('aria-expanded', 'true'); - self.$selection.attr('aria-owns', resultsId); + Utils.Extend(BaseSelection, Utils.Observable); - self._attachCloseHandler(container); - }); + BaseSelection.prototype.render = function () { + var $selection = $( + '' + ); - container.on('close', function () { - // When the dropdown is closed, aria-expanded="false" - self.$selection.attr('aria-expanded', 'false'); - self.$selection.removeAttr('aria-activedescendant'); - self.$selection.removeAttr('aria-owns'); + this._tabindex = 0; - // This needs to be delayed as the active element is the body when the - // key is pressed. - window.setTimeout(function () { - self.$selection.focus(); - }, 1); + if (this.$element.data('old-tabindex') != null) { + this._tabindex = this.$element.data('old-tabindex'); + } else if (this.$element.attr('tabindex') != null) { + this._tabindex = this.$element.attr('tabindex'); + } - self._detachCloseHandler(container); - }); + $selection.attr('title', this.$element.attr('title')); + $selection.attr('tabindex', this._tabindex); - container.on('enable', function () { - self.$selection.attr('tabindex', self._tabindex); - }); + this.$selection = $selection; - container.on('disable', function () { - self.$selection.attr('tabindex', '-1'); - }); - }; - - BaseSelection.prototype._handleBlur = function (evt) { - var self = this; - - // This needs to be delayed as the active element is the body when the tab - // key is pressed, possibly along with others. - window.setTimeout(function () { - // Don't trigger `blur` if the focus is still in the selection - if ( - (document.activeElement == self.$selection[0]) || - ($.contains(self.$selection[0], document.activeElement)) - ) { - return; - } + return $selection; + }; - self.trigger('blur', evt); - }, 1); - }; + BaseSelection.prototype.bind = function (container, $container) { + var self = this; - BaseSelection.prototype._attachCloseHandler = function (container) { - var self = this; + var id = container.id + '-container'; + var resultsId = container.id + '-results'; + var searchHidden = this.options.get('minimumResultsForSearch') === Infinity; + var isRequired = this.options.get('required') === true; - $(document.body).on('mousedown.select2.' + container.id, function (e) { - var $target = $(e.target); + this.container = container; - var $select = $target.closest('.select2'); + if (isRequired) { + this.$selection.attr('aria-required', 'true') + } - var $all = $('.select2.select2-container--open'); + this.$selection.on('focus', function (evt) { + self.trigger('focus', evt); + }); - $all.each(function () { - var $this = $(this); + this.$selection.on('blur', function (evt) { + self._handleBlur(evt); + }); - if (this == $select[0]) { - return; - } + this.$selection.on('keydown', function (evt) { + self.trigger('keypress', evt); - var $element = $this.data('element'); + if (evt.which === KEYS.SPACE) { + evt.preventDefault(); + } + }); - $element.select2('close'); - }); - }); - }; - - BaseSelection.prototype._detachCloseHandler = function (container) { - $(document.body).off('mousedown.select2.' + container.id); - }; - - BaseSelection.prototype.position = function ($selection, $container) { - var $selectionContainer = $container.find('.selection'); - $selectionContainer.append($selection); - }; - - BaseSelection.prototype.destroy = function () { - this._detachCloseHandler(this.container); - }; - - BaseSelection.prototype.update = function (data) { - throw new Error('The `update` method must be defined in child classes.'); - }; - - return BaseSelection; -}); - -S2.define('select2/selection/single',[ - 'jquery', - './base', - '../utils', - '../keys' -], function ($, BaseSelection, Utils, KEYS) { - function SingleSelection () { - SingleSelection.__super__.constructor.apply(this, arguments); - } + container.on('results:focus', function (params) { + self.$selection.attr('aria-activedescendant', params.data._resultId); + }); - Utils.Extend(SingleSelection, BaseSelection); + container.on('selection:update', function (params) { + self.update(params.data); + }); - SingleSelection.prototype.render = function () { - var $selection = SingleSelection.__super__.render.call(this); + container.on('open', function () { + // When the dropdown is open, aria-expanded="true" + self.$selection.attr('aria-expanded', 'true'); + self.$selection.attr('aria-owns', resultsId); - $selection.addClass('select2-selection--single'); + self._attachCloseHandler(container); + }); - $selection.html( - '' + - '' + - '' + - '' - ); + container.on('close', function () { + // When the dropdown is closed, aria-expanded="false" + self.$selection.attr('aria-expanded', 'false'); + self.$selection.removeAttr('aria-activedescendant'); + self.$selection.removeAttr('aria-owns'); - return $selection; - }; + // This needs to be delayed as the active element is the body when the + // key is pressed. + window.setTimeout(function () { + self.$selection.focus(); + }, 1); - SingleSelection.prototype.bind = function (container, $container) { - var self = this; + self._detachCloseHandler(container); + }); - SingleSelection.__super__.bind.apply(this, arguments); + container.on('enable', function () { + self.$selection.attr('tabindex', self._tabindex); + }); - var id = container.id + '-container'; + container.on('disable', function () { + self.$selection.attr('tabindex', '-1'); + }); + }; - this.$selection.find('.select2-selection__rendered') - .attr('id', id) - .attr('role', 'textbox') - .attr('aria-readonly', 'true'); - this.$selection.attr('aria-labelledby', id); + BaseSelection.prototype._handleBlur = function (evt) { + var self = this; + + // This needs to be delayed as the active element is the body when the tab + // key is pressed, possibly along with others. + window.setTimeout(function () { + // Don't trigger `blur` if the focus is still in the selection + if ( + (document.activeElement == self.$selection[0]) || + ($.contains(self.$selection[0], document.activeElement)) + ) { + return; + } - // This makes single non-search selects work in screen readers. If it causes problems elsewhere, remove. - this.$selection.attr('role', 'combobox'); + self.trigger('blur', evt); + }, 1); + }; - this.$selection.on('mousedown', function (evt) { - // Only respond to left clicks - if (evt.which !== 1) { - return; - } + BaseSelection.prototype._attachCloseHandler = function (container) { + var self = this; - self.trigger('toggle', { - originalEvent: evt - }); - }); + $(document.body).on('mousedown.select2.' + container.id, function (e) { + var $target = $(e.target); - this.$selection.on('focus', function (evt) { - // User focuses on the container - }); + var $select = $target.closest('.select2'); - this.$selection.on('keydown', function (evt) { - // If user starts typing an alphanumeric key on the keyboard, open if not opened. - if (!container.isOpen() && evt.which >= 48 && evt.which <= 90) { - container.open(); - } - }); + var $all = $('.select2.select2-container--open'); - this.$selection.on('blur', function (evt) { - // User exits the container - }); + $all.each(function () { + var $this = $(this); - container.on('focus', function (evt) { - if (!container.isOpen()) { - self.$selection.focus(); - } - }); + if (this == $select[0]) { + return; + } - container.on('selection:update', function (params) { - self.update(params.data); - }); - }; + var $element = $this.data('element'); + $element.select2('close'); - SingleSelection.prototype.clear = function () { - this.$selection.find('.select2-selection__rendered').empty(); - }; + // Remove any focus when dropdown is closed by clicking outside the select area. + // Timeout of 1 required for close to finish wrapping up. + setTimeout(function(){ + $this.find('*:focus').blur(); + $target.focus(); + }, 1); + }); + }); + }; - SingleSelection.prototype.display = function (data, container) { - var template = this.options.get('templateSelection'); - var escapeMarkup = this.options.get('escapeMarkup'); + BaseSelection.prototype._detachCloseHandler = function (container) { + $(document.body).off('mousedown.select2.' + container.id); + }; - return escapeMarkup(template(data, container)); - }; + BaseSelection.prototype.position = function ($selection, $container) { + var $selectionContainer = $container.find('.selection'); + $selectionContainer.append($selection); + }; - SingleSelection.prototype.selectionContainer = function () { - return $(''); - }; + BaseSelection.prototype.destroy = function () { + this._detachCloseHandler(this.container); + }; - SingleSelection.prototype.update = function (data) { - if (data.length === 0) { - this.clear(); - return; - } + BaseSelection.prototype.update = function (data) { + throw new Error('The `update` method must be defined in child classes.'); + }; - var selection = data[0]; + return BaseSelection; + }); - var $rendered = this.$selection.find('.select2-selection__rendered'); - var formatted = this.display(selection, $rendered); + S2.define('select2/selection/single',[ + 'jquery', + './base', + '../utils', + '../keys' + ], function ($, BaseSelection, Utils, KEYS) { + function SingleSelection () { + SingleSelection.__super__.constructor.apply(this, arguments); + } - $rendered.empty().append(formatted); - $rendered.prop('title', selection.title || selection.text); - }; + Utils.Extend(SingleSelection, BaseSelection); - return SingleSelection; -}); + SingleSelection.prototype.render = function () { + var $selection = SingleSelection.__super__.render.call(this); -S2.define('select2/selection/multiple',[ - 'jquery', - './base', - '../utils' -], function ($, BaseSelection, Utils) { - function MultipleSelection ($element, options) { - MultipleSelection.__super__.constructor.apply(this, arguments); - } + $selection.addClass('select2-selection--single'); - Utils.Extend(MultipleSelection, BaseSelection); + $selection.html( + '' + + '' + + '' + + '' + ); - MultipleSelection.prototype.render = function () { - var $selection = MultipleSelection.__super__.render.call(this); + return $selection; + }; - $selection.addClass('select2-selection--multiple'); + SingleSelection.prototype.bind = function (container, $container) { + var self = this; - $selection.html( - '' - ); + SingleSelection.__super__.bind.apply(this, arguments); - return $selection; - }; + var isRequired = this.options.get('required') === true; + if (isRequired) { + this.$selection.find('.select2-selection__rendered').attr('aria-required', 'true') + } - MultipleSelection.prototype.bind = function (container, $container) { - var self = this; + var id = container.id + '-container'; - MultipleSelection.__super__.bind.apply(this, arguments); + this.$selection.find('.select2-selection__rendered') + .attr('id', id) + .attr('role', 'textbox') + .attr('aria-readonly', 'true'); - this.$selection.on('click', function (evt) { - self.trigger('toggle', { - originalEvent: evt - }); - }); + var label = this.options.get( 'label' ); - this.$selection.on( - 'click', - '.select2-selection__choice__remove', - function (evt) { - // Ignore the event if it is disabled - if (self.options.get('disabled')) { - return; + if ( typeof( label ) === 'string' ) { + this.$selection.attr( 'aria-label', label ); + } else { + this.$selection.attr( 'aria-labelledby', id ); } - var $remove = $(this); - var $selection = $remove.parent(); + // This makes single non-search selects work in screen readers. If it causes problems elsewhere, remove. + this.$selection.attr('role', 'combobox'); - var data = $selection.data('data'); + this.$selection.on('mousedown', function (evt) { + // Only respond to left clicks + if (evt.which !== 1) { + return; + } - self.trigger('unselect', { - originalEvent: evt, - data: data + self.trigger('toggle', { + originalEvent: evt + }); }); - } - ); - }; - MultipleSelection.prototype.clear = function () { - this.$selection.find('.select2-selection__rendered').empty(); - }; + this.$selection.on('focus', function (evt) { + // User focuses on the container + }); - MultipleSelection.prototype.display = function (data, container) { - var template = this.options.get('templateSelection'); - var escapeMarkup = this.options.get('escapeMarkup'); + this.$selection.on('keydown', function (evt) { + // If user starts typing an alphanumeric key on the keyboard, open if not opened. + if (!container.isOpen() && evt.which >= 48 && evt.which <= 90) { + container.open(); + } + }); - return escapeMarkup(template(data, container)); - }; + this.$selection.on('blur', function (evt) { + // User exits the container + }); - MultipleSelection.prototype.selectionContainer = function () { - var $container = $( - '
  • ' + - '' + - '
  • ' - ); + container.on('focus', function (evt) { + if (!container.isOpen()) { + self.$selection.focus(); + } + }); - return $container; - }; + container.on('selection:update', function (params) { + self.update(params.data); + }); + }; - MultipleSelection.prototype.update = function (data) { - var self = this; - this.clear(); + SingleSelection.prototype.clear = function () { + this.$selection.find('.select2-selection__rendered').empty(); + }; - if (data.length === 0) { - return; - } + SingleSelection.prototype.display = function (data, container) { + var template = this.options.get('templateSelection'); + var escapeMarkup = this.options.get('escapeMarkup'); - var $selections = []; + return escapeMarkup(template(data, container)); + }; - for (var d = 0; d < data.length; d++) { - var selection = data[d]; + SingleSelection.prototype.selectionContainer = function () { + return $(''); + }; - var $selection = this.selectionContainer(); - var formatted = this.display(selection, $selection).trim(); + SingleSelection.prototype.update = function (data) { + if (data.length === 0) { + this.clear(); + return; + } - $selection.append(formatted); - $selection.prop('title', selection.title || selection.text); + var selection = data[0]; - $selection.data('data', selection); + var $rendered = this.$selection.find('.select2-selection__rendered'); + var formatted = Utils.entityDecode(this.display(selection, $rendered)); - $selections.push($selection); - } + $rendered.empty().text(formatted); + $rendered.prop('title', selection.title || selection.text); + }; - var $rendered = this.$selection.find('.select2-selection__rendered'); + return SingleSelection; + }); - Utils.appendMany($rendered, $selections); + S2.define('select2/selection/multiple',[ + 'jquery', + './base', + '../utils' + ], function ($, BaseSelection, Utils) { + function MultipleSelection ($element, options) { + MultipleSelection.__super__.constructor.apply(this, arguments); + } - // Return cursor to search field after updating. - // Needs 1 ms delay because of other 1 ms setTimeouts when rendering. - if ('undefined' !== typeof this.$search) { - setTimeout(function(){ - self.$search.focus(); - }, 1); - } - }; + Utils.Extend(MultipleSelection, BaseSelection); - return MultipleSelection; -}); + MultipleSelection.prototype.render = function () { + var $selection = MultipleSelection.__super__.render.call(this); -S2.define('select2/selection/placeholder',[ - '../utils' -], function (Utils) { - function Placeholder (decorated, $element, options) { - this.placeholder = this.normalizePlaceholder(options.get('placeholder')); + $selection.addClass('select2-selection--multiple'); - decorated.call(this, $element, options); - } + $selection.html( + '' + ); - Placeholder.prototype.normalizePlaceholder = function (_, placeholder) { - if (typeof placeholder === 'string') { - placeholder = { - id: '', - text: placeholder + return $selection; }; - } - return placeholder; - }; + MultipleSelection.prototype.bind = function (container, $container) { + var self = this; - Placeholder.prototype.createPlaceholder = function (decorated, placeholder) { - var $placeholder = this.selectionContainer(); + MultipleSelection.__super__.bind.apply(this, arguments); - $placeholder.html(this.display(placeholder)); - $placeholder.addClass('select2-selection__placeholder') - .removeClass('select2-selection__choice'); - - return $placeholder; - }; + this.$selection.on('click', function (evt) { + self.trigger('toggle', { + originalEvent: evt + }); + }); - Placeholder.prototype.update = function (decorated, data) { - var singlePlaceholder = ( - data.length == 1 && data[0].id != this.placeholder.id - ); - var multipleSelections = data.length > 1; + this.$selection.on( + 'click', + '.select2-selection__choice__remove', + function (evt) { + // Ignore the event if it is disabled + if (self.options.get('disabled')) { + return; + } - if (multipleSelections || singlePlaceholder) { - return decorated.call(this, data); - } + var $remove = $(this); + var $selection = $remove.parent(); - this.clear(); + var data = $selection.data('data'); - var $placeholder = this.createPlaceholder(this.placeholder); + self.trigger('unselect', { + originalEvent: evt, + data: data + }); + } + ); - this.$selection.find('.select2-selection__rendered').append($placeholder); - }; + this.$selection.on('keydown', function (evt) { + // If user starts typing an alphanumeric key on the keyboard, open if not opened. + if (!container.isOpen() && evt.which >= 48 && evt.which <= 90) { + container.open(); + } + }); - return Placeholder; -}); + // Focus on the search field when the container is focused instead of the main container. + container.on( 'focus', function(){ + self.focusOnSearch(); + }); + }; -S2.define('select2/selection/allowClear',[ - 'jquery', - '../keys' -], function ($, KEYS) { - function AllowClear () { } + MultipleSelection.prototype.clear = function () { + this.$selection.find('.select2-selection__rendered').empty(); + }; - AllowClear.prototype.bind = function (decorated, container, $container) { - var self = this; + MultipleSelection.prototype.display = function (data, container) { + var template = this.options.get('templateSelection'); + var escapeMarkup = this.options.get('escapeMarkup'); - decorated.call(this, container, $container); + return escapeMarkup(template(data, container)); + }; - if (this.placeholder == null) { - if (this.options.get('debug') && window.console && console.error) { - console.error( - 'Select2: The `allowClear` option should be used in combination ' + - 'with the `placeholder` option.' + MultipleSelection.prototype.selectionContainer = function () { + var $container = $( + '
  • ' + + '' + + '
  • ' ); - } - } - this.$selection.on('mousedown', '.select2-selection__clear', - function (evt) { - self._handleClear(evt); - }); + return $container; + }; - container.on('keypress', function (evt) { - self._handleKeyboardClear(evt, container); - }); - }; + /** + * Focus on the search field instead of the main multiselect container. + */ + MultipleSelection.prototype.focusOnSearch = function() { + var self = this; - AllowClear.prototype._handleClear = function (_, evt) { - // Ignore the event if it is disabled - if (this.options.get('disabled')) { - return; - } + if ('undefined' !== typeof self.$search) { + // Needs 1 ms delay because of other 1 ms setTimeouts when rendering. + setTimeout(function(){ + // Prevent the dropdown opening again when focused from this. + // This gets reset automatically when focus is triggered. + self._keyUpPrevented = true; - var $clear = this.$selection.find('.select2-selection__clear'); + self.$search.focus(); + }, 1); + } + } - // Ignore the event if nothing has been selected - if ($clear.length === 0) { - return; - } + MultipleSelection.prototype.update = function (data) { + this.clear(); - evt.stopPropagation(); + if (data.length === 0) { + return; + } - var data = $clear.data('data'); + var $selections = []; - for (var d = 0; d < data.length; d++) { - var unselectData = { - data: data[d] - }; + for (var d = 0; d < data.length; d++) { + var selection = data[d]; - // Trigger the `unselect` event, so people can prevent it from being - // cleared. - this.trigger('unselect', unselectData); + var $selection = this.selectionContainer(); + var removeItemTag = $selection.html(); + var formatted = this.display(selection, $selection); + if ('string' === typeof formatted) { + formatted = Utils.entityDecode(formatted.trim()); + } - // If the event was prevented, don't clear it out. - if (unselectData.prevented) { - return; - } - } + $selection.text(formatted); + $selection.prepend(removeItemTag); + $selection.prop('title', selection.title || selection.text); - this.$element.val(this.placeholder.id).trigger('change'); + $selection.data('data', selection); - this.trigger('toggle', {}); - }; + $selections.push($selection); + } - AllowClear.prototype._handleKeyboardClear = function (_, evt, container) { - if (container.isOpen()) { - return; - } + var $rendered = this.$selection.find('.select2-selection__rendered'); - if (evt.which == KEYS.DELETE || evt.which == KEYS.BACKSPACE) { - this._handleClear(evt); - } - }; + Utils.appendMany($rendered, $selections); + }; - AllowClear.prototype.update = function (decorated, data) { - decorated.call(this, data); + return MultipleSelection; + }); - if (this.$selection.find('.select2-selection__placeholder').length > 0 || - data.length === 0) { - return; - } + S2.define('select2/selection/placeholder',[ + '../utils' + ], function (Utils) { + function Placeholder (decorated, $element, options) { + this.placeholder = this.normalizePlaceholder(options.get('placeholder')); - var $remove = $( - '' + - '×' + - '' - ); - $remove.data('data', data); - - this.$selection.find('.select2-selection__rendered').prepend($remove); - }; - - return AllowClear; -}); - -S2.define('select2/selection/search',[ - 'jquery', - '../utils', - '../keys' -], function ($, Utils, KEYS) { - function Search (decorated, $element, options) { - decorated.call(this, $element, options); - } + decorated.call(this, $element, options); + } - Search.prototype.render = function (decorated) { - var $search = $( - '' - ); + Placeholder.prototype.normalizePlaceholder = function (_, placeholder) { + if (typeof placeholder === 'string') { + placeholder = { + id: '', + text: placeholder + }; + } - this.$searchContainer = $search; - this.$search = $search.find('input'); + return placeholder; + }; - var $rendered = decorated.call(this); + Placeholder.prototype.createPlaceholder = function (decorated, placeholder) { + var $placeholder = this.selectionContainer(); - this._transferTabIndex(); + $placeholder.text(Utils.entityDecode(this.display(placeholder))); + $placeholder.addClass('select2-selection__placeholder') + .removeClass('select2-selection__choice'); - return $rendered; - }; + return $placeholder; + }; - Search.prototype.bind = function (decorated, container, $container) { - var self = this; - var resultsId = container.id + '-results'; + Placeholder.prototype.update = function (decorated, data) { + var singlePlaceholder = ( + data.length == 1 && data[0].id != this.placeholder.id + ); + var multipleSelections = data.length > 1; - decorated.call(this, container, $container); + if (multipleSelections || singlePlaceholder) { + return decorated.call(this, data); + } - container.on('open', function () { - self.$search.attr('aria-owns', resultsId); - self.$search.trigger('focus'); - }); + this.clear(); - container.on('close', function () { - self.$search.val(''); - self.$search.removeAttr('aria-activedescendant'); - self.$search.removeAttr('aria-owns'); - self.$search.trigger('focus'); - }); + var $placeholder = this.createPlaceholder(this.placeholder); - container.on('enable', function () { - self.$search.prop('disabled', false); + this.$selection.find('.select2-selection__rendered').append($placeholder); + }; - self._transferTabIndex(); + return Placeholder; }); - container.on('disable', function () { - self.$search.prop('disabled', true); - }); + S2.define('select2/selection/allowClear',[ + 'jquery', + '../keys' + ], function ($, KEYS) { + function AllowClear () { } - container.on('focus', function (evt) { - self.$search.trigger('focus'); - }); + AllowClear.prototype.bind = function (decorated, container, $container) { + var self = this; - container.on('results:focus', function (params) { - self.$search.attr('aria-activedescendant', params.data._resultId); - }); + decorated.call(this, container, $container); - this.$selection.on('focusin', '.select2-search--inline', function (evt) { - self.trigger('focus', evt); - }); + if (this.placeholder == null) { + if (this.options.get('debug') && window.console && console.error) { + console.error( + 'Select2: The `allowClear` option should be used in combination ' + + 'with the `placeholder` option.' + ); + } + } - this.$selection.on('focusout', '.select2-search--inline', function (evt) { - self._handleBlur(evt); - }); + this.$selection.on('mousedown', '.select2-selection__clear', + function (evt) { + self._handleClear(evt); + }); - this.$selection.on('keydown', '.select2-search--inline', function (evt) { - evt.stopPropagation(); + container.on('keypress', function (evt) { + self._handleKeyboardClear(evt, container); + }); + }; - self.trigger('keypress', evt); + AllowClear.prototype._handleClear = function (_, evt) { + // Ignore the event if it is disabled + if (this.options.get('disabled')) { + return; + } - self._keyUpPrevented = evt.isDefaultPrevented(); + var $clear = this.$selection.find('.select2-selection__clear'); - var key = evt.which; + // Ignore the event if nothing has been selected + if ($clear.length === 0) { + return; + } - if (key === KEYS.BACKSPACE && self.$search.val() === '') { - var $previousChoice = self.$searchContainer - .prev('.select2-selection__choice'); + evt.stopPropagation(); - if ($previousChoice.length > 0) { - var item = $previousChoice.data('data'); + var data = $clear.data('data'); - self.searchRemoveChoice(item); + for (var d = 0; d < data.length; d++) { + var unselectData = { + data: data[d] + }; - evt.preventDefault(); - } - } - }); + // Trigger the `unselect` event, so people can prevent it from being + // cleared. + this.trigger('unselect', unselectData); - // 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. - // This property is not available in Edge, but Edge also doesn't have - // this bug. - var msie = document.documentMode; - var disableInputEvents = msie && msie <= 11; - - // Workaround for browsers which do not support the `input` event - // This will prevent double-triggering of events for browsers which support - // both the `keyup` and `input` events. - this.$selection.on( - 'input.searchcheck', - '.select2-search--inline', - function (evt) { - // IE will trigger the `input` event when a placeholder is used on a - // search box. To get around this issue, we are forced to ignore all - // `input` events in IE and keep using `keyup`. - if (disableInputEvents) { - self.$selection.off('input.search input.searchcheck'); - return; + // If the event was prevented, don't clear it out. + if (unselectData.prevented) { + return; + } } - // Unbind the duplicated `keyup` event - self.$selection.off('keyup.search'); - } - ); - - this.$selection.on( - 'keyup.search input.search', - '.select2-search--inline', - function (evt) { - // IE will trigger the `input` event when a placeholder is used on a - // search box. To get around this issue, we are forced to ignore all - // `input` events in IE and keep using `keyup`. - if (disableInputEvents && evt.type === 'input') { - self.$selection.off('input.search input.searchcheck'); - return; - } + this.$element.val(this.placeholder.id).trigger('change'); - var key = evt.which; + this.trigger('toggle', {}); + }; - // We can freely ignore events from modifier keys - if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) { + AllowClear.prototype._handleKeyboardClear = function (_, evt, container) { + if (container.isOpen()) { return; } - // Tabbing will be handled during the `keydown` phase - if (key == KEYS.TAB) { - return; + if (evt.which == KEYS.DELETE || evt.which == KEYS.BACKSPACE) { + this._handleClear(evt); } + }; - self.handleSearch(evt); - } - ); - }; - - /** - * This method will transfer the tabindex attribute from the rendered - * selection to the search box. This allows for the search box to be used as - * the primary focus instead of the selection container. - * - * @private - */ - Search.prototype._transferTabIndex = function (decorated) { - this.$search.attr('tabindex', this.$selection.attr('tabindex')); - this.$selection.attr('tabindex', '-1'); - }; - - Search.prototype.createPlaceholder = function (decorated, placeholder) { - this.$search.attr('placeholder', placeholder.text); - }; - - Search.prototype.update = function (decorated, data) { - var searchHadFocus = this.$search[0] == document.activeElement; - - this.$search.attr('placeholder', ''); - - decorated.call(this, data); - - this.$selection.find('.select2-selection__rendered') - .append(this.$searchContainer); - - this.resizeSearch(); - if (searchHadFocus) { - this.$search.focus(); - } - }; - - Search.prototype.handleSearch = function () { - this.resizeSearch(); + AllowClear.prototype.update = function (decorated, data) { + decorated.call(this, data); - if (!this._keyUpPrevented) { - var input = this.$search.val(); + if (this.$selection.find('.select2-selection__placeholder').length > 0 || + data.length === 0) { + return; + } - this.trigger('query', { - term: input - }); - } + var $remove = $( + '' + + '×' + + '' + ); + $remove.data('data', data); - this._keyUpPrevented = false; - }; + this.$selection.find('.select2-selection__rendered').prepend($remove); + }; - Search.prototype.searchRemoveChoice = function (decorated, item) { - this.trigger('unselect', { - data: item + return AllowClear; }); - this.$search.val(item.text); - this.handleSearch(); - }; + S2.define('select2/selection/search',[ + 'jquery', + '../utils', + '../keys' + ], function ($, Utils, KEYS) { + function Search (decorated, $element, options) { + decorated.call(this, $element, options); + } - Search.prototype.resizeSearch = function () { - this.$search.css('width', '25px'); + Search.prototype.render = function (decorated) { + var $search = $( + '' + ); - var width = ''; + this.$searchContainer = $search; + this.$search = $search.find('input'); - if (this.$search.attr('placeholder') !== '') { - width = this.$selection.find('.select2-selection__rendered').innerWidth(); - } else { - var minimumWidth = this.$search.val().length + 1; + var $rendered = decorated.call(this); - width = (minimumWidth * 0.75) + 'em'; - } + this._transferTabIndex(); - this.$search.css('width', width); - }; + return $rendered; + }; - return Search; -}); + Search.prototype.bind = function (decorated, container, $container) { + var self = this; + var resultsId = container.id + '-results'; -S2.define('select2/selection/eventRelay',[ - 'jquery' -], function ($) { - function EventRelay () { } + decorated.call(this, container, $container); - EventRelay.prototype.bind = function (decorated, container, $container) { - var self = this; - var relayEvents = [ - 'open', 'opening', - 'close', 'closing', - 'select', 'selecting', - 'unselect', 'unselecting' - ]; + container.on('open', function () { + self.$search.attr('aria-owns', resultsId); + self.$search.trigger('focus'); + }); - var preventableEvents = ['opening', 'closing', 'selecting', 'unselecting']; + container.on('close', function () { + self.$search.val(''); + self.$search.removeAttr('aria-activedescendant'); + self.$search.removeAttr('aria-owns'); + self.$search.trigger('focus'); + }); - decorated.call(this, container, $container); + container.on('enable', function () { + self.$search.prop('disabled', false); - container.on('*', function (name, params) { - // Ignore events that should not be relayed - if ($.inArray(name, relayEvents) === -1) { - return; - } + self._transferTabIndex(); + }); - // The parameters should always be an object - params = params || {}; + container.on('disable', function () { + self.$search.prop('disabled', true); + }); - // Generate the jQuery event for the Select2 event - var evt = $.Event('select2:' + name, { - params: params - }); + container.on('focus', function (evt) { + self.$search.trigger('focus'); + }); - self.$element.trigger(evt); - - // Only handle preventable events if it was one - if ($.inArray(name, preventableEvents) === -1) { - return; - } - - params.prevented = evt.isDefaultPrevented(); - }); - }; + container.on('results:focus', function (params) { + self.$search.attr('aria-activedescendant', params.data._resultId); + }); - return EventRelay; -}); + this.$selection.on('focusin', '.select2-search--inline', function (evt) { + self.trigger('focus', evt); + }); -S2.define('select2/translation',[ - 'jquery', - 'require' -], function ($, require) { - function Translation (dict) { - this.dict = dict || {}; - } + this.$selection.on('focusout', '.select2-search--inline', function (evt) { + self._handleBlur(evt); + }); - Translation.prototype.all = function () { - return this.dict; - }; + this.$selection.on('keydown', '.select2-search--inline', function (evt) { + evt.stopPropagation(); - Translation.prototype.get = function (key) { - return this.dict[key]; - }; + self.trigger('keypress', evt); - Translation.prototype.extend = function (translation) { - this.dict = $.extend({}, translation.all(), this.dict); - }; + self._keyUpPrevented = evt.isDefaultPrevented(); - // Static functions + var key = evt.which; - Translation._cache = {}; + if (key === KEYS.BACKSPACE && self.$search.val() === '') { + var $previousChoice = self.$searchContainer + .prev('.select2-selection__choice'); - Translation.loadPath = function (path) { - if (!(path in Translation._cache)) { - var translations = require(path); + if ($previousChoice.length > 0) { + var item = $previousChoice.data('data'); - Translation._cache[path] = translations; - } + self.searchRemoveChoice(item); - return new Translation(Translation._cache[path]); - }; - - return Translation; -}); - -S2.define('select2/diacritics',[ - -], function () { - var diacritics = { - '\u24B6': 'A', - '\uFF21': 'A', - '\u00C0': 'A', - '\u00C1': 'A', - '\u00C2': 'A', - '\u1EA6': 'A', - '\u1EA4': 'A', - '\u1EAA': 'A', - '\u1EA8': 'A', - '\u00C3': 'A', - '\u0100': 'A', - '\u0102': 'A', - '\u1EB0': 'A', - '\u1EAE': 'A', - '\u1EB4': 'A', - '\u1EB2': 'A', - '\u0226': 'A', - '\u01E0': 'A', - '\u00C4': 'A', - '\u01DE': 'A', - '\u1EA2': 'A', - '\u00C5': 'A', - '\u01FA': 'A', - '\u01CD': 'A', - '\u0200': 'A', - '\u0202': 'A', - '\u1EA0': 'A', - '\u1EAC': 'A', - '\u1EB6': 'A', - '\u1E00': 'A', - '\u0104': 'A', - '\u023A': 'A', - '\u2C6F': 'A', - '\uA732': 'AA', - '\u00C6': 'AE', - '\u01FC': 'AE', - '\u01E2': 'AE', - '\uA734': 'AO', - '\uA736': 'AU', - '\uA738': 'AV', - '\uA73A': 'AV', - '\uA73C': 'AY', - '\u24B7': 'B', - '\uFF22': 'B', - '\u1E02': 'B', - '\u1E04': 'B', - '\u1E06': 'B', - '\u0243': 'B', - '\u0182': 'B', - '\u0181': 'B', - '\u24B8': 'C', - '\uFF23': 'C', - '\u0106': 'C', - '\u0108': 'C', - '\u010A': 'C', - '\u010C': 'C', - '\u00C7': 'C', - '\u1E08': 'C', - '\u0187': 'C', - '\u023B': 'C', - '\uA73E': 'C', - '\u24B9': 'D', - '\uFF24': 'D', - '\u1E0A': 'D', - '\u010E': 'D', - '\u1E0C': 'D', - '\u1E10': 'D', - '\u1E12': 'D', - '\u1E0E': 'D', - '\u0110': 'D', - '\u018B': 'D', - '\u018A': 'D', - '\u0189': 'D', - '\uA779': 'D', - '\u01F1': 'DZ', - '\u01C4': 'DZ', - '\u01F2': 'Dz', - '\u01C5': 'Dz', - '\u24BA': 'E', - '\uFF25': 'E', - '\u00C8': 'E', - '\u00C9': 'E', - '\u00CA': 'E', - '\u1EC0': 'E', - '\u1EBE': 'E', - '\u1EC4': 'E', - '\u1EC2': 'E', - '\u1EBC': 'E', - '\u0112': 'E', - '\u1E14': 'E', - '\u1E16': 'E', - '\u0114': 'E', - '\u0116': 'E', - '\u00CB': 'E', - '\u1EBA': 'E', - '\u011A': 'E', - '\u0204': 'E', - '\u0206': 'E', - '\u1EB8': 'E', - '\u1EC6': 'E', - '\u0228': 'E', - '\u1E1C': 'E', - '\u0118': 'E', - '\u1E18': 'E', - '\u1E1A': 'E', - '\u0190': 'E', - '\u018E': 'E', - '\u24BB': 'F', - '\uFF26': 'F', - '\u1E1E': 'F', - '\u0191': 'F', - '\uA77B': 'F', - '\u24BC': 'G', - '\uFF27': 'G', - '\u01F4': 'G', - '\u011C': 'G', - '\u1E20': 'G', - '\u011E': 'G', - '\u0120': 'G', - '\u01E6': 'G', - '\u0122': 'G', - '\u01E4': 'G', - '\u0193': 'G', - '\uA7A0': 'G', - '\uA77D': 'G', - '\uA77E': 'G', - '\u24BD': 'H', - '\uFF28': 'H', - '\u0124': 'H', - '\u1E22': 'H', - '\u1E26': 'H', - '\u021E': 'H', - '\u1E24': 'H', - '\u1E28': 'H', - '\u1E2A': 'H', - '\u0126': 'H', - '\u2C67': 'H', - '\u2C75': 'H', - '\uA78D': 'H', - '\u24BE': 'I', - '\uFF29': 'I', - '\u00CC': 'I', - '\u00CD': 'I', - '\u00CE': 'I', - '\u0128': 'I', - '\u012A': 'I', - '\u012C': 'I', - '\u0130': 'I', - '\u00CF': 'I', - '\u1E2E': 'I', - '\u1EC8': 'I', - '\u01CF': 'I', - '\u0208': 'I', - '\u020A': 'I', - '\u1ECA': 'I', - '\u012E': 'I', - '\u1E2C': 'I', - '\u0197': 'I', - '\u24BF': 'J', - '\uFF2A': 'J', - '\u0134': 'J', - '\u0248': 'J', - '\u24C0': 'K', - '\uFF2B': 'K', - '\u1E30': 'K', - '\u01E8': 'K', - '\u1E32': 'K', - '\u0136': 'K', - '\u1E34': 'K', - '\u0198': 'K', - '\u2C69': 'K', - '\uA740': 'K', - '\uA742': 'K', - '\uA744': 'K', - '\uA7A2': 'K', - '\u24C1': 'L', - '\uFF2C': 'L', - '\u013F': 'L', - '\u0139': 'L', - '\u013D': 'L', - '\u1E36': 'L', - '\u1E38': 'L', - '\u013B': 'L', - '\u1E3C': 'L', - '\u1E3A': 'L', - '\u0141': 'L', - '\u023D': 'L', - '\u2C62': 'L', - '\u2C60': 'L', - '\uA748': 'L', - '\uA746': 'L', - '\uA780': 'L', - '\u01C7': 'LJ', - '\u01C8': 'Lj', - '\u24C2': 'M', - '\uFF2D': 'M', - '\u1E3E': 'M', - '\u1E40': 'M', - '\u1E42': 'M', - '\u2C6E': 'M', - '\u019C': 'M', - '\u24C3': 'N', - '\uFF2E': 'N', - '\u01F8': 'N', - '\u0143': 'N', - '\u00D1': 'N', - '\u1E44': 'N', - '\u0147': 'N', - '\u1E46': 'N', - '\u0145': 'N', - '\u1E4A': 'N', - '\u1E48': 'N', - '\u0220': 'N', - '\u019D': 'N', - '\uA790': 'N', - '\uA7A4': 'N', - '\u01CA': 'NJ', - '\u01CB': 'Nj', - '\u24C4': 'O', - '\uFF2F': 'O', - '\u00D2': 'O', - '\u00D3': 'O', - '\u00D4': 'O', - '\u1ED2': 'O', - '\u1ED0': 'O', - '\u1ED6': 'O', - '\u1ED4': 'O', - '\u00D5': 'O', - '\u1E4C': 'O', - '\u022C': 'O', - '\u1E4E': 'O', - '\u014C': 'O', - '\u1E50': 'O', - '\u1E52': 'O', - '\u014E': 'O', - '\u022E': 'O', - '\u0230': 'O', - '\u00D6': 'O', - '\u022A': 'O', - '\u1ECE': 'O', - '\u0150': 'O', - '\u01D1': 'O', - '\u020C': 'O', - '\u020E': 'O', - '\u01A0': 'O', - '\u1EDC': 'O', - '\u1EDA': 'O', - '\u1EE0': 'O', - '\u1EDE': 'O', - '\u1EE2': 'O', - '\u1ECC': 'O', - '\u1ED8': 'O', - '\u01EA': 'O', - '\u01EC': 'O', - '\u00D8': 'O', - '\u01FE': 'O', - '\u0186': 'O', - '\u019F': 'O', - '\uA74A': 'O', - '\uA74C': 'O', - '\u01A2': 'OI', - '\uA74E': 'OO', - '\u0222': 'OU', - '\u24C5': 'P', - '\uFF30': 'P', - '\u1E54': 'P', - '\u1E56': 'P', - '\u01A4': 'P', - '\u2C63': 'P', - '\uA750': 'P', - '\uA752': 'P', - '\uA754': 'P', - '\u24C6': 'Q', - '\uFF31': 'Q', - '\uA756': 'Q', - '\uA758': 'Q', - '\u024A': 'Q', - '\u24C7': 'R', - '\uFF32': 'R', - '\u0154': 'R', - '\u1E58': 'R', - '\u0158': 'R', - '\u0210': 'R', - '\u0212': 'R', - '\u1E5A': 'R', - '\u1E5C': 'R', - '\u0156': 'R', - '\u1E5E': 'R', - '\u024C': 'R', - '\u2C64': 'R', - '\uA75A': 'R', - '\uA7A6': 'R', - '\uA782': 'R', - '\u24C8': 'S', - '\uFF33': 'S', - '\u1E9E': 'S', - '\u015A': 'S', - '\u1E64': 'S', - '\u015C': 'S', - '\u1E60': 'S', - '\u0160': 'S', - '\u1E66': 'S', - '\u1E62': 'S', - '\u1E68': 'S', - '\u0218': 'S', - '\u015E': 'S', - '\u2C7E': 'S', - '\uA7A8': 'S', - '\uA784': 'S', - '\u24C9': 'T', - '\uFF34': 'T', - '\u1E6A': 'T', - '\u0164': 'T', - '\u1E6C': 'T', - '\u021A': 'T', - '\u0162': 'T', - '\u1E70': 'T', - '\u1E6E': 'T', - '\u0166': 'T', - '\u01AC': 'T', - '\u01AE': 'T', - '\u023E': 'T', - '\uA786': 'T', - '\uA728': 'TZ', - '\u24CA': 'U', - '\uFF35': 'U', - '\u00D9': 'U', - '\u00DA': 'U', - '\u00DB': 'U', - '\u0168': 'U', - '\u1E78': 'U', - '\u016A': 'U', - '\u1E7A': 'U', - '\u016C': 'U', - '\u00DC': 'U', - '\u01DB': 'U', - '\u01D7': 'U', - '\u01D5': 'U', - '\u01D9': 'U', - '\u1EE6': 'U', - '\u016E': 'U', - '\u0170': 'U', - '\u01D3': 'U', - '\u0214': 'U', - '\u0216': 'U', - '\u01AF': 'U', - '\u1EEA': 'U', - '\u1EE8': 'U', - '\u1EEE': 'U', - '\u1EEC': 'U', - '\u1EF0': 'U', - '\u1EE4': 'U', - '\u1E72': 'U', - '\u0172': 'U', - '\u1E76': 'U', - '\u1E74': 'U', - '\u0244': 'U', - '\u24CB': 'V', - '\uFF36': 'V', - '\u1E7C': 'V', - '\u1E7E': 'V', - '\u01B2': 'V', - '\uA75E': 'V', - '\u0245': 'V', - '\uA760': 'VY', - '\u24CC': 'W', - '\uFF37': 'W', - '\u1E80': 'W', - '\u1E82': 'W', - '\u0174': 'W', - '\u1E86': 'W', - '\u1E84': 'W', - '\u1E88': 'W', - '\u2C72': 'W', - '\u24CD': 'X', - '\uFF38': 'X', - '\u1E8A': 'X', - '\u1E8C': 'X', - '\u24CE': 'Y', - '\uFF39': 'Y', - '\u1EF2': 'Y', - '\u00DD': 'Y', - '\u0176': 'Y', - '\u1EF8': 'Y', - '\u0232': 'Y', - '\u1E8E': 'Y', - '\u0178': 'Y', - '\u1EF6': 'Y', - '\u1EF4': 'Y', - '\u01B3': 'Y', - '\u024E': 'Y', - '\u1EFE': 'Y', - '\u24CF': 'Z', - '\uFF3A': 'Z', - '\u0179': 'Z', - '\u1E90': 'Z', - '\u017B': 'Z', - '\u017D': 'Z', - '\u1E92': 'Z', - '\u1E94': 'Z', - '\u01B5': 'Z', - '\u0224': 'Z', - '\u2C7F': 'Z', - '\u2C6B': 'Z', - '\uA762': 'Z', - '\u24D0': 'a', - '\uFF41': 'a', - '\u1E9A': 'a', - '\u00E0': 'a', - '\u00E1': 'a', - '\u00E2': 'a', - '\u1EA7': 'a', - '\u1EA5': 'a', - '\u1EAB': 'a', - '\u1EA9': 'a', - '\u00E3': 'a', - '\u0101': 'a', - '\u0103': 'a', - '\u1EB1': 'a', - '\u1EAF': 'a', - '\u1EB5': 'a', - '\u1EB3': 'a', - '\u0227': 'a', - '\u01E1': 'a', - '\u00E4': 'a', - '\u01DF': 'a', - '\u1EA3': 'a', - '\u00E5': 'a', - '\u01FB': 'a', - '\u01CE': 'a', - '\u0201': 'a', - '\u0203': 'a', - '\u1EA1': 'a', - '\u1EAD': 'a', - '\u1EB7': 'a', - '\u1E01': 'a', - '\u0105': 'a', - '\u2C65': 'a', - '\u0250': 'a', - '\uA733': 'aa', - '\u00E6': 'ae', - '\u01FD': 'ae', - '\u01E3': 'ae', - '\uA735': 'ao', - '\uA737': 'au', - '\uA739': 'av', - '\uA73B': 'av', - '\uA73D': 'ay', - '\u24D1': 'b', - '\uFF42': 'b', - '\u1E03': 'b', - '\u1E05': 'b', - '\u1E07': 'b', - '\u0180': 'b', - '\u0183': 'b', - '\u0253': 'b', - '\u24D2': 'c', - '\uFF43': 'c', - '\u0107': 'c', - '\u0109': 'c', - '\u010B': 'c', - '\u010D': 'c', - '\u00E7': 'c', - '\u1E09': 'c', - '\u0188': 'c', - '\u023C': 'c', - '\uA73F': 'c', - '\u2184': 'c', - '\u24D3': 'd', - '\uFF44': 'd', - '\u1E0B': 'd', - '\u010F': 'd', - '\u1E0D': 'd', - '\u1E11': 'd', - '\u1E13': 'd', - '\u1E0F': 'd', - '\u0111': 'd', - '\u018C': 'd', - '\u0256': 'd', - '\u0257': 'd', - '\uA77A': 'd', - '\u01F3': 'dz', - '\u01C6': 'dz', - '\u24D4': 'e', - '\uFF45': 'e', - '\u00E8': 'e', - '\u00E9': 'e', - '\u00EA': 'e', - '\u1EC1': 'e', - '\u1EBF': 'e', - '\u1EC5': 'e', - '\u1EC3': 'e', - '\u1EBD': 'e', - '\u0113': 'e', - '\u1E15': 'e', - '\u1E17': 'e', - '\u0115': 'e', - '\u0117': 'e', - '\u00EB': 'e', - '\u1EBB': 'e', - '\u011B': 'e', - '\u0205': 'e', - '\u0207': 'e', - '\u1EB9': 'e', - '\u1EC7': 'e', - '\u0229': 'e', - '\u1E1D': 'e', - '\u0119': 'e', - '\u1E19': 'e', - '\u1E1B': 'e', - '\u0247': 'e', - '\u025B': 'e', - '\u01DD': 'e', - '\u24D5': 'f', - '\uFF46': 'f', - '\u1E1F': 'f', - '\u0192': 'f', - '\uA77C': 'f', - '\u24D6': 'g', - '\uFF47': 'g', - '\u01F5': 'g', - '\u011D': 'g', - '\u1E21': 'g', - '\u011F': 'g', - '\u0121': 'g', - '\u01E7': 'g', - '\u0123': 'g', - '\u01E5': 'g', - '\u0260': 'g', - '\uA7A1': 'g', - '\u1D79': 'g', - '\uA77F': 'g', - '\u24D7': 'h', - '\uFF48': 'h', - '\u0125': 'h', - '\u1E23': 'h', - '\u1E27': 'h', - '\u021F': 'h', - '\u1E25': 'h', - '\u1E29': 'h', - '\u1E2B': 'h', - '\u1E96': 'h', - '\u0127': 'h', - '\u2C68': 'h', - '\u2C76': 'h', - '\u0265': 'h', - '\u0195': 'hv', - '\u24D8': 'i', - '\uFF49': 'i', - '\u00EC': 'i', - '\u00ED': 'i', - '\u00EE': 'i', - '\u0129': 'i', - '\u012B': 'i', - '\u012D': 'i', - '\u00EF': 'i', - '\u1E2F': 'i', - '\u1EC9': 'i', - '\u01D0': 'i', - '\u0209': 'i', - '\u020B': 'i', - '\u1ECB': 'i', - '\u012F': 'i', - '\u1E2D': 'i', - '\u0268': 'i', - '\u0131': 'i', - '\u24D9': 'j', - '\uFF4A': 'j', - '\u0135': 'j', - '\u01F0': 'j', - '\u0249': 'j', - '\u24DA': 'k', - '\uFF4B': 'k', - '\u1E31': 'k', - '\u01E9': 'k', - '\u1E33': 'k', - '\u0137': 'k', - '\u1E35': 'k', - '\u0199': 'k', - '\u2C6A': 'k', - '\uA741': 'k', - '\uA743': 'k', - '\uA745': 'k', - '\uA7A3': 'k', - '\u24DB': 'l', - '\uFF4C': 'l', - '\u0140': 'l', - '\u013A': 'l', - '\u013E': 'l', - '\u1E37': 'l', - '\u1E39': 'l', - '\u013C': 'l', - '\u1E3D': 'l', - '\u1E3B': 'l', - '\u017F': 'l', - '\u0142': 'l', - '\u019A': 'l', - '\u026B': 'l', - '\u2C61': 'l', - '\uA749': 'l', - '\uA781': 'l', - '\uA747': 'l', - '\u01C9': 'lj', - '\u24DC': 'm', - '\uFF4D': 'm', - '\u1E3F': 'm', - '\u1E41': 'm', - '\u1E43': 'm', - '\u0271': 'm', - '\u026F': 'm', - '\u24DD': 'n', - '\uFF4E': 'n', - '\u01F9': 'n', - '\u0144': 'n', - '\u00F1': 'n', - '\u1E45': 'n', - '\u0148': 'n', - '\u1E47': 'n', - '\u0146': 'n', - '\u1E4B': 'n', - '\u1E49': 'n', - '\u019E': 'n', - '\u0272': 'n', - '\u0149': 'n', - '\uA791': 'n', - '\uA7A5': 'n', - '\u01CC': 'nj', - '\u24DE': 'o', - '\uFF4F': 'o', - '\u00F2': 'o', - '\u00F3': 'o', - '\u00F4': 'o', - '\u1ED3': 'o', - '\u1ED1': 'o', - '\u1ED7': 'o', - '\u1ED5': 'o', - '\u00F5': 'o', - '\u1E4D': 'o', - '\u022D': 'o', - '\u1E4F': 'o', - '\u014D': 'o', - '\u1E51': 'o', - '\u1E53': 'o', - '\u014F': 'o', - '\u022F': 'o', - '\u0231': 'o', - '\u00F6': 'o', - '\u022B': 'o', - '\u1ECF': 'o', - '\u0151': 'o', - '\u01D2': 'o', - '\u020D': 'o', - '\u020F': 'o', - '\u01A1': 'o', - '\u1EDD': 'o', - '\u1EDB': 'o', - '\u1EE1': 'o', - '\u1EDF': 'o', - '\u1EE3': 'o', - '\u1ECD': 'o', - '\u1ED9': 'o', - '\u01EB': 'o', - '\u01ED': 'o', - '\u00F8': 'o', - '\u01FF': 'o', - '\u0254': 'o', - '\uA74B': 'o', - '\uA74D': 'o', - '\u0275': 'o', - '\u01A3': 'oi', - '\u0223': 'ou', - '\uA74F': 'oo', - '\u24DF': 'p', - '\uFF50': 'p', - '\u1E55': 'p', - '\u1E57': 'p', - '\u01A5': 'p', - '\u1D7D': 'p', - '\uA751': 'p', - '\uA753': 'p', - '\uA755': 'p', - '\u24E0': 'q', - '\uFF51': 'q', - '\u024B': 'q', - '\uA757': 'q', - '\uA759': 'q', - '\u24E1': 'r', - '\uFF52': 'r', - '\u0155': 'r', - '\u1E59': 'r', - '\u0159': 'r', - '\u0211': 'r', - '\u0213': 'r', - '\u1E5B': 'r', - '\u1E5D': 'r', - '\u0157': 'r', - '\u1E5F': 'r', - '\u024D': 'r', - '\u027D': 'r', - '\uA75B': 'r', - '\uA7A7': 'r', - '\uA783': 'r', - '\u24E2': 's', - '\uFF53': 's', - '\u00DF': 's', - '\u015B': 's', - '\u1E65': 's', - '\u015D': 's', - '\u1E61': 's', - '\u0161': 's', - '\u1E67': 's', - '\u1E63': 's', - '\u1E69': 's', - '\u0219': 's', - '\u015F': 's', - '\u023F': 's', - '\uA7A9': 's', - '\uA785': 's', - '\u1E9B': 's', - '\u24E3': 't', - '\uFF54': 't', - '\u1E6B': 't', - '\u1E97': 't', - '\u0165': 't', - '\u1E6D': 't', - '\u021B': 't', - '\u0163': 't', - '\u1E71': 't', - '\u1E6F': 't', - '\u0167': 't', - '\u01AD': 't', - '\u0288': 't', - '\u2C66': 't', - '\uA787': 't', - '\uA729': 'tz', - '\u24E4': 'u', - '\uFF55': 'u', - '\u00F9': 'u', - '\u00FA': 'u', - '\u00FB': 'u', - '\u0169': 'u', - '\u1E79': 'u', - '\u016B': 'u', - '\u1E7B': 'u', - '\u016D': 'u', - '\u00FC': 'u', - '\u01DC': 'u', - '\u01D8': 'u', - '\u01D6': 'u', - '\u01DA': 'u', - '\u1EE7': 'u', - '\u016F': 'u', - '\u0171': 'u', - '\u01D4': 'u', - '\u0215': 'u', - '\u0217': 'u', - '\u01B0': 'u', - '\u1EEB': 'u', - '\u1EE9': 'u', - '\u1EEF': 'u', - '\u1EED': 'u', - '\u1EF1': 'u', - '\u1EE5': 'u', - '\u1E73': 'u', - '\u0173': 'u', - '\u1E77': 'u', - '\u1E75': 'u', - '\u0289': 'u', - '\u24E5': 'v', - '\uFF56': 'v', - '\u1E7D': 'v', - '\u1E7F': 'v', - '\u028B': 'v', - '\uA75F': 'v', - '\u028C': 'v', - '\uA761': 'vy', - '\u24E6': 'w', - '\uFF57': 'w', - '\u1E81': 'w', - '\u1E83': 'w', - '\u0175': 'w', - '\u1E87': 'w', - '\u1E85': 'w', - '\u1E98': 'w', - '\u1E89': 'w', - '\u2C73': 'w', - '\u24E7': 'x', - '\uFF58': 'x', - '\u1E8B': 'x', - '\u1E8D': 'x', - '\u24E8': 'y', - '\uFF59': 'y', - '\u1EF3': 'y', - '\u00FD': 'y', - '\u0177': 'y', - '\u1EF9': 'y', - '\u0233': 'y', - '\u1E8F': 'y', - '\u00FF': 'y', - '\u1EF7': 'y', - '\u1E99': 'y', - '\u1EF5': 'y', - '\u01B4': 'y', - '\u024F': 'y', - '\u1EFF': 'y', - '\u24E9': 'z', - '\uFF5A': 'z', - '\u017A': 'z', - '\u1E91': 'z', - '\u017C': 'z', - '\u017E': 'z', - '\u1E93': 'z', - '\u1E95': 'z', - '\u01B6': 'z', - '\u0225': 'z', - '\u0240': 'z', - '\u2C6C': 'z', - '\uA763': 'z', - '\u0386': '\u0391', - '\u0388': '\u0395', - '\u0389': '\u0397', - '\u038A': '\u0399', - '\u03AA': '\u0399', - '\u038C': '\u039F', - '\u038E': '\u03A5', - '\u03AB': '\u03A5', - '\u038F': '\u03A9', - '\u03AC': '\u03B1', - '\u03AD': '\u03B5', - '\u03AE': '\u03B7', - '\u03AF': '\u03B9', - '\u03CA': '\u03B9', - '\u0390': '\u03B9', - '\u03CC': '\u03BF', - '\u03CD': '\u03C5', - '\u03CB': '\u03C5', - '\u03B0': '\u03C5', - '\u03C9': '\u03C9', - '\u03C2': '\u03C3' - }; - - return diacritics; -}); - -S2.define('select2/data/base',[ - '../utils' -], function (Utils) { - function BaseAdapter ($element, options) { - BaseAdapter.__super__.constructor.call(this); - } + evt.preventDefault(); + } + } else if (evt.which === KEYS.ENTER) { + container.open(); + evt.preventDefault(); + } + }); - Utils.Extend(BaseAdapter, Utils.Observable); + // 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. + // This property is not available in Edge, but Edge also doesn't have + // this bug. + var msie = document.documentMode; + var disableInputEvents = msie && msie <= 11; + + // Workaround for browsers which do not support the `input` event + // This will prevent double-triggering of events for browsers which support + // both the `keyup` and `input` events. + this.$selection.on( + 'input.searchcheck', + '.select2-search--inline', + function (evt) { + // IE will trigger the `input` event when a placeholder is used on a + // search box. To get around this issue, we are forced to ignore all + // `input` events in IE and keep using `keyup`. + if (disableInputEvents) { + self.$selection.off('input.search input.searchcheck'); + return; + } - BaseAdapter.prototype.current = function (callback) { - throw new Error('The `current` method must be defined in child classes.'); - }; + // Unbind the duplicated `keyup` event + self.$selection.off('keyup.search'); + } + ); - BaseAdapter.prototype.query = function (params, callback) { - throw new Error('The `query` method must be defined in child classes.'); - }; + this.$selection.on( + 'keyup.search input.search', + '.select2-search--inline', + function (evt) { + // IE will trigger the `input` event when a placeholder is used on a + // search box. To get around this issue, we are forced to ignore all + // `input` events in IE and keep using `keyup`. + if (disableInputEvents && evt.type === 'input') { + self.$selection.off('input.search input.searchcheck'); + return; + } - BaseAdapter.prototype.bind = function (container, $container) { - // Can be implemented in subclasses - }; + var key = evt.which; - BaseAdapter.prototype.destroy = function () { - // Can be implemented in subclasses - }; + // We can freely ignore events from modifier keys + if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) { + return; + } - BaseAdapter.prototype.generateResultId = function (container, data) { - var id = ''; + // Tabbing will be handled during the `keydown` phase + if (key == KEYS.TAB) { + return; + } - if (container != null) { - id += container.id - } else { - id += Utils.generateChars(4); - } + self.handleSearch(evt); + } + ); + }; - id += '-result-'; - id += Utils.generateChars(4); + /** + * This method will transfer the tabindex attribute from the rendered + * selection to the search box. This allows for the search box to be used as + * the primary focus instead of the selection container. + * + * @private + */ + Search.prototype._transferTabIndex = function (decorated) { + this.$search.attr('tabindex', this.$selection.attr('tabindex')); + this.$selection.attr('tabindex', '-1'); + }; - if (data.id != null) { - id += '-' + data.id.toString(); - } else { - id += '-' + Utils.generateChars(4); - } - return id; - }; - - return BaseAdapter; -}); - -S2.define('select2/data/select',[ - './base', - '../utils', - 'jquery' -], function (BaseAdapter, Utils, $) { - function SelectAdapter ($element, options) { - this.$element = $element; - this.options = options; - - SelectAdapter.__super__.constructor.call(this); - } + Search.prototype.createPlaceholder = function (decorated, placeholder) { + this.$search.attr('placeholder', placeholder.text); + }; - Utils.Extend(SelectAdapter, BaseAdapter); + Search.prototype.update = function (decorated, data) { + var searchHadFocus = this.$search[0] == document.activeElement; - SelectAdapter.prototype.current = function (callback) { - var data = []; - var self = this; + this.$search.attr('placeholder', ''); - this.$element.find(':selected').each(function () { - var $option = $(this); + decorated.call(this, data); - var option = self.item($option); + this.$selection.find('.select2-selection__rendered') + .append(this.$searchContainer); - data.push(option); - }); + this.resizeSearch(); + if (searchHadFocus) { + this.$search.focus(); + } + }; - callback(data); - }; + Search.prototype.handleSearch = function () { + this.resizeSearch(); - SelectAdapter.prototype.select = function (data) { - var self = this; + if (!this._keyUpPrevented) { + var input = this.$search.val(); - data.selected = true; + this.trigger('query', { + term: input + }); + } - // If data.element is a DOM node, use it instead - if ($(data.element).is('option')) { - data.element.selected = true; + this._keyUpPrevented = false; + }; - this.$element.trigger('change'); + Search.prototype.searchRemoveChoice = function (decorated, item) { + this.trigger('unselect', { + data: item + }); - return; - } + this.$search.val(item.text); + this.handleSearch(); + }; - if (this.$element.prop('multiple')) { - this.current(function (currentData) { - var val = []; + Search.prototype.resizeSearch = function () { + this.$search.css('width', '25px'); - data = [data]; - data.push.apply(data, currentData); + var width = ''; - for (var d = 0; d < data.length; d++) { - var id = data[d].id; + if (this.$search.attr('placeholder') !== '') { + width = this.$selection.find('.select2-selection__rendered').innerWidth(); + } else { + var minimumWidth = this.$search.val().length + 1; - if ($.inArray(id, val) === -1) { - val.push(id); - } + width = (minimumWidth * 0.75) + 'em'; } - self.$element.val(val); - self.$element.trigger('change'); - }); - } else { - var val = data.id; - - this.$element.val(val); - this.$element.trigger('change'); - } - }; - - SelectAdapter.prototype.unselect = function (data) { - var self = this; - - if (!this.$element.prop('multiple')) { - return; - } + this.$search.css('width', width); + }; - data.selected = false; + return Search; + }); - if ($(data.element).is('option')) { - data.element.selected = false; + S2.define('select2/selection/eventRelay',[ + 'jquery' + ], function ($) { + function EventRelay () { } - this.$element.trigger('change'); + EventRelay.prototype.bind = function (decorated, container, $container) { + var self = this; + var relayEvents = [ + 'open', 'opening', + 'close', 'closing', + 'select', 'selecting', + 'unselect', 'unselecting' + ]; - return; - } + var preventableEvents = ['opening', 'closing', 'selecting', 'unselecting']; - this.current(function (currentData) { - var val = []; + decorated.call(this, container, $container); - for (var d = 0; d < currentData.length; d++) { - var id = currentData[d].id; + container.on('*', function (name, params) { + // Ignore events that should not be relayed + if ($.inArray(name, relayEvents) === -1) { + return; + } - if (id !== data.id && $.inArray(id, val) === -1) { - val.push(id); - } - } + // The parameters should always be an object + params = params || {}; - self.$element.val(val); + // Generate the jQuery event for the Select2 event + var evt = $.Event('select2:' + name, { + params: params + }); - self.$element.trigger('change'); - }); - }; + self.$element.trigger(evt); - SelectAdapter.prototype.bind = function (container, $container) { - var self = this; + // Only handle preventable events if it was one + if ($.inArray(name, preventableEvents) === -1) { + return; + } - this.container = container; + params.prevented = evt.isDefaultPrevented(); + }); + }; - container.on('select', function (params) { - self.select(params.data); + return EventRelay; }); - container.on('unselect', function (params) { - self.unselect(params.data); - }); - }; + S2.define('select2/translation',[ + 'jquery', + 'require' + ], function ($, require) { + function Translation (dict) { + this.dict = dict || {}; + } - 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'); - }); - }; + Translation.prototype.all = function () { + return this.dict; + }; - SelectAdapter.prototype.query = function (params, callback) { - var data = []; - var self = this; + Translation.prototype.get = function (key) { + return this.dict[key]; + }; - var $options = this.$element.children(); + Translation.prototype.extend = function (translation) { + this.dict = $.extend({}, translation.all(), this.dict); + }; - $options.each(function () { - var $option = $(this); + // Static functions - if (!$option.is('option') && !$option.is('optgroup')) { - return; - } + Translation._cache = {}; - var option = self.item($option); + Translation.loadPath = function (path) { + if (!(path in Translation._cache)) { + var translations = require(path); - var matches = self.matches(params, option); + Translation._cache[path] = translations; + } - if (matches !== null) { - data.push(matches); - } - }); + return new Translation(Translation._cache[path]); + }; - callback({ - results: data + return Translation; }); - }; - - SelectAdapter.prototype.addOptions = function ($options) { - Utils.appendMany(this.$element, $options); - }; - SelectAdapter.prototype.option = function (data) { - var option; + S2.define('select2/diacritics',[ + + ], function () { + var diacritics = { + '\u24B6': 'A', + '\uFF21': 'A', + '\u00C0': 'A', + '\u00C1': 'A', + '\u00C2': 'A', + '\u1EA6': 'A', + '\u1EA4': 'A', + '\u1EAA': 'A', + '\u1EA8': 'A', + '\u00C3': 'A', + '\u0100': 'A', + '\u0102': 'A', + '\u1EB0': 'A', + '\u1EAE': 'A', + '\u1EB4': 'A', + '\u1EB2': 'A', + '\u0226': 'A', + '\u01E0': 'A', + '\u00C4': 'A', + '\u01DE': 'A', + '\u1EA2': 'A', + '\u00C5': 'A', + '\u01FA': 'A', + '\u01CD': 'A', + '\u0200': 'A', + '\u0202': 'A', + '\u1EA0': 'A', + '\u1EAC': 'A', + '\u1EB6': 'A', + '\u1E00': 'A', + '\u0104': 'A', + '\u023A': 'A', + '\u2C6F': 'A', + '\uA732': 'AA', + '\u00C6': 'AE', + '\u01FC': 'AE', + '\u01E2': 'AE', + '\uA734': 'AO', + '\uA736': 'AU', + '\uA738': 'AV', + '\uA73A': 'AV', + '\uA73C': 'AY', + '\u24B7': 'B', + '\uFF22': 'B', + '\u1E02': 'B', + '\u1E04': 'B', + '\u1E06': 'B', + '\u0243': 'B', + '\u0182': 'B', + '\u0181': 'B', + '\u24B8': 'C', + '\uFF23': 'C', + '\u0106': 'C', + '\u0108': 'C', + '\u010A': 'C', + '\u010C': 'C', + '\u00C7': 'C', + '\u1E08': 'C', + '\u0187': 'C', + '\u023B': 'C', + '\uA73E': 'C', + '\u24B9': 'D', + '\uFF24': 'D', + '\u1E0A': 'D', + '\u010E': 'D', + '\u1E0C': 'D', + '\u1E10': 'D', + '\u1E12': 'D', + '\u1E0E': 'D', + '\u0110': 'D', + '\u018B': 'D', + '\u018A': 'D', + '\u0189': 'D', + '\uA779': 'D', + '\u01F1': 'DZ', + '\u01C4': 'DZ', + '\u01F2': 'Dz', + '\u01C5': 'Dz', + '\u24BA': 'E', + '\uFF25': 'E', + '\u00C8': 'E', + '\u00C9': 'E', + '\u00CA': 'E', + '\u1EC0': 'E', + '\u1EBE': 'E', + '\u1EC4': 'E', + '\u1EC2': 'E', + '\u1EBC': 'E', + '\u0112': 'E', + '\u1E14': 'E', + '\u1E16': 'E', + '\u0114': 'E', + '\u0116': 'E', + '\u00CB': 'E', + '\u1EBA': 'E', + '\u011A': 'E', + '\u0204': 'E', + '\u0206': 'E', + '\u1EB8': 'E', + '\u1EC6': 'E', + '\u0228': 'E', + '\u1E1C': 'E', + '\u0118': 'E', + '\u1E18': 'E', + '\u1E1A': 'E', + '\u0190': 'E', + '\u018E': 'E', + '\u24BB': 'F', + '\uFF26': 'F', + '\u1E1E': 'F', + '\u0191': 'F', + '\uA77B': 'F', + '\u24BC': 'G', + '\uFF27': 'G', + '\u01F4': 'G', + '\u011C': 'G', + '\u1E20': 'G', + '\u011E': 'G', + '\u0120': 'G', + '\u01E6': 'G', + '\u0122': 'G', + '\u01E4': 'G', + '\u0193': 'G', + '\uA7A0': 'G', + '\uA77D': 'G', + '\uA77E': 'G', + '\u24BD': 'H', + '\uFF28': 'H', + '\u0124': 'H', + '\u1E22': 'H', + '\u1E26': 'H', + '\u021E': 'H', + '\u1E24': 'H', + '\u1E28': 'H', + '\u1E2A': 'H', + '\u0126': 'H', + '\u2C67': 'H', + '\u2C75': 'H', + '\uA78D': 'H', + '\u24BE': 'I', + '\uFF29': 'I', + '\u00CC': 'I', + '\u00CD': 'I', + '\u00CE': 'I', + '\u0128': 'I', + '\u012A': 'I', + '\u012C': 'I', + '\u0130': 'I', + '\u00CF': 'I', + '\u1E2E': 'I', + '\u1EC8': 'I', + '\u01CF': 'I', + '\u0208': 'I', + '\u020A': 'I', + '\u1ECA': 'I', + '\u012E': 'I', + '\u1E2C': 'I', + '\u0197': 'I', + '\u24BF': 'J', + '\uFF2A': 'J', + '\u0134': 'J', + '\u0248': 'J', + '\u24C0': 'K', + '\uFF2B': 'K', + '\u1E30': 'K', + '\u01E8': 'K', + '\u1E32': 'K', + '\u0136': 'K', + '\u1E34': 'K', + '\u0198': 'K', + '\u2C69': 'K', + '\uA740': 'K', + '\uA742': 'K', + '\uA744': 'K', + '\uA7A2': 'K', + '\u24C1': 'L', + '\uFF2C': 'L', + '\u013F': 'L', + '\u0139': 'L', + '\u013D': 'L', + '\u1E36': 'L', + '\u1E38': 'L', + '\u013B': 'L', + '\u1E3C': 'L', + '\u1E3A': 'L', + '\u0141': 'L', + '\u023D': 'L', + '\u2C62': 'L', + '\u2C60': 'L', + '\uA748': 'L', + '\uA746': 'L', + '\uA780': 'L', + '\u01C7': 'LJ', + '\u01C8': 'Lj', + '\u24C2': 'M', + '\uFF2D': 'M', + '\u1E3E': 'M', + '\u1E40': 'M', + '\u1E42': 'M', + '\u2C6E': 'M', + '\u019C': 'M', + '\u24C3': 'N', + '\uFF2E': 'N', + '\u01F8': 'N', + '\u0143': 'N', + '\u00D1': 'N', + '\u1E44': 'N', + '\u0147': 'N', + '\u1E46': 'N', + '\u0145': 'N', + '\u1E4A': 'N', + '\u1E48': 'N', + '\u0220': 'N', + '\u019D': 'N', + '\uA790': 'N', + '\uA7A4': 'N', + '\u01CA': 'NJ', + '\u01CB': 'Nj', + '\u24C4': 'O', + '\uFF2F': 'O', + '\u00D2': 'O', + '\u00D3': 'O', + '\u00D4': 'O', + '\u1ED2': 'O', + '\u1ED0': 'O', + '\u1ED6': 'O', + '\u1ED4': 'O', + '\u00D5': 'O', + '\u1E4C': 'O', + '\u022C': 'O', + '\u1E4E': 'O', + '\u014C': 'O', + '\u1E50': 'O', + '\u1E52': 'O', + '\u014E': 'O', + '\u022E': 'O', + '\u0230': 'O', + '\u00D6': 'O', + '\u022A': 'O', + '\u1ECE': 'O', + '\u0150': 'O', + '\u01D1': 'O', + '\u020C': 'O', + '\u020E': 'O', + '\u01A0': 'O', + '\u1EDC': 'O', + '\u1EDA': 'O', + '\u1EE0': 'O', + '\u1EDE': 'O', + '\u1EE2': 'O', + '\u1ECC': 'O', + '\u1ED8': 'O', + '\u01EA': 'O', + '\u01EC': 'O', + '\u00D8': 'O', + '\u01FE': 'O', + '\u0186': 'O', + '\u019F': 'O', + '\uA74A': 'O', + '\uA74C': 'O', + '\u01A2': 'OI', + '\uA74E': 'OO', + '\u0222': 'OU', + '\u24C5': 'P', + '\uFF30': 'P', + '\u1E54': 'P', + '\u1E56': 'P', + '\u01A4': 'P', + '\u2C63': 'P', + '\uA750': 'P', + '\uA752': 'P', + '\uA754': 'P', + '\u24C6': 'Q', + '\uFF31': 'Q', + '\uA756': 'Q', + '\uA758': 'Q', + '\u024A': 'Q', + '\u24C7': 'R', + '\uFF32': 'R', + '\u0154': 'R', + '\u1E58': 'R', + '\u0158': 'R', + '\u0210': 'R', + '\u0212': 'R', + '\u1E5A': 'R', + '\u1E5C': 'R', + '\u0156': 'R', + '\u1E5E': 'R', + '\u024C': 'R', + '\u2C64': 'R', + '\uA75A': 'R', + '\uA7A6': 'R', + '\uA782': 'R', + '\u24C8': 'S', + '\uFF33': 'S', + '\u1E9E': 'S', + '\u015A': 'S', + '\u1E64': 'S', + '\u015C': 'S', + '\u1E60': 'S', + '\u0160': 'S', + '\u1E66': 'S', + '\u1E62': 'S', + '\u1E68': 'S', + '\u0218': 'S', + '\u015E': 'S', + '\u2C7E': 'S', + '\uA7A8': 'S', + '\uA784': 'S', + '\u24C9': 'T', + '\uFF34': 'T', + '\u1E6A': 'T', + '\u0164': 'T', + '\u1E6C': 'T', + '\u021A': 'T', + '\u0162': 'T', + '\u1E70': 'T', + '\u1E6E': 'T', + '\u0166': 'T', + '\u01AC': 'T', + '\u01AE': 'T', + '\u023E': 'T', + '\uA786': 'T', + '\uA728': 'TZ', + '\u24CA': 'U', + '\uFF35': 'U', + '\u00D9': 'U', + '\u00DA': 'U', + '\u00DB': 'U', + '\u0168': 'U', + '\u1E78': 'U', + '\u016A': 'U', + '\u1E7A': 'U', + '\u016C': 'U', + '\u00DC': 'U', + '\u01DB': 'U', + '\u01D7': 'U', + '\u01D5': 'U', + '\u01D9': 'U', + '\u1EE6': 'U', + '\u016E': 'U', + '\u0170': 'U', + '\u01D3': 'U', + '\u0214': 'U', + '\u0216': 'U', + '\u01AF': 'U', + '\u1EEA': 'U', + '\u1EE8': 'U', + '\u1EEE': 'U', + '\u1EEC': 'U', + '\u1EF0': 'U', + '\u1EE4': 'U', + '\u1E72': 'U', + '\u0172': 'U', + '\u1E76': 'U', + '\u1E74': 'U', + '\u0244': 'U', + '\u24CB': 'V', + '\uFF36': 'V', + '\u1E7C': 'V', + '\u1E7E': 'V', + '\u01B2': 'V', + '\uA75E': 'V', + '\u0245': 'V', + '\uA760': 'VY', + '\u24CC': 'W', + '\uFF37': 'W', + '\u1E80': 'W', + '\u1E82': 'W', + '\u0174': 'W', + '\u1E86': 'W', + '\u1E84': 'W', + '\u1E88': 'W', + '\u2C72': 'W', + '\u24CD': 'X', + '\uFF38': 'X', + '\u1E8A': 'X', + '\u1E8C': 'X', + '\u24CE': 'Y', + '\uFF39': 'Y', + '\u1EF2': 'Y', + '\u00DD': 'Y', + '\u0176': 'Y', + '\u1EF8': 'Y', + '\u0232': 'Y', + '\u1E8E': 'Y', + '\u0178': 'Y', + '\u1EF6': 'Y', + '\u1EF4': 'Y', + '\u01B3': 'Y', + '\u024E': 'Y', + '\u1EFE': 'Y', + '\u24CF': 'Z', + '\uFF3A': 'Z', + '\u0179': 'Z', + '\u1E90': 'Z', + '\u017B': 'Z', + '\u017D': 'Z', + '\u1E92': 'Z', + '\u1E94': 'Z', + '\u01B5': 'Z', + '\u0224': 'Z', + '\u2C7F': 'Z', + '\u2C6B': 'Z', + '\uA762': 'Z', + '\u24D0': 'a', + '\uFF41': 'a', + '\u1E9A': 'a', + '\u00E0': 'a', + '\u00E1': 'a', + '\u00E2': 'a', + '\u1EA7': 'a', + '\u1EA5': 'a', + '\u1EAB': 'a', + '\u1EA9': 'a', + '\u00E3': 'a', + '\u0101': 'a', + '\u0103': 'a', + '\u1EB1': 'a', + '\u1EAF': 'a', + '\u1EB5': 'a', + '\u1EB3': 'a', + '\u0227': 'a', + '\u01E1': 'a', + '\u00E4': 'a', + '\u01DF': 'a', + '\u1EA3': 'a', + '\u00E5': 'a', + '\u01FB': 'a', + '\u01CE': 'a', + '\u0201': 'a', + '\u0203': 'a', + '\u1EA1': 'a', + '\u1EAD': 'a', + '\u1EB7': 'a', + '\u1E01': 'a', + '\u0105': 'a', + '\u2C65': 'a', + '\u0250': 'a', + '\uA733': 'aa', + '\u00E6': 'ae', + '\u01FD': 'ae', + '\u01E3': 'ae', + '\uA735': 'ao', + '\uA737': 'au', + '\uA739': 'av', + '\uA73B': 'av', + '\uA73D': 'ay', + '\u24D1': 'b', + '\uFF42': 'b', + '\u1E03': 'b', + '\u1E05': 'b', + '\u1E07': 'b', + '\u0180': 'b', + '\u0183': 'b', + '\u0253': 'b', + '\u24D2': 'c', + '\uFF43': 'c', + '\u0107': 'c', + '\u0109': 'c', + '\u010B': 'c', + '\u010D': 'c', + '\u00E7': 'c', + '\u1E09': 'c', + '\u0188': 'c', + '\u023C': 'c', + '\uA73F': 'c', + '\u2184': 'c', + '\u24D3': 'd', + '\uFF44': 'd', + '\u1E0B': 'd', + '\u010F': 'd', + '\u1E0D': 'd', + '\u1E11': 'd', + '\u1E13': 'd', + '\u1E0F': 'd', + '\u0111': 'd', + '\u018C': 'd', + '\u0256': 'd', + '\u0257': 'd', + '\uA77A': 'd', + '\u01F3': 'dz', + '\u01C6': 'dz', + '\u24D4': 'e', + '\uFF45': 'e', + '\u00E8': 'e', + '\u00E9': 'e', + '\u00EA': 'e', + '\u1EC1': 'e', + '\u1EBF': 'e', + '\u1EC5': 'e', + '\u1EC3': 'e', + '\u1EBD': 'e', + '\u0113': 'e', + '\u1E15': 'e', + '\u1E17': 'e', + '\u0115': 'e', + '\u0117': 'e', + '\u00EB': 'e', + '\u1EBB': 'e', + '\u011B': 'e', + '\u0205': 'e', + '\u0207': 'e', + '\u1EB9': 'e', + '\u1EC7': 'e', + '\u0229': 'e', + '\u1E1D': 'e', + '\u0119': 'e', + '\u1E19': 'e', + '\u1E1B': 'e', + '\u0247': 'e', + '\u025B': 'e', + '\u01DD': 'e', + '\u24D5': 'f', + '\uFF46': 'f', + '\u1E1F': 'f', + '\u0192': 'f', + '\uA77C': 'f', + '\u24D6': 'g', + '\uFF47': 'g', + '\u01F5': 'g', + '\u011D': 'g', + '\u1E21': 'g', + '\u011F': 'g', + '\u0121': 'g', + '\u01E7': 'g', + '\u0123': 'g', + '\u01E5': 'g', + '\u0260': 'g', + '\uA7A1': 'g', + '\u1D79': 'g', + '\uA77F': 'g', + '\u24D7': 'h', + '\uFF48': 'h', + '\u0125': 'h', + '\u1E23': 'h', + '\u1E27': 'h', + '\u021F': 'h', + '\u1E25': 'h', + '\u1E29': 'h', + '\u1E2B': 'h', + '\u1E96': 'h', + '\u0127': 'h', + '\u2C68': 'h', + '\u2C76': 'h', + '\u0265': 'h', + '\u0195': 'hv', + '\u24D8': 'i', + '\uFF49': 'i', + '\u00EC': 'i', + '\u00ED': 'i', + '\u00EE': 'i', + '\u0129': 'i', + '\u012B': 'i', + '\u012D': 'i', + '\u00EF': 'i', + '\u1E2F': 'i', + '\u1EC9': 'i', + '\u01D0': 'i', + '\u0209': 'i', + '\u020B': 'i', + '\u1ECB': 'i', + '\u012F': 'i', + '\u1E2D': 'i', + '\u0268': 'i', + '\u0131': 'i', + '\u24D9': 'j', + '\uFF4A': 'j', + '\u0135': 'j', + '\u01F0': 'j', + '\u0249': 'j', + '\u24DA': 'k', + '\uFF4B': 'k', + '\u1E31': 'k', + '\u01E9': 'k', + '\u1E33': 'k', + '\u0137': 'k', + '\u1E35': 'k', + '\u0199': 'k', + '\u2C6A': 'k', + '\uA741': 'k', + '\uA743': 'k', + '\uA745': 'k', + '\uA7A3': 'k', + '\u24DB': 'l', + '\uFF4C': 'l', + '\u0140': 'l', + '\u013A': 'l', + '\u013E': 'l', + '\u1E37': 'l', + '\u1E39': 'l', + '\u013C': 'l', + '\u1E3D': 'l', + '\u1E3B': 'l', + '\u017F': 'l', + '\u0142': 'l', + '\u019A': 'l', + '\u026B': 'l', + '\u2C61': 'l', + '\uA749': 'l', + '\uA781': 'l', + '\uA747': 'l', + '\u01C9': 'lj', + '\u24DC': 'm', + '\uFF4D': 'm', + '\u1E3F': 'm', + '\u1E41': 'm', + '\u1E43': 'm', + '\u0271': 'm', + '\u026F': 'm', + '\u24DD': 'n', + '\uFF4E': 'n', + '\u01F9': 'n', + '\u0144': 'n', + '\u00F1': 'n', + '\u1E45': 'n', + '\u0148': 'n', + '\u1E47': 'n', + '\u0146': 'n', + '\u1E4B': 'n', + '\u1E49': 'n', + '\u019E': 'n', + '\u0272': 'n', + '\u0149': 'n', + '\uA791': 'n', + '\uA7A5': 'n', + '\u01CC': 'nj', + '\u24DE': 'o', + '\uFF4F': 'o', + '\u00F2': 'o', + '\u00F3': 'o', + '\u00F4': 'o', + '\u1ED3': 'o', + '\u1ED1': 'o', + '\u1ED7': 'o', + '\u1ED5': 'o', + '\u00F5': 'o', + '\u1E4D': 'o', + '\u022D': 'o', + '\u1E4F': 'o', + '\u014D': 'o', + '\u1E51': 'o', + '\u1E53': 'o', + '\u014F': 'o', + '\u022F': 'o', + '\u0231': 'o', + '\u00F6': 'o', + '\u022B': 'o', + '\u1ECF': 'o', + '\u0151': 'o', + '\u01D2': 'o', + '\u020D': 'o', + '\u020F': 'o', + '\u01A1': 'o', + '\u1EDD': 'o', + '\u1EDB': 'o', + '\u1EE1': 'o', + '\u1EDF': 'o', + '\u1EE3': 'o', + '\u1ECD': 'o', + '\u1ED9': 'o', + '\u01EB': 'o', + '\u01ED': 'o', + '\u00F8': 'o', + '\u01FF': 'o', + '\u0254': 'o', + '\uA74B': 'o', + '\uA74D': 'o', + '\u0275': 'o', + '\u01A3': 'oi', + '\u0223': 'ou', + '\uA74F': 'oo', + '\u24DF': 'p', + '\uFF50': 'p', + '\u1E55': 'p', + '\u1E57': 'p', + '\u01A5': 'p', + '\u1D7D': 'p', + '\uA751': 'p', + '\uA753': 'p', + '\uA755': 'p', + '\u24E0': 'q', + '\uFF51': 'q', + '\u024B': 'q', + '\uA757': 'q', + '\uA759': 'q', + '\u24E1': 'r', + '\uFF52': 'r', + '\u0155': 'r', + '\u1E59': 'r', + '\u0159': 'r', + '\u0211': 'r', + '\u0213': 'r', + '\u1E5B': 'r', + '\u1E5D': 'r', + '\u0157': 'r', + '\u1E5F': 'r', + '\u024D': 'r', + '\u027D': 'r', + '\uA75B': 'r', + '\uA7A7': 'r', + '\uA783': 'r', + '\u24E2': 's', + '\uFF53': 's', + '\u00DF': 's', + '\u015B': 's', + '\u1E65': 's', + '\u015D': 's', + '\u1E61': 's', + '\u0161': 's', + '\u1E67': 's', + '\u1E63': 's', + '\u1E69': 's', + '\u0219': 's', + '\u015F': 's', + '\u023F': 's', + '\uA7A9': 's', + '\uA785': 's', + '\u1E9B': 's', + '\u24E3': 't', + '\uFF54': 't', + '\u1E6B': 't', + '\u1E97': 't', + '\u0165': 't', + '\u1E6D': 't', + '\u021B': 't', + '\u0163': 't', + '\u1E71': 't', + '\u1E6F': 't', + '\u0167': 't', + '\u01AD': 't', + '\u0288': 't', + '\u2C66': 't', + '\uA787': 't', + '\uA729': 'tz', + '\u24E4': 'u', + '\uFF55': 'u', + '\u00F9': 'u', + '\u00FA': 'u', + '\u00FB': 'u', + '\u0169': 'u', + '\u1E79': 'u', + '\u016B': 'u', + '\u1E7B': 'u', + '\u016D': 'u', + '\u00FC': 'u', + '\u01DC': 'u', + '\u01D8': 'u', + '\u01D6': 'u', + '\u01DA': 'u', + '\u1EE7': 'u', + '\u016F': 'u', + '\u0171': 'u', + '\u01D4': 'u', + '\u0215': 'u', + '\u0217': 'u', + '\u01B0': 'u', + '\u1EEB': 'u', + '\u1EE9': 'u', + '\u1EEF': 'u', + '\u1EED': 'u', + '\u1EF1': 'u', + '\u1EE5': 'u', + '\u1E73': 'u', + '\u0173': 'u', + '\u1E77': 'u', + '\u1E75': 'u', + '\u0289': 'u', + '\u24E5': 'v', + '\uFF56': 'v', + '\u1E7D': 'v', + '\u1E7F': 'v', + '\u028B': 'v', + '\uA75F': 'v', + '\u028C': 'v', + '\uA761': 'vy', + '\u24E6': 'w', + '\uFF57': 'w', + '\u1E81': 'w', + '\u1E83': 'w', + '\u0175': 'w', + '\u1E87': 'w', + '\u1E85': 'w', + '\u1E98': 'w', + '\u1E89': 'w', + '\u2C73': 'w', + '\u24E7': 'x', + '\uFF58': 'x', + '\u1E8B': 'x', + '\u1E8D': 'x', + '\u24E8': 'y', + '\uFF59': 'y', + '\u1EF3': 'y', + '\u00FD': 'y', + '\u0177': 'y', + '\u1EF9': 'y', + '\u0233': 'y', + '\u1E8F': 'y', + '\u00FF': 'y', + '\u1EF7': 'y', + '\u1E99': 'y', + '\u1EF5': 'y', + '\u01B4': 'y', + '\u024F': 'y', + '\u1EFF': 'y', + '\u24E9': 'z', + '\uFF5A': 'z', + '\u017A': 'z', + '\u1E91': 'z', + '\u017C': 'z', + '\u017E': 'z', + '\u1E93': 'z', + '\u1E95': 'z', + '\u01B6': 'z', + '\u0225': 'z', + '\u0240': 'z', + '\u2C6C': 'z', + '\uA763': 'z', + '\u0386': '\u0391', + '\u0388': '\u0395', + '\u0389': '\u0397', + '\u038A': '\u0399', + '\u03AA': '\u0399', + '\u038C': '\u039F', + '\u038E': '\u03A5', + '\u03AB': '\u03A5', + '\u038F': '\u03A9', + '\u03AC': '\u03B1', + '\u03AD': '\u03B5', + '\u03AE': '\u03B7', + '\u03AF': '\u03B9', + '\u03CA': '\u03B9', + '\u0390': '\u03B9', + '\u03CC': '\u03BF', + '\u03CD': '\u03C5', + '\u03CB': '\u03C5', + '\u03B0': '\u03C5', + '\u03C9': '\u03C9', + '\u03C2': '\u03C3' + }; - if (data.children) { - option = document.createElement('optgroup'); - option.label = data.text; - } else { - option = document.createElement('option'); + return diacritics; + }); - if (option.textContent !== undefined) { - option.textContent = data.text; - } else { - option.innerText = data.text; + S2.define('select2/data/base',[ + '../utils' + ], function (Utils) { + function BaseAdapter ($element, options) { + BaseAdapter.__super__.constructor.call(this); } - } - if (data.id !== undefined) { - option.value = data.id; - } - - if (data.disabled) { - option.disabled = true; - } - - if (data.selected) { - option.selected = true; - } - - if (data.title) { - option.title = data.title; - } + Utils.Extend(BaseAdapter, Utils.Observable); - var $option = $(option); + BaseAdapter.prototype.current = function (callback) { + throw new Error('The `current` method must be defined in child classes.'); + }; - var normalizedData = this._normalizeItem(data); - normalizedData.element = option; + BaseAdapter.prototype.query = function (params, callback) { + throw new Error('The `query` method must be defined in child classes.'); + }; - // Override the option's data with the combined data - $.data(option, 'data', normalizedData); + BaseAdapter.prototype.bind = function (container, $container) { + // Can be implemented in subclasses + }; - return $option; - }; + BaseAdapter.prototype.destroy = function () { + // Can be implemented in subclasses + }; - SelectAdapter.prototype.item = function ($option) { - var data = {}; + BaseAdapter.prototype.generateResultId = function (container, data) { + var id = ''; - data = $.data($option[0], 'data'); + if (container != null) { + id += container.id + } else { + id += Utils.generateChars(4); + } - if (data != null) { - return data; - } + id += '-result-'; + id += Utils.generateChars(4); - if ($option.is('option')) { - data = { - id: $option.val(), - text: $option.text(), - disabled: $option.prop('disabled'), - selected: $option.prop('selected'), - title: $option.prop('title') - }; - } else if ($option.is('optgroup')) { - data = { - text: $option.prop('label'), - children: [], - title: $option.prop('title') + if (data.id != null) { + id += '-' + data.id.toString(); + } else { + id += '-' + Utils.generateChars(4); + } + return id; }; - var $children = $option.children('option'); - var children = []; - - for (var c = 0; c < $children.length; c++) { - var $child = $($children[c]); + return BaseAdapter; + }); - var child = this.item($child); + S2.define('select2/data/select',[ + './base', + '../utils', + 'jquery' + ], function (BaseAdapter, Utils, $) { + function SelectAdapter ($element, options) { + this.$element = $element; + this.options = options; - children.push(child); + SelectAdapter.__super__.constructor.call(this); } - data.children = children; - } + Utils.Extend(SelectAdapter, BaseAdapter); - data = this._normalizeItem(data); - data.element = $option[0]; + SelectAdapter.prototype.current = function (callback) { + var data = []; + var self = this; - $.data($option[0], 'data', data); + this.$element.find(':selected').each(function () { + var $option = $(this); - return data; - }; + var option = self.item($option); - SelectAdapter.prototype._normalizeItem = function (item) { - if (!$.isPlainObject(item)) { - item = { - id: item, - text: item + data.push(option); + }); + + callback(data); }; - } - item = $.extend({}, { - text: '' - }, item); + SelectAdapter.prototype.select = function (data) { + var self = this; - var defaults = { - selected: false, - disabled: false - }; + data.selected = true; - if (item.id != null) { - item.id = item.id.toString(); - } + // If data.element is a DOM node, use it instead + if ($(data.element).is('option')) { + data.element.selected = true; - if (item.text != null) { - item.text = item.text.toString(); - } + this.$element.trigger('change'); - if (item._resultId == null && item.id) { - item._resultId = this.generateResultId(this.container, item); - } + return; + } - return $.extend({}, defaults, item); - }; + if (this.$element.prop('multiple')) { + this.current(function (currentData) { + var val = []; - SelectAdapter.prototype.matches = function (params, data) { - var matcher = this.options.get('matcher'); + data = [data]; + data.push.apply(data, currentData); - return matcher(params, data); - }; + for (var d = 0; d < data.length; d++) { + var id = data[d].id; - return SelectAdapter; -}); + if ($.inArray(id, val) === -1) { + val.push(id); + } + } -S2.define('select2/data/array',[ - './select', - '../utils', - 'jquery' -], function (SelectAdapter, Utils, $) { - function ArrayAdapter ($element, options) { - var data = options.get('data') || []; + self.$element.val(val); + self.$element.trigger('change'); + }); + } else { + var val = data.id; - ArrayAdapter.__super__.constructor.call(this, $element, options); + this.$element.val(val); + this.$element.trigger('change'); + } + }; - this.addOptions(this.convertToOptions(data)); - } + SelectAdapter.prototype.unselect = function (data) { + var self = this; - Utils.Extend(ArrayAdapter, SelectAdapter); + if (!this.$element.prop('multiple')) { + return; + } - ArrayAdapter.prototype.select = function (data) { - var $option = this.$element.find('option').filter(function (i, elm) { - return elm.value == data.id.toString(); - }); + data.selected = false; - if ($option.length === 0) { - $option = this.option(data); + if ($(data.element).is('option')) { + data.element.selected = false; - this.addOptions($option); - } + this.$element.trigger('change'); + + return; + } - ArrayAdapter.__super__.select.call(this, data); - }; + this.current(function (currentData) { + var val = []; - ArrayAdapter.prototype.convertToOptions = function (data) { - var self = this; + for (var d = 0; d < currentData.length; d++) { + var id = currentData[d].id; - var $existing = this.$element.find('option'); - var existingIds = $existing.map(function () { - return self.item($(this)).id; - }).get(); + if (id !== data.id && $.inArray(id, val) === -1) { + val.push(id); + } + } - var $options = []; + self.$element.val(val); - // Filter out all items except for the one passed in the argument - function onlyItem (item) { - return function () { - return $(this).val() == item.id; + self.$element.trigger('change'); + }); }; - } - for (var d = 0; d < data.length; d++) { - var item = this._normalizeItem(data[d]); + SelectAdapter.prototype.bind = function (container, $container) { + var self = this; - // Skip items which were pre-loaded, only merge the data - if ($.inArray(item.id, existingIds) >= 0) { - var $existingOption = $existing.filter(onlyItem(item)); + this.container = container; - var existingData = this.item($existingOption); - var newData = $.extend(true, {}, item, existingData); + container.on('select', function (params) { + self.select(params.data); + }); - var $newOption = this.option(newData); + container.on('unselect', function (params) { + self.unselect(params.data); + }); + }; - $existingOption.replaceWith($newOption); + 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'); + }); + }; - continue; - } + SelectAdapter.prototype.query = function (params, callback) { + var data = []; + var self = this; - var $option = this.option(item); + var $options = this.$element.children(); - if (item.children) { - var $children = this.convertToOptions(item.children); + $options.each(function () { + var $option = $(this); - Utils.appendMany($option, $children); - } + if (!$option.is('option') && !$option.is('optgroup')) { + return; + } - $options.push($option); - } + var option = self.item($option); - return $options; - }; + var matches = self.matches(params, option); - return ArrayAdapter; -}); + if (matches !== null) { + data.push(matches); + } + }); -S2.define('select2/data/ajax',[ - './array', - '../utils', - 'jquery' -], function (ArrayAdapter, Utils, $) { - function AjaxAdapter ($element, options) { - this.ajaxOptions = this._applyDefaults(options.get('ajax')); + callback({ + results: data + }); + }; - if (this.ajaxOptions.processResults != null) { - this.processResults = this.ajaxOptions.processResults; - } + SelectAdapter.prototype.addOptions = function ($options) { + Utils.appendMany(this.$element, $options); + }; - AjaxAdapter.__super__.constructor.call(this, $element, options); - } + SelectAdapter.prototype.option = function (data) { + var option; - Utils.Extend(AjaxAdapter, ArrayAdapter); + if (data.children) { + option = document.createElement('optgroup'); + option.label = data.text; + } else { + option = document.createElement('option'); - AjaxAdapter.prototype._applyDefaults = function (options) { - var defaults = { - data: function (params) { - return $.extend({}, params, { - q: params.term - }); - }, - transport: function (params, success, failure) { - var $request = $.ajax(params); + if (option.textContent !== undefined) { + option.textContent = data.text; + } else { + option.innerText = data.text; + } + } - $request.then(success); - $request.fail(failure); + if (data.id !== undefined) { + option.value = data.id; + } - return $request; - } - }; + if (data.disabled) { + option.disabled = true; + } - return $.extend({}, defaults, options, true); - }; + if (data.selected) { + option.selected = true; + } - AjaxAdapter.prototype.processResults = function (results) { - return results; - }; + if (data.title) { + option.title = data.title; + } - AjaxAdapter.prototype.query = function (params, callback) { - var matches = []; - var self = this; + var $option = $(option); - if (this._request != null) { - // JSONP requests cannot always be aborted - if ($.isFunction(this._request.abort)) { - this._request.abort(); - } + var normalizedData = this._normalizeItem(data); + normalizedData.element = option; - this._request = null; - } + // Override the option's data with the combined data + $.data(option, 'data', normalizedData); - var options = $.extend({ - type: 'GET' - }, this.ajaxOptions); + return $option; + }; - if (typeof options.url === 'function') { - options.url = options.url.call(this.$element, params); - } + SelectAdapter.prototype.item = function ($option) { + var data = {}; - if (typeof options.data === 'function') { - options.data = options.data.call(this.$element, params); - } + data = $.data($option[0], 'data'); - function request () { - var $request = options.transport(options, function (data) { - var results = self.processResults(data, params); + if (data != null) { + return data; + } - if (self.options.get('debug') && window.console && console.error) { - // Check to make sure that the response included a `results` key. - if (!results || !results.results || !$.isArray(results.results)) { - console.error( - 'Select2: The AJAX results did not return an array in the ' + - '`results` key of the response.' - ); + if ($option.is('option')) { + data = { + id: $option.val(), + text: $option.text(), + disabled: $option.prop('disabled'), + selected: $option.prop('selected'), + title: $option.prop('title') + }; + } else if ($option.is('optgroup')) { + data = { + text: $option.prop('label'), + children: [], + title: $option.prop('title') + }; + + var $children = $option.children('option'); + var children = []; + + for (var c = 0; c < $children.length; c++) { + var $child = $($children[c]); + + var child = this.item($child); + + children.push(child); } - } - callback(results); - self.container.focusOnActiveElement(); - }, function () { - // Attempt to detect if a request was aborted - // Only works if the transport exposes a status property - if ($request.status && $request.status === '0') { - return; + data.children = children; } - self.trigger('results:message', { - message: 'errorLoading' - }); - }); + data = this._normalizeItem(data); + data.element = $option[0]; - self._request = $request; - } + $.data($option[0], 'data', data); - if (this.ajaxOptions.delay && params.term != null) { - if (this._queryTimeout) { - window.clearTimeout(this._queryTimeout); - } + return data; + }; - this._queryTimeout = window.setTimeout(request, this.ajaxOptions.delay); - } else { - request(); - } - }; + SelectAdapter.prototype._normalizeItem = function (item) { + if (!$.isPlainObject(item)) { + item = { + id: item, + text: item + }; + } - return AjaxAdapter; -}); + item = $.extend({}, { + text: '' + }, item); -S2.define('select2/data/tags',[ - 'jquery' -], function ($) { - function Tags (decorated, $element, options) { - var tags = options.get('tags'); + var defaults = { + selected: false, + disabled: false + }; - var createTag = options.get('createTag'); + if (item.id != null) { + item.id = item.id.toString(); + } - if (createTag !== undefined) { - this.createTag = createTag; - } + if (item.text != null) { + item.text = item.text.toString(); + } - var insertTag = options.get('insertTag'); + if (item._resultId == null && item.id) { + item._resultId = this.generateResultId(this.container, item); + } - if (insertTag !== undefined) { - this.insertTag = insertTag; - } + return $.extend({}, defaults, item); + }; - decorated.call(this, $element, options); + SelectAdapter.prototype.matches = function (params, data) { + var matcher = this.options.get('matcher'); - if ($.isArray(tags)) { - for (var t = 0; t < tags.length; t++) { - var tag = tags[t]; - var item = this._normalizeItem(tag); + return matcher(params, data); + }; - var $option = this.option(item); + return SelectAdapter; + }); - this.$element.append($option); - } - } - } + S2.define('select2/data/array',[ + './select', + '../utils', + 'jquery' + ], function (SelectAdapter, Utils, $) { + function ArrayAdapter ($element, options) { + var data = options.get('data') || []; - Tags.prototype.query = function (decorated, params, callback) { - var self = this; + ArrayAdapter.__super__.constructor.call(this, $element, options); - this._removeOldTags(); + this.addOptions(this.convertToOptions(data)); + } - if (params.term == null || params.page != null) { - decorated.call(this, params, callback); - return; - } + Utils.Extend(ArrayAdapter, SelectAdapter); - function wrapper (obj, child) { - var data = obj.results; + ArrayAdapter.prototype.select = function (data) { + var $option = this.$element.find('option').filter(function (i, elm) { + return elm.value == data.id.toString(); + }); - for (var i = 0; i < data.length; i++) { - var option = data[i]; + if ($option.length === 0) { + $option = this.option(data); - var checkChildren = ( - option.children != null && - !wrapper({ - results: option.children - }, true) - ); + this.addOptions($option); + } - var optionText = (option.text || '').toUpperCase(); - var paramsTerm = (params.term || '').toUpperCase(); + ArrayAdapter.__super__.select.call(this, data); + }; - var checkText = optionText === paramsTerm; + ArrayAdapter.prototype.convertToOptions = function (data) { + var self = this; - if (checkText || checkChildren) { - if (child) { - return false; - } + var $existing = this.$element.find('option'); + var existingIds = $existing.map(function () { + return self.item($(this)).id; + }).get(); - obj.data = data; - callback(obj); + var $options = []; - return; + // Filter out all items except for the one passed in the argument + function onlyItem (item) { + return function () { + return $(this).val() == item.id; + }; } - } - if (child) { - return true; - } + for (var d = 0; d < data.length; d++) { + var item = this._normalizeItem(data[d]); - var tag = self.createTag(params); + // Skip items which were pre-loaded, only merge the data + if ($.inArray(item.id, existingIds) >= 0) { + var $existingOption = $existing.filter(onlyItem(item)); - if (tag != null) { - var $option = self.option(tag); - $option.attr('data-select2-tag', true); + var existingData = this.item($existingOption); + var newData = $.extend(true, {}, item, existingData); - self.addOptions([$option]); + var $newOption = this.option(newData); - self.insertTag(data, tag); - } + $existingOption.replaceWith($newOption); - obj.results = data; + continue; + } - callback(obj); - } + var $option = this.option(item); - decorated.call(this, params, wrapper); - }; + if (item.children) { + var $children = this.convertToOptions(item.children); - Tags.prototype.createTag = function (decorated, params) { - var term = $.trim(params.term); + Utils.appendMany($option, $children); + } - if (term === '') { - return null; - } + $options.push($option); + } - return { - id: term, - text: term - }; - }; + return $options; + }; - Tags.prototype.insertTag = function (_, data, tag) { - data.unshift(tag); - }; + return ArrayAdapter; + }); - Tags.prototype._removeOldTags = function (_) { - var tag = this._lastTag; + S2.define('select2/data/ajax',[ + './array', + '../utils', + 'jquery' + ], function (ArrayAdapter, Utils, $) { + function AjaxAdapter ($element, options) { + this.ajaxOptions = this._applyDefaults(options.get('ajax')); - var $options = this.$element.find('option[data-select2-tag]'); + if (this.ajaxOptions.processResults != null) { + this.processResults = this.ajaxOptions.processResults; + } - $options.each(function () { - if (this.selected) { - return; + AjaxAdapter.__super__.constructor.call(this, $element, options); } - $(this).remove(); - }); - }; + Utils.Extend(AjaxAdapter, ArrayAdapter); - return Tags; -}); + AjaxAdapter.prototype._applyDefaults = function (options) { + var defaults = { + data: function (params) { + return $.extend({}, params, { + q: params.term + }); + }, + transport: function (params, success, failure) { + var $request = $.ajax(params); -S2.define('select2/data/tokenizer',[ - 'jquery' -], function ($) { - function Tokenizer (decorated, $element, options) { - var tokenizer = options.get('tokenizer'); + $request.then(success); + $request.fail(failure); - if (tokenizer !== undefined) { - this.tokenizer = tokenizer; - } + return $request; + } + }; - decorated.call(this, $element, options); - } + return $.extend({}, defaults, options, true); + }; - Tokenizer.prototype.bind = function (decorated, container, $container) { - decorated.call(this, container, $container); + AjaxAdapter.prototype.processResults = function (results) { + return results; + }; - this.$search = container.dropdown.$search || container.selection.$search || - $container.find('.select2-search__field'); - }; + AjaxAdapter.prototype.query = function (params, callback) { + var matches = []; + var self = this; - Tokenizer.prototype.query = function (decorated, params, callback) { - var self = this; + if (this._request != null) { + // JSONP requests cannot always be aborted + if ($.isFunction(this._request.abort)) { + this._request.abort(); + } - function createAndSelect (data) { - // Normalize the data object so we can use it for checks - var item = self._normalizeItem(data); + this._request = null; + } - // 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; - }); + var options = $.extend({ + type: 'GET' + }, this.ajaxOptions); - // 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); + if (typeof options.url === 'function') { + options.url = options.url.call(this.$element, params); + } - self._removeOldTags(); - self.addOptions([$option]); - } + if (typeof options.data === 'function') { + options.data = options.data.call(this.$element, params); + } - // Select the item, now that we know there is an option for it - select(item); - } + function request () { + var $request = options.transport(options, function (data) { + var results = self.processResults(data, params); + + if (self.options.get('debug') && window.console && console.error) { + // Check to make sure that the response included a `results` key. + if (!results || !results.results || !$.isArray(results.results)) { + console.error( + 'Select2: The AJAX results did not return an array in the ' + + '`results` key of the response.' + ); + } + } - function select (data) { - self.trigger('select', { - data: data - }); - } + callback(results); + self.container.focusOnActiveElement(); + }, function () { + // Attempt to detect if a request was aborted + // Only works if the transport exposes a status property + if ($request.status && $request.status === '0') { + return; + } - params.term = params.term || ''; + self.trigger('results:message', { + message: 'errorLoading' + }); + }); - var tokenData = this.tokenizer(params, this.options, createAndSelect); + self._request = $request; + } - if (tokenData.term !== params.term) { - // Replace the search term if we have the search box - if (this.$search.length) { - this.$search.val(tokenData.term); - this.$search.focus(); - } + if (this.ajaxOptions.delay && params.term != null) { + if (this._queryTimeout) { + window.clearTimeout(this._queryTimeout); + } - params.term = tokenData.term; - } + this._queryTimeout = window.setTimeout(request, this.ajaxOptions.delay); + } else { + request(); + } + }; - decorated.call(this, params, callback); - }; + return AjaxAdapter; + }); - Tokenizer.prototype.tokenizer = function (_, params, options, callback) { - var separators = options.get('tokenSeparators') || []; - var term = params.term; - var i = 0; + S2.define('select2/data/tags',[ + 'jquery' + ], function ($) { + function Tags (decorated, $element, options) { + var tags = options.get('tags'); - var createTag = this.createTag || function (params) { - return { - id: params.term, - text: params.term - }; - }; + var createTag = options.get('createTag'); - while (i < term.length) { - var termChar = term[i]; + if (createTag !== undefined) { + this.createTag = createTag; + } - if ($.inArray(termChar, separators) === -1) { - i++; + var insertTag = options.get('insertTag'); - continue; - } + if (insertTag !== undefined) { + this.insertTag = insertTag; + } - var part = term.substr(0, i); - var partParams = $.extend({}, params, { - term: part - }); + decorated.call(this, $element, options); - var data = createTag(partParams); + if ($.isArray(tags)) { + for (var t = 0; t < tags.length; t++) { + var tag = tags[t]; + var item = this._normalizeItem(tag); - if (data == null) { - i++; - continue; + var $option = this.option(item); + + this.$element.append($option); + } + } } - callback(data); + Tags.prototype.query = function (decorated, params, callback) { + var self = this; - // Reset the term to not include the tokenized portion - term = term.substr(i + 1) || ''; - i = 0; - } + this._removeOldTags(); - return { - term: term - }; - }; + if (params.term == null || params.page != null) { + decorated.call(this, params, callback); + return; + } - return Tokenizer; -}); + function wrapper (obj, child) { + var data = obj.results; -S2.define('select2/data/minimumInputLength',[ + for (var i = 0; i < data.length; i++) { + var option = data[i]; -], function () { - function MinimumInputLength (decorated, $e, options) { - this.minimumInputLength = options.get('minimumInputLength'); + var checkChildren = ( + option.children != null && + !wrapper({ + results: option.children + }, true) + ); - decorated.call(this, $e, options); - } + var optionText = (option.text || '').toUpperCase(); + var paramsTerm = (params.term || '').toUpperCase(); - MinimumInputLength.prototype.query = function (decorated, params, callback) { - params.term = params.term || ''; + var checkText = optionText === paramsTerm; - if (params.term.length < this.minimumInputLength) { - this.trigger('results:message', { - message: 'inputTooShort', - args: { - minimum: this.minimumInputLength, - input: params.term, - params: params - } - }); + if (checkText || checkChildren) { + if (child) { + return false; + } - return; - } + obj.data = data; + callback(obj); - decorated.call(this, params, callback); - }; + return; + } + } - return MinimumInputLength; -}); + if (child) { + return true; + } -S2.define('select2/data/maximumInputLength',[ + var tag = self.createTag(params); -], function () { - function MaximumInputLength (decorated, $e, options) { - this.maximumInputLength = options.get('maximumInputLength'); + if (tag != null) { + var $option = self.option(tag); + $option.attr('data-select2-tag', true); - decorated.call(this, $e, options); - } + self.addOptions([$option]); - MaximumInputLength.prototype.query = function (decorated, params, callback) { - params.term = params.term || ''; + self.insertTag(data, tag); + } - if (this.maximumInputLength > 0 && - params.term.length > this.maximumInputLength) { - this.trigger('results:message', { - message: 'inputTooLong', - args: { - maximum: this.maximumInputLength, - input: params.term, - params: params - } - }); + obj.results = data; - return; - } + callback(obj); + } - decorated.call(this, params, callback); - }; + decorated.call(this, params, wrapper); + }; - return MaximumInputLength; -}); + Tags.prototype.createTag = function (decorated, params) { + var term = $.trim(params.term); -S2.define('select2/data/maximumSelectionLength',[ + if (term === '') { + return null; + } -], function (){ - function MaximumSelectionLength (decorated, $e, options) { - this.maximumSelectionLength = options.get('maximumSelectionLength'); + return { + id: term, + text: term + }; + }; - decorated.call(this, $e, options); - } + Tags.prototype.insertTag = function (_, data, tag) { + data.unshift(tag); + }; - MaximumSelectionLength.prototype.query = - function (decorated, params, callback) { - var self = this; + Tags.prototype._removeOldTags = function (_) { + var tag = this._lastTag; - this.current(function (currentData) { - var count = currentData != null ? currentData.length : 0; - if (self.maximumSelectionLength > 0 && - count >= self.maximumSelectionLength) { - self.trigger('results:message', { - message: 'maximumSelected', - args: { - maximum: self.maximumSelectionLength - } - }); - return; - } - decorated.call(self, params, callback); - }); - }; + var $options = this.$element.find('option[data-select2-tag]'); - return MaximumSelectionLength; -}); + $options.each(function () { + if (this.selected) { + return; + } -S2.define('select2/dropdown',[ - 'jquery', - './utils' -], function ($, Utils) { - function Dropdown ($element, options) { - this.$element = $element; - this.options = options; + $(this).remove(); + }); + }; - Dropdown.__super__.constructor.call(this); - } + return Tags; + }); - Utils.Extend(Dropdown, Utils.Observable); + S2.define('select2/data/tokenizer',[ + 'jquery' + ], function ($) { + function Tokenizer (decorated, $element, options) { + var tokenizer = options.get('tokenizer'); - Dropdown.prototype.render = function () { - var $dropdown = $( - '' + - '' + - '' - ); + if (tokenizer !== undefined) { + this.tokenizer = tokenizer; + } - $dropdown.attr('dir', this.options.get('dir')); + decorated.call(this, $element, options); + } - this.$dropdown = $dropdown; + Tokenizer.prototype.bind = function (decorated, container, $container) { + decorated.call(this, container, $container); - return $dropdown; - }; + this.$search = container.dropdown.$search || container.selection.$search || + $container.find('.select2-search__field'); + }; - Dropdown.prototype.bind = function () { - // Should be implemented in subclasses - }; + Tokenizer.prototype.query = function (decorated, params, callback) { + var self = this; - Dropdown.prototype.position = function ($dropdown, $container) { - // Should be implmented in subclasses - }; + function createAndSelect (data) { + // Normalize the data object so we can use it for checks + var item = self._normalizeItem(data); - Dropdown.prototype.destroy = function () { - // Remove the dropdown from the DOM - this.$dropdown.remove(); - }; + // 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; + }); - return Dropdown; -}); + // 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); -S2.define('select2/dropdown/search',[ - 'jquery', - '../utils' -], function ($, Utils) { - function Search () { } + self._removeOldTags(); + self.addOptions([$option]); + } - Search.prototype.render = function (decorated) { - var $rendered = decorated.call(this); + // Select the item, now that we know there is an option for it + select(item); + } - var $search = $( - '' + - '' + - '' - ); + function select (data) { + self.trigger('select', { + data: data + }); + } - this.$searchContainer = $search; - this.$search = $search.find('input'); + params.term = params.term || ''; - $rendered.prepend($search); + var tokenData = this.tokenizer(params, this.options, createAndSelect); - return $rendered; - }; + if (tokenData.term !== params.term) { + // Replace the search term if we have the search box + if (this.$search.length) { + this.$search.val(tokenData.term); + this.$search.focus(); + } - Search.prototype.bind = function (decorated, container, $container) { - var self = this; - var resultsId = container.id + '-results'; + params.term = tokenData.term; + } - decorated.call(this, container, $container); + decorated.call(this, params, callback); + }; - this.$search.on('keydown', function (evt) { - self.trigger('keypress', evt); + Tokenizer.prototype.tokenizer = function (_, params, options, callback) { + var separators = options.get('tokenSeparators') || []; + var term = params.term; + var i = 0; - self._keyUpPrevented = evt.isDefaultPrevented(); - }); + var createTag = this.createTag || function (params) { + return { + id: params.term, + text: params.term + }; + }; - // Workaround for browsers which do not support the `input` event - // This will prevent double-triggering of events for browsers which support - // both the `keyup` and `input` events. - this.$search.on('input', function (evt) { - // Unbind the duplicated `keyup` event - $(this).off('keyup'); - }); + while (i < term.length) { + var termChar = term[i]; - this.$search.on('keyup input', function (evt) { - self.handleSearch(evt); - }); + if ($.inArray(termChar, separators) === -1) { + i++; - container.on('open', function () { - self.$search.attr('tabindex', 0); - self.$search.attr('aria-owns', resultsId); - self.$search.focus(); + continue; + } - window.setTimeout(function () { - self.$search.focus(); - }, 0); - }); + var part = term.substr(0, i); + var partParams = $.extend({}, params, { + term: part + }); - container.on('close', function () { - self.$search.attr('tabindex', -1); - self.$search.removeAttr('aria-activedescendant'); - self.$search.removeAttr('aria-owns'); - self.$search.val(''); - }); + var data = createTag(partParams); - container.on('focus', function () { - if (container.isOpen()) { - self.$search.focus(); - } - }); + if (data == null) { + i++; + continue; + } - container.on('results:all', function (params) { - if (params.query.term == null || params.query.term === '') { - var showSearch = self.showSearch(params); + callback(data); - if (showSearch) { - self.$searchContainer.removeClass('select2-search--hide'); - } else { - self.$searchContainer.addClass('select2-search--hide'); + // Reset the term to not include the tokenized portion + term = term.substr(i + 1) || ''; + i = 0; } - } - }); - - container.on('results:focus', function (params) { - self.$search.attr('aria-activedescendant', params.data._resultId); - }); - }; - - Search.prototype.handleSearch = function (evt) { - if (!this._keyUpPrevented) { - var input = this.$search.val(); - - this.trigger('query', { - term: input - }); - } - this._keyUpPrevented = false; - }; + return { + term: term + }; + }; - Search.prototype.showSearch = function (_, params) { - return true; - }; + return Tokenizer; + }); - return Search; -}); + S2.define('select2/data/minimumInputLength',[ -S2.define('select2/dropdown/hidePlaceholder',[ + ], function () { + function MinimumInputLength (decorated, $e, options) { + this.minimumInputLength = options.get('minimumInputLength'); -], function () { - function HidePlaceholder (decorated, $element, options, dataAdapter) { - this.placeholder = this.normalizePlaceholder(options.get('placeholder')); + decorated.call(this, $e, options); + } - decorated.call(this, $element, options, dataAdapter); - } + MinimumInputLength.prototype.query = function (decorated, params, callback) { + params.term = params.term || ''; - HidePlaceholder.prototype.append = function (decorated, data) { - data.results = this.removePlaceholder(data.results); + if (params.term.length < this.minimumInputLength) { + this.trigger('results:message', { + message: 'inputTooShort', + args: { + minimum: this.minimumInputLength, + input: params.term, + params: params + } + }); - decorated.call(this, data); - }; + return; + } - HidePlaceholder.prototype.normalizePlaceholder = function (_, placeholder) { - if (typeof placeholder === 'string') { - placeholder = { - id: '', - text: placeholder + decorated.call(this, params, callback); }; - } - return placeholder; - }; + return MinimumInputLength; + }); - HidePlaceholder.prototype.removePlaceholder = function (_, data) { - var modifiedData = data.slice(0); + S2.define('select2/data/maximumInputLength',[ - for (var d = data.length - 1; d >= 0; d--) { - var item = data[d]; + ], function () { + function MaximumInputLength (decorated, $e, options) { + this.maximumInputLength = options.get('maximumInputLength'); - if (this.placeholder.id === item.id) { - modifiedData.splice(d, 1); + decorated.call(this, $e, options); } - } - - return modifiedData; - }; - - return HidePlaceholder; -}); -S2.define('select2/dropdown/infiniteScroll',[ - 'jquery' -], function ($) { - function InfiniteScroll (decorated, $element, options, dataAdapter) { - this.lastParams = {}; + MaximumInputLength.prototype.query = function (decorated, params, callback) { + params.term = params.term || ''; - decorated.call(this, $element, options, dataAdapter); + if (this.maximumInputLength > 0 && + params.term.length > this.maximumInputLength) { + this.trigger('results:message', { + message: 'inputTooLong', + args: { + maximum: this.maximumInputLength, + input: params.term, + params: params + } + }); - this.$loadingMore = this.createLoadingMore(); - this.loading = false; - } + return; + } - InfiniteScroll.prototype.append = function (decorated, data) { - this.$loadingMore.remove(); - this.loading = false; + decorated.call(this, params, callback); + }; - decorated.call(this, data); + return MaximumInputLength; + }); - if (this.showLoadingMore(data)) { - this.$results.append(this.$loadingMore); - } - }; + S2.define('select2/data/maximumSelectionLength',[ - InfiniteScroll.prototype.bind = function (decorated, container, $container) { - var self = this; + ], function (){ + function MaximumSelectionLength (decorated, $e, options) { + this.maximumSelectionLength = options.get('maximumSelectionLength'); - decorated.call(this, container, $container); + decorated.call(this, $e, options); + } - container.on('query', function (params) { - self.lastParams = params; - self.loading = true; - }); + MaximumSelectionLength.prototype.query = + function (decorated, params, callback) { + var self = this; + + this.current(function (currentData) { + var count = currentData != null ? currentData.length : 0; + if (self.maximumSelectionLength > 0 && + count >= self.maximumSelectionLength) { + self.trigger('results:message', { + message: 'maximumSelected', + args: { + maximum: self.maximumSelectionLength + } + }); + return; + } + decorated.call(self, params, callback); + }); + }; - container.on('query:append', function (params) { - self.lastParams = params; - self.loading = true; + return MaximumSelectionLength; }); - this.$results.on('scroll', function () { - var isLoadMoreVisible = $.contains( - document.documentElement, - self.$loadingMore[0] - ); + S2.define('select2/dropdown',[ + 'jquery', + './utils' + ], function ($, Utils) { + function Dropdown ($element, options) { + this.$element = $element; + this.options = options; - if (self.loading || !isLoadMoreVisible) { - return; + Dropdown.__super__.constructor.call(this); } - var currentOffset = self.$results.offset().top + - self.$results.outerHeight(false); - var loadingMoreOffset = self.$loadingMore.offset().top + - self.$loadingMore.outerHeight(false); + Utils.Extend(Dropdown, Utils.Observable); - if (currentOffset + 50 >= loadingMoreOffset) { - self.loadMore(); - } - }); - }; + Dropdown.prototype.render = function () { + var $dropdown = $( + '' + + '' + + '' + ); + + $dropdown.attr('dir', this.options.get('dir')); + + this.$dropdown = $dropdown; - InfiniteScroll.prototype.loadMore = function () { - this.loading = true; + return $dropdown; + }; - var params = $.extend({}, {page: 1}, this.lastParams); + Dropdown.prototype.bind = function () { + // Should be implemented in subclasses + }; - params.page++; + Dropdown.prototype.position = function ($dropdown, $container) { + // Should be implmented in subclasses + }; - this.trigger('query:append', params); - }; + Dropdown.prototype.destroy = function () { + // Remove the dropdown from the DOM + this.$dropdown.remove(); + }; - InfiniteScroll.prototype.showLoadingMore = function (_, data) { - return data.pagination && data.pagination.more; - }; + return Dropdown; + }); - InfiniteScroll.prototype.createLoadingMore = function () { - var $option = $( - '
  • ' - ); + S2.define('select2/dropdown/search',[ + 'jquery', + '../utils' + ], function ($, Utils) { + function Search () { } + + Search.prototype.render = function (decorated) { + var $rendered = decorated.call(this); + + var $search = $( + '' + + '' + + '' + ); - var message = this.options.get('translations').get('loadingMore'); + this.$searchContainer = $search; + this.$search = $search.find('input'); - $option.html(message(this.lastParams)); + $rendered.prepend($search); - return $option; - }; + return $rendered; + }; - return InfiniteScroll; -}); + Search.prototype.bind = function (decorated, container, $container) { + var self = this; + var resultsId = container.id + '-results'; -S2.define('select2/dropdown/attachBody',[ - 'jquery', - '../utils' -], function ($, Utils) { - function AttachBody (decorated, $element, options) { - this.$dropdownParent = options.get('dropdownParent') || $(document.body); + decorated.call(this, container, $container); - decorated.call(this, $element, options); - } + this.$search.on('keydown', function (evt) { + self.trigger('keypress', evt); - AttachBody.prototype.bind = function (decorated, container, $container) { - var self = this; + self._keyUpPrevented = evt.isDefaultPrevented(); + }); - var setupResultsEvents = false; + // Workaround for browsers which do not support the `input` event + // This will prevent double-triggering of events for browsers which support + // both the `keyup` and `input` events. + this.$search.on('input', function (evt) { + // Unbind the duplicated `keyup` event + $(this).off('keyup'); + }); - decorated.call(this, container, $container); + this.$search.on('keyup input', function (evt) { + self.handleSearch(evt); + }); - container.on('open', function () { - self._showDropdown(); - self._attachPositioningHandler(container); + container.on('open', function () { + self.$search.attr('tabindex', 0); + self.$search.attr('aria-owns', resultsId); + self.$search.focus(); - if (!setupResultsEvents) { - setupResultsEvents = true; + window.setTimeout(function () { + self.$search.focus(); + }, 0); + }); - container.on('results:all', function () { - self._positionDropdown(); - self._resizeDropdown(); + container.on('close', function () { + self.$search.attr('tabindex', -1); + self.$search.removeAttr('aria-activedescendant'); + self.$search.removeAttr('aria-owns'); + self.$search.val(''); }); - container.on('results:append', function () { - self._positionDropdown(); - self._resizeDropdown(); + container.on('focus', function () { + if (!container.isOpen()) { + self.$search.focus(); + } }); - } - }); - container.on('close', function () { - self._hideDropdown(); - self._detachPositioningHandler(container); - }); + container.on('results:all', function (params) { + if (params.query.term == null || params.query.term === '') { + var showSearch = self.showSearch(params); - this.$dropdownContainer.on('mousedown', function (evt) { - evt.stopPropagation(); - }); - }; + if (showSearch) { + self.$searchContainer.removeClass('select2-search--hide'); + } else { + self.$searchContainer.addClass('select2-search--hide'); + } + } + }); + + container.on('results:focus', function (params) { + self.$search.attr('aria-activedescendant', params.data._resultId); + }); + }; - AttachBody.prototype.destroy = function (decorated) { - decorated.call(this); + Search.prototype.handleSearch = function (evt) { + if (!this._keyUpPrevented) { + var input = this.$search.val(); - this.$dropdownContainer.remove(); - }; + this.trigger('query', { + term: input + }); + } - AttachBody.prototype.position = function (decorated, $dropdown, $container) { - // Clone all of the container classes - $dropdown.attr('class', $container.attr('class')); + this._keyUpPrevented = false; + }; - $dropdown.removeClass('select2'); - $dropdown.addClass('select2-container--open'); + Search.prototype.showSearch = function (_, params) { + return true; + }; - $dropdown.css({ - position: 'absolute', - top: -999999 + return Search; }); - this.$container = $container; - }; + S2.define('select2/dropdown/hidePlaceholder',[ - AttachBody.prototype.render = function (decorated) { - var $container = $(''); + ], function () { + function HidePlaceholder (decorated, $element, options, dataAdapter) { + this.placeholder = this.normalizePlaceholder(options.get('placeholder')); - var $dropdown = decorated.call(this); - $container.append($dropdown); + decorated.call(this, $element, options, dataAdapter); + } - this.$dropdownContainer = $container; + HidePlaceholder.prototype.append = function (decorated, data) { + data.results = this.removePlaceholder(data.results); - return $container; - }; + decorated.call(this, data); + }; - AttachBody.prototype._hideDropdown = function (decorated) { - this.$dropdownContainer.detach(); - }; + HidePlaceholder.prototype.normalizePlaceholder = function (_, placeholder) { + if (typeof placeholder === 'string') { + placeholder = { + id: '', + text: placeholder + }; + } - AttachBody.prototype._attachPositioningHandler = - function (decorated, container) { - var self = this; + return placeholder; + }; - var scrollEvent = 'scroll.select2.' + container.id; - var resizeEvent = 'resize.select2.' + container.id; - var orientationEvent = 'orientationchange.select2.' + container.id; + HidePlaceholder.prototype.removePlaceholder = function (_, data) { + var modifiedData = data.slice(0); - var $watchers = this.$container.parents().filter(Utils.hasScroll); - $watchers.each(function () { - $(this).data('select2-scroll-position', { - x: $(this).scrollLeft(), - y: $(this).scrollTop() - }); - }); + for (var d = data.length - 1; d >= 0; d--) { + var item = data[d]; - $watchers.on(scrollEvent, function (ev) { - var position = $(this).data('select2-scroll-position'); - $(this).scrollTop(position.y); - }); + if (this.placeholder.id === item.id) { + modifiedData.splice(d, 1); + } + } + + return modifiedData; + }; - $(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent, - function (e) { - self._positionDropdown(); - self._resizeDropdown(); + return HidePlaceholder; }); - }; - AttachBody.prototype._detachPositioningHandler = - function (decorated, container) { - var scrollEvent = 'scroll.select2.' + container.id; - var resizeEvent = 'resize.select2.' + container.id; - var orientationEvent = 'orientationchange.select2.' + container.id; + S2.define('select2/dropdown/infiniteScroll',[ + 'jquery' + ], function ($) { + function InfiniteScroll (decorated, $element, options, dataAdapter) { + this.lastParams = {}; - var $watchers = this.$container.parents().filter(Utils.hasScroll); - $watchers.off(scrollEvent); + decorated.call(this, $element, options, dataAdapter); - $(window).off(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent); - }; + this.$loadingMore = this.createLoadingMore(); + this.loading = false; + } - AttachBody.prototype._positionDropdown = function () { - var $window = $(window); + InfiniteScroll.prototype.append = function (decorated, data) { + this.$loadingMore.remove(); + this.loading = false; - var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above'); - var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below'); + decorated.call(this, data); - var newDirection = null; + if (this.showLoadingMore(data)) { + this.$results.append(this.$loadingMore); + } + }; - var offset = this.$container.offset(); + InfiniteScroll.prototype.bind = function (decorated, container, $container) { + var self = this; - offset.bottom = offset.top + this.$container.outerHeight(false); + decorated.call(this, container, $container); - var container = { - height: this.$container.outerHeight(false) - }; + container.on('query', function (params) { + self.lastParams = params; + self.loading = true; + }); - container.top = offset.top; - container.bottom = offset.top + container.height; + container.on('query:append', function (params) { + self.lastParams = params; + self.loading = true; + }); - var dropdown = { - height: this.$dropdown.outerHeight(false) - }; + this.$results.on('scroll', function () { + var isLoadMoreVisible = $.contains( + document.documentElement, + self.$loadingMore[0] + ); - var viewport = { - top: $window.scrollTop(), - bottom: $window.scrollTop() + $window.height() - }; + if (self.loading || !isLoadMoreVisible) { + return; + } - var enoughRoomAbove = viewport.top < (offset.top - dropdown.height); - var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height); + var currentOffset = self.$results.offset().top + + self.$results.outerHeight(false); + var loadingMoreOffset = self.$loadingMore.offset().top + + self.$loadingMore.outerHeight(false); - var css = { - left: offset.left, - top: container.bottom - }; + if (currentOffset + 50 >= loadingMoreOffset) { + self.loadMore(); + } + }); + }; - // Determine what the parent element is to use for calciulating the offset - var $offsetParent = this.$dropdownParent; + InfiniteScroll.prototype.loadMore = function () { + this.loading = true; - // For statically positoned elements, we need to get the element - // that is determining the offset - if ($offsetParent.css('position') === 'static') { - $offsetParent = $offsetParent.offsetParent(); - } + var params = $.extend({}, {page: 1}, this.lastParams); - var parentOffset = $offsetParent.offset(); + params.page++; - css.top -= parentOffset.top; - css.left -= parentOffset.left; + this.trigger('query:append', params); + }; - if (!isCurrentlyAbove && !isCurrentlyBelow) { - newDirection = 'below'; - } + InfiniteScroll.prototype.showLoadingMore = function (_, data) { + return data.pagination && data.pagination.more; + }; - if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) { - newDirection = 'above'; - } else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) { - newDirection = 'below'; - } + InfiniteScroll.prototype.createLoadingMore = function () { + var $option = $( + '
  • ' + ); - if (newDirection == 'above' || - (isCurrentlyAbove && newDirection !== 'below')) { - css.top = container.top - parentOffset.top - dropdown.height; - } + var message = this.options.get('translations').get('loadingMore'); - if (newDirection != null) { - this.$dropdown - .removeClass('select2-dropdown--below select2-dropdown--above') - .addClass('select2-dropdown--' + newDirection); - this.$container - .removeClass('select2-container--below select2-container--above') - .addClass('select2-container--' + newDirection); - } + $option.html(message(this.lastParams)); - this.$dropdownContainer.css(css); - }; + return $option; + }; - AttachBody.prototype._resizeDropdown = function () { - var css = { - width: this.$container.outerWidth(false) + 'px' - }; + return InfiniteScroll; + }); - if (this.options.get('dropdownAutoWidth')) { - css.minWidth = css.width; - css.position = 'relative'; - css.width = 'auto'; - } + S2.define('select2/dropdown/attachBody',[ + 'jquery', + '../utils' + ], function ($, Utils) { + function AttachBody (decorated, $element, options) { + this.$dropdownParent = options.get('dropdownParent') || $(document.body); - this.$dropdown.css(css); - }; + decorated.call(this, $element, options); + } - AttachBody.prototype._showDropdown = function (decorated) { - this.$dropdownContainer.appendTo(this.$dropdownParent); + AttachBody.prototype.bind = function (decorated, container, $container) { + var self = this; - this._positionDropdown(); - this._resizeDropdown(); - }; + var setupResultsEvents = false; - return AttachBody; -}); + decorated.call(this, container, $container); -S2.define('select2/dropdown/minimumResultsForSearch',[ + container.on('open', function () { + self._showDropdown(); + self._attachPositioningHandler(container); -], function () { - function countResults (data) { - var count = 0; + if (!setupResultsEvents) { + setupResultsEvents = true; - for (var d = 0; d < data.length; d++) { - var item = data[d]; + container.on('results:all', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); - if (item.children) { - count += countResults(item.children); - } else { - count++; - } - } + container.on('results:append', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + } + }); - return count; - } + container.on('close', function () { + self._hideDropdown(); + self._detachPositioningHandler(container); + }); - function MinimumResultsForSearch (decorated, $element, options, dataAdapter) { - this.minimumResultsForSearch = options.get('minimumResultsForSearch'); + this.$dropdownContainer.on('mousedown', function (evt) { + evt.stopPropagation(); + }); + }; - if (this.minimumResultsForSearch < 0) { - this.minimumResultsForSearch = Infinity; - } + AttachBody.prototype.destroy = function (decorated) { + decorated.call(this); - decorated.call(this, $element, options, dataAdapter); - } + this.$dropdownContainer.remove(); + }; - MinimumResultsForSearch.prototype.showSearch = function (decorated, params) { - if (countResults(params.data.results) < this.minimumResultsForSearch) { - return false; - } + AttachBody.prototype.position = function (decorated, $dropdown, $container) { + // Clone all of the container classes + $dropdown.attr('class', $container.attr('class')); - return decorated.call(this, params); - }; + $dropdown.removeClass('select2'); + $dropdown.addClass('select2-container--open'); - return MinimumResultsForSearch; -}); + $dropdown.css({ + position: 'absolute', + top: -999999 + }); -S2.define('select2/dropdown/selectOnClose',[ + this.$container = $container; + }; -], function () { - function SelectOnClose () { } + AttachBody.prototype.render = function (decorated) { + var $container = $(''); - SelectOnClose.prototype.bind = function (decorated, container, $container) { - var self = this; + var $dropdown = decorated.call(this); + $container.append($dropdown); - decorated.call(this, container, $container); + this.$dropdownContainer = $container; - container.on('close', function (params) { - self._handleSelectOnClose(params); - }); - }; + return $container; + }; - SelectOnClose.prototype._handleSelectOnClose = function (_, params) { - if (params && params.originalSelect2Event != null) { - var event = params.originalSelect2Event; + AttachBody.prototype._hideDropdown = function (decorated) { + this.$dropdownContainer.detach(); + }; - // 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; - } - } + AttachBody.prototype._attachPositioningHandler = + function (decorated, container) { + var self = this; - var $highlightedResults = this.getHighlightedResults(); + var scrollEvent = 'scroll.select2.' + container.id; + var resizeEvent = 'resize.select2.' + container.id; + var orientationEvent = 'orientationchange.select2.' + container.id; - // Only select highlighted results - if ($highlightedResults.length < 1) { - return; - } + var $watchers = this.$container.parents().filter(Utils.hasScroll); + $watchers.each(function () { + $(this).data('select2-scroll-position', { + x: $(this).scrollLeft(), + y: $(this).scrollTop() + }); + }); - var data = $highlightedResults.data('data'); + $watchers.on(scrollEvent, function (ev) { + var position = $(this).data('select2-scroll-position'); + $(this).scrollTop(position.y); + }); - // Don't re-select already selected resulte - if ( - (data.element != null && data.element.selected) || - (data.element == null && data.selected) - ) { - return; - } + $(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent, + function (e) { + self._positionDropdown(); + self._resizeDropdown(); + }); + }; - this.trigger('select', { - data: data - }); - }; + AttachBody.prototype._detachPositioningHandler = + function (decorated, container) { + var scrollEvent = 'scroll.select2.' + container.id; + var resizeEvent = 'resize.select2.' + container.id; + var orientationEvent = 'orientationchange.select2.' + container.id; - return SelectOnClose; -}); + var $watchers = this.$container.parents().filter(Utils.hasScroll); + $watchers.off(scrollEvent); -S2.define('select2/dropdown/closeOnSelect',[ + $(window).off(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent); + }; -], function () { - function CloseOnSelect () { } + AttachBody.prototype._positionDropdown = function () { + var $window = $(window); - CloseOnSelect.prototype.bind = function (decorated, container, $container) { - var self = this; + var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above'); + var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below'); - decorated.call(this, container, $container); + var newDirection = null; - container.on('select', function (evt) { - self._selectTriggered(evt); - }); + var offset = this.$container.offset(); - container.on('unselect', function (evt) { - self._selectTriggered(evt); - }); - }; + offset.bottom = offset.top + this.$container.outerHeight(false); - CloseOnSelect.prototype._selectTriggered = function (_, evt) { - var originalEvent = evt.originalEvent; + var container = { + height: this.$container.outerHeight(false) + }; - // Don't close if the control key is being held - if (originalEvent && originalEvent.ctrlKey) { - return; - } + container.top = offset.top; + container.bottom = offset.top + container.height; - this.trigger('close', { - originalEvent: originalEvent, - originalSelect2Event: evt - }); - }; + var dropdown = { + height: this.$dropdown.outerHeight(false) + }; - return CloseOnSelect; -}); + var viewport = { + top: $window.scrollTop(), + bottom: $window.scrollTop() + $window.height() + }; -S2.define('select2/i18n/en',[],function () { - // English - return { - errorLoading: function () { - return 'The results could not be loaded.'; - }, - inputTooLong: function (args) { - var overChars = args.input.length - args.maximum; + var enoughRoomAbove = viewport.top < (offset.top - dropdown.height); + var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height); - var message = 'Please delete ' + overChars + ' character'; + var css = { + left: offset.left, + top: container.bottom + }; - if (overChars != 1) { - message += 's'; - } + // Determine what the parent element is to use for calciulating the offset + var $offsetParent = this.$dropdownParent; - return message; - }, - inputTooShort: function (args) { - var remainingChars = args.minimum - args.input.length; + // For statically positoned elements, we need to get the element + // that is determining the offset + if ($offsetParent.css('position') === 'static') { + $offsetParent = $offsetParent.offsetParent(); + } - var message = 'Please enter ' + remainingChars + ' or more characters'; + var parentOffset = $offsetParent.offset(); - return message; - }, - loadingMore: function () { - return 'Loading more results…'; - }, - maximumSelected: function (args) { - var message = 'You can only select ' + args.maximum + ' item'; + css.left -= parentOffset.left; - if (args.maximum != 1) { - message += 's'; - } + if (!isCurrentlyAbove && !isCurrentlyBelow) { + newDirection = 'below'; + } - return message; - }, - noResults: function () { - return 'No results found'; - }, - searching: function () { - return 'Searching…'; - } - }; -}); - -S2.define('select2/defaults',[ - 'jquery', - 'require', - - './results', - - './selection/single', - './selection/multiple', - './selection/placeholder', - './selection/allowClear', - './selection/search', - './selection/eventRelay', - - './utils', - './translation', - './diacritics', - - './data/select', - './data/array', - './data/ajax', - './data/tags', - './data/tokenizer', - './data/minimumInputLength', - './data/maximumInputLength', - './data/maximumSelectionLength', - - './dropdown', - './dropdown/search', - './dropdown/hidePlaceholder', - './dropdown/infiniteScroll', - './dropdown/attachBody', - './dropdown/minimumResultsForSearch', - './dropdown/selectOnClose', - './dropdown/closeOnSelect', - - './i18n/en' -], function ($, require, - - ResultsList, - - SingleSelection, MultipleSelection, Placeholder, AllowClear, - SelectionSearch, EventRelay, - - Utils, Translation, DIACRITICS, - - SelectData, ArrayData, AjaxData, Tags, Tokenizer, - MinimumInputLength, MaximumInputLength, MaximumSelectionLength, - - Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll, - AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect, - - EnglishTranslation) { - function Defaults () { - this.reset(); - } + if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) { + newDirection = 'above'; + } else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) { + newDirection = 'below'; + } - Defaults.prototype.apply = function (options) { - options = $.extend(true, {}, this.defaults, options); + if (newDirection == 'above' || + (isCurrentlyAbove && newDirection !== 'below')) { + css.top = container.top - dropdown.height; + } - if (options.dataAdapter == null) { - if (options.ajax != null) { - options.dataAdapter = AjaxData; - } else if (options.data != null) { - options.dataAdapter = ArrayData; - } else { - options.dataAdapter = SelectData; - } + if (newDirection != null) { + this.$dropdown + .removeClass('select2-dropdown--below select2-dropdown--above') + .addClass('select2-dropdown--' + newDirection); + this.$container + .removeClass('select2-container--below select2-container--above') + .addClass('select2-container--' + newDirection); + } - if (options.minimumInputLength > 0) { - options.dataAdapter = Utils.Decorate( - options.dataAdapter, - MinimumInputLength - ); - } + this.$dropdownContainer.css(css); + }; - if (options.maximumInputLength > 0) { - options.dataAdapter = Utils.Decorate( - options.dataAdapter, - MaximumInputLength - ); - } + AttachBody.prototype._resizeDropdown = function () { + var css = { + width: this.$container.outerWidth(false) + 'px' + }; - if (options.maximumSelectionLength > 0) { - options.dataAdapter = Utils.Decorate( - options.dataAdapter, - MaximumSelectionLength - ); - } + if (this.options.get('dropdownAutoWidth')) { + css.minWidth = css.width; + css.position = 'relative'; + css.width = 'auto'; + } - if (options.tags) { - options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags); - } + this.$dropdown.css(css); + }; - if (options.tokenSeparators != null || options.tokenizer != null) { - options.dataAdapter = Utils.Decorate( - options.dataAdapter, - Tokenizer - ); - } + AttachBody.prototype._showDropdown = function (decorated) { + this.$dropdownContainer.appendTo(this.$dropdownParent); - if (options.query != null) { - var Query = require(options.amdBase + 'compat/query'); + this._positionDropdown(); + this._resizeDropdown(); + }; - options.dataAdapter = Utils.Decorate( - options.dataAdapter, - Query - ); - } + return AttachBody; + }); - if (options.initSelection != null) { - var InitSelection = require(options.amdBase + 'compat/initSelection'); + S2.define('select2/dropdown/minimumResultsForSearch',[ - options.dataAdapter = Utils.Decorate( - options.dataAdapter, - InitSelection - ); - } - } + ], function () { + function countResults (data) { + var count = 0; - if (options.resultsAdapter == null) { - options.resultsAdapter = ResultsList; + for (var d = 0; d < data.length; d++) { + var item = data[d]; - if (options.ajax != null) { - options.resultsAdapter = Utils.Decorate( - options.resultsAdapter, - InfiniteScroll - ); - } + if (item.children) { + count += countResults(item.children); + } else { + count++; + } + } - if (options.placeholder != null) { - options.resultsAdapter = Utils.Decorate( - options.resultsAdapter, - HidePlaceholder - ); + return count; } - if (options.selectOnClose) { - options.resultsAdapter = Utils.Decorate( - options.resultsAdapter, - SelectOnClose - ); - } - } + function MinimumResultsForSearch (decorated, $element, options, dataAdapter) { + this.minimumResultsForSearch = options.get('minimumResultsForSearch'); - if (options.dropdownAdapter == null) { - if (options.multiple) { - options.dropdownAdapter = Dropdown; - } else { - var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch); + if (this.minimumResultsForSearch < 0) { + this.minimumResultsForSearch = Infinity; + } - options.dropdownAdapter = SearchableDropdown; + decorated.call(this, $element, options, dataAdapter); } - if (options.minimumResultsForSearch !== 0) { - options.dropdownAdapter = Utils.Decorate( - options.dropdownAdapter, - MinimumResultsForSearch - ); - } + MinimumResultsForSearch.prototype.showSearch = function (decorated, params) { + if (countResults(params.data.results) < this.minimumResultsForSearch) { + return false; + } - if (options.closeOnSelect) { - options.dropdownAdapter = Utils.Decorate( - options.dropdownAdapter, - CloseOnSelect - ); - } + return decorated.call(this, params); + }; - if ( - options.dropdownCssClass != null || - options.dropdownCss != null || - options.adaptDropdownCssClass != null - ) { - var DropdownCSS = require(options.amdBase + 'compat/dropdownCss'); + return MinimumResultsForSearch; + }); - options.dropdownAdapter = Utils.Decorate( - options.dropdownAdapter, - DropdownCSS - ); - } + S2.define('select2/dropdown/selectOnClose',[ - options.dropdownAdapter = Utils.Decorate( - options.dropdownAdapter, - AttachBody - ); - } + ], function () { + function SelectOnClose () { } - if (options.selectionAdapter == null) { - if (options.multiple) { - options.selectionAdapter = MultipleSelection; - } else { - options.selectionAdapter = SingleSelection; - } + SelectOnClose.prototype.bind = function (decorated, container, $container) { + var self = this; - // Add the placeholder mixin if a placeholder was specified - if (options.placeholder != null) { - options.selectionAdapter = Utils.Decorate( - options.selectionAdapter, - Placeholder - ); - } + decorated.call(this, container, $container); - if (options.allowClear) { - options.selectionAdapter = Utils.Decorate( - options.selectionAdapter, - AllowClear - ); - } + container.on('close', function (params) { + self._handleSelectOnClose(params); + }); + }; - if (options.multiple) { - options.selectionAdapter = Utils.Decorate( - options.selectionAdapter, - SelectionSearch - ); - } + SelectOnClose.prototype._handleSelectOnClose = function (_, params) { + if (params && params.originalSelect2Event != null) { + var event = params.originalSelect2Event; - if ( - options.containerCssClass != null || - options.containerCss != null || - options.adaptContainerCssClass != null - ) { - var ContainerCSS = require(options.amdBase + 'compat/containerCss'); + // 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; + } + } - options.selectionAdapter = Utils.Decorate( - options.selectionAdapter, - ContainerCSS - ); - } + var $highlightedResults = this.getHighlightedResults(); - options.selectionAdapter = Utils.Decorate( - options.selectionAdapter, - EventRelay - ); - } + // Only select highlighted results + if ($highlightedResults.length < 1) { + return; + } - 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]; + var data = $highlightedResults.data('data'); - options.language = [options.language, baseLanguage]; - } else { - options.language = [options.language]; + // Don't re-select already selected resulte + if ( + (data.element != null && data.element.selected) || + (data.element == null && data.selected) + ) { + return; + } + + this.trigger('select', { + data: data + }); + }; + + return SelectOnClose; + }); + + S2.define('select2/dropdown/closeOnSelect',[ + + ], function () { + function CloseOnSelect () { } + + CloseOnSelect.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('select', function (evt) { + self._selectTriggered(evt); + }); + + container.on('unselect', function (evt) { + self._selectTriggered(evt); + }); + }; + + CloseOnSelect.prototype._selectTriggered = function (_, evt) { + var originalEvent = evt.originalEvent; + + // Don't close if the control key is being held + if (originalEvent && originalEvent.ctrlKey) { + return; + } + + this.trigger('close', { + originalEvent: originalEvent, + originalSelect2Event: evt + }); + }; + + return CloseOnSelect; + }); + + S2.define('select2/i18n/en',[],function () { + // English + return { + errorLoading: function () { + return 'The results could not be loaded.'; + }, + inputTooLong: function (args) { + var overChars = args.input.length - args.maximum; + + var message = 'Please delete ' + overChars + ' character'; + + if (overChars != 1) { + message += 's'; + } + + return message; + }, + inputTooShort: function (args) { + var remainingChars = args.minimum - args.input.length; + + var message = 'Please enter ' + remainingChars + ' or more characters'; + + return message; + }, + loadingMore: function () { + return 'Loading more results…'; + }, + maximumSelected: function (args) { + var message = 'You can only select ' + args.maximum + ' item'; + + if (args.maximum != 1) { + message += 's'; + } + + return message; + }, + noResults: function () { + return 'No results found'; + }, + searching: function () { + return 'Searching…'; + } + }; + }); + + S2.define('select2/defaults',[ + 'jquery', + 'require', + + './results', + + './selection/single', + './selection/multiple', + './selection/placeholder', + './selection/allowClear', + './selection/search', + './selection/eventRelay', + + './utils', + './translation', + './diacritics', + + './data/select', + './data/array', + './data/ajax', + './data/tags', + './data/tokenizer', + './data/minimumInputLength', + './data/maximumInputLength', + './data/maximumSelectionLength', + + './dropdown', + './dropdown/search', + './dropdown/hidePlaceholder', + './dropdown/infiniteScroll', + './dropdown/attachBody', + './dropdown/minimumResultsForSearch', + './dropdown/selectOnClose', + './dropdown/closeOnSelect', + + './i18n/en' + ], function ($, require, + + ResultsList, + + SingleSelection, MultipleSelection, Placeholder, AllowClear, + SelectionSearch, EventRelay, + + Utils, Translation, DIACRITICS, + + SelectData, ArrayData, AjaxData, Tags, Tokenizer, + MinimumInputLength, MaximumInputLength, MaximumSelectionLength, + + Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll, + AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect, + + EnglishTranslation) { + function Defaults () { + this.reset(); } - } - if ($.isArray(options.language)) { - var languages = new Translation(); - 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.' - ); + Defaults.prototype.apply = function (options) { + options = $.extend(true, {}, this.defaults, options); + + if (options.dataAdapter == null) { + if (options.ajax != null) { + options.dataAdapter = AjaxData; + } else if (options.data != null) { + options.dataAdapter = ArrayData; + } else { + options.dataAdapter = SelectData; + } + + if (options.minimumInputLength > 0) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + MinimumInputLength + ); + } + + if (options.maximumInputLength > 0) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + MaximumInputLength + ); + } + + if (options.maximumSelectionLength > 0) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + MaximumSelectionLength + ); + } + + if (options.tags) { + options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags); + } + + if (options.tokenSeparators != null || options.tokenizer != null) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + Tokenizer + ); + } + + if (options.query != null) { + var Query = require(options.amdBase + 'compat/query'); + + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + Query + ); + } + + if (options.initSelection != null) { + var InitSelection = require(options.amdBase + 'compat/initSelection'); + + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + InitSelection + ); + } + } + + if (options.resultsAdapter == null) { + options.resultsAdapter = ResultsList; + + if (options.ajax != null) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + InfiniteScroll + ); + } + + if (options.placeholder != null) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + HidePlaceholder + ); + } + + if (options.selectOnClose) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + SelectOnClose + ); + } + } + + if (options.dropdownAdapter == null) { + if (options.multiple) { + options.dropdownAdapter = Dropdown; + } else { + var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch); + + options.dropdownAdapter = SearchableDropdown; + } + + if (options.minimumResultsForSearch !== 0) { + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + MinimumResultsForSearch + ); + } + + if (options.closeOnSelect) { + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + CloseOnSelect + ); + } + + if ( + options.dropdownCssClass != null || + options.dropdownCss != null || + options.adaptDropdownCssClass != null + ) { + var DropdownCSS = require(options.amdBase + 'compat/dropdownCss'); + + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + DropdownCSS + ); + } + + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + AttachBody + ); + } + + if (options.selectionAdapter == null) { + if (options.multiple) { + options.selectionAdapter = MultipleSelection; + } else { + options.selectionAdapter = SingleSelection; + } + + // Add the placeholder mixin if a placeholder was specified + if (options.placeholder != null) { + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + Placeholder + ); + } + + if (options.allowClear) { + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + AllowClear + ); + } + + if (options.multiple) { + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + SelectionSearch + ); + } + + if ( + options.containerCssClass != null || + options.containerCss != null || + options.adaptContainerCssClass != null + ) { + var ContainerCSS = require(options.amdBase + 'compat/containerCss'); + + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + ContainerCSS + ); + } + + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + EventRelay + ); + } + + 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 ($.isArray(options.language)) { + var languages = new Translation(); + 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.' + ); + } + + continue; + } } - continue; + languages.extend(language); } + + options.translations = languages; + } else { + var baseTranslation = Translation.loadPath( + this.defaults.amdLanguageBase + 'en' + ); + var customTranslation = new Translation(options.language); + + customTranslation.extend(baseTranslation); + + options.translations = customTranslation; } - languages.extend(language); - } + return options; + }; - options.translations = languages; - } else { - var baseTranslation = Translation.loadPath( - this.defaults.amdLanguageBase + 'en' - ); - var customTranslation = new Translation(options.language); + Defaults.prototype.reset = function () { + function stripDiacritics (text) { + // Used 'uni range + named function' from http://jsperf.com/diacritics/18 + function match(a) { + return DIACRITICS[a] || a; + } - customTranslation.extend(baseTranslation); + return text.replace(/[^\u0000-\u007E]/g, match); + } - options.translations = customTranslation; - } + function matcher (params, data) { + // Always return the object if there is nothing to compare + if ($.trim(params.term) === '') { + return data; + } - return options; - }; + // Do a recursive check for options with children + if (data.children && data.children.length > 0) { + // Clone the data object if there are children + // This is required as we modify the object to remove any non-matches + var match = $.extend(true, {}, data); - Defaults.prototype.reset = function () { - function stripDiacritics (text) { - // Used 'uni range + named function' from http://jsperf.com/diacritics/18 - function match(a) { - return DIACRITICS[a] || a; - } + // Check each child of the option + for (var c = data.children.length - 1; c >= 0; c--) { + var child = data.children[c]; - return text.replace(/[^\u0000-\u007E]/g, match); - } + var matches = matcher(params, child); - function matcher (params, data) { - // Always return the object if there is nothing to compare - if ($.trim(params.term) === '') { - return data; - } + // If there wasn't a match, remove the object in the array + if (matches == null) { + match.children.splice(c, 1); + } + } - // Do a recursive check for options with children - if (data.children && data.children.length > 0) { - // Clone the data object if there are children - // This is required as we modify the object to remove any non-matches - var match = $.extend(true, {}, data); + // If any children matched, return the new object + if (match.children.length > 0) { + return match; + } - // Check each child of the option - for (var c = data.children.length - 1; c >= 0; c--) { - var child = data.children[c]; + // If there were no matching children, check just the plain object + return matcher(params, match); + } - var matches = matcher(params, child); + var original = stripDiacritics(data.text).toUpperCase(); + var term = stripDiacritics(params.term).toUpperCase(); - // If there wasn't a match, remove the object in the array - if (matches == null) { - match.children.splice(c, 1); + // Check if the text contains the term + if (original.indexOf(term) > -1) { + return data; } + + // If it doesn't contain the term, don't return anything + return null; } - // If any children matched, return the new object - if (match.children.length > 0) { - return match; + this.defaults = { + amdBase: './', + amdLanguageBase: './i18n/', + closeOnSelect: true, + debug: false, + dropdownAutoWidth: false, + escapeMarkup: Utils.escapeMarkup, + language: EnglishTranslation, + matcher: matcher, + minimumInputLength: 0, + maximumInputLength: 0, + maximumSelectionLength: 0, + minimumResultsForSearch: 0, + selectOnClose: false, + sorter: function (data) { + return data; + }, + templateResult: function (result) { + return result.text; + }, + templateSelection: function (selection) { + return selection.text; + }, + theme: 'default', + width: 'resolve' + }; + }; + + Defaults.prototype.set = function (key, value) { + var camelKey = $.camelCase(key); + + var data = {}; + data[camelKey] = value; + + var convertedData = Utils._convertData(data); + + $.extend(this.defaults, convertedData); + }; + + var defaults = new Defaults(); + + return defaults; + }); + + S2.define('select2/options',[ + 'require', + 'jquery', + './defaults', + './utils' + ], function (require, $, Defaults, Utils) { + function Options (options, $element) { + this.options = options; + + if ($element != null) { + this.fromElement($element); } - // If there were no matching children, check just the plain object - return matcher(params, match); - } + this.options = Defaults.apply(this.options); - var original = stripDiacritics(data.text).toUpperCase(); - var term = stripDiacritics(params.term).toUpperCase(); + if ($element && $element.is('input')) { + var InputCompat = require(this.get('amdBase') + 'compat/inputData'); - // Check if the text contains the term - if (original.indexOf(term) > -1) { - return data; + this.options.dataAdapter = Utils.Decorate( + this.options.dataAdapter, + InputCompat + ); + } } - // If it doesn't contain the term, don't return anything - return null; - } + Options.prototype.fromElement = function ($e) { + var excludedData = ['select2']; - this.defaults = { - amdBase: './', - amdLanguageBase: './i18n/', - closeOnSelect: true, - debug: false, - dropdownAutoWidth: false, - escapeMarkup: Utils.escapeMarkup, - language: EnglishTranslation, - matcher: matcher, - minimumInputLength: 0, - maximumInputLength: 0, - maximumSelectionLength: 0, - minimumResultsForSearch: 0, - selectOnClose: false, - sorter: function (data) { - return data; - }, - templateResult: function (result) { - return result.text; - }, - templateSelection: function (selection) { - return selection.text; - }, - theme: 'default', - width: 'resolve' - }; - }; + if (this.options.multiple == null) { + this.options.multiple = $e.prop('multiple'); + } - Defaults.prototype.set = function (key, value) { - var camelKey = $.camelCase(key); + if (this.options.disabled == null) { + this.options.disabled = $e.prop('disabled'); + } - var data = {}; - data[camelKey] = value; + if (!this.options.required) { + this.options.required = $e.prop('required'); + } - var convertedData = Utils._convertData(data); + 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'); + } + } - $.extend(this.defaults, convertedData); - }; + if (this.options.dir == null) { + if ($e.prop('dir')) { + this.options.dir = $e.prop('dir'); + } else if ($e.closest('[dir]').prop('dir')) { + this.options.dir = $e.closest('[dir]').prop('dir'); + } else { + this.options.dir = 'ltr'; + } + } - var defaults = new Defaults(); + $e.prop('disabled', this.options.disabled); + $e.prop('multiple', this.options.multiple); - return defaults; -}); + if ($e.data('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.' + ); + } -S2.define('select2/options',[ - 'require', - 'jquery', - './defaults', - './utils' -], function (require, $, Defaults, Utils) { - function Options (options, $element) { - this.options = options; + $e.data('data', $e.data('select2Tags')); + $e.data('tags', true); + } - if ($element != null) { - this.fromElement($element); - } + if ($e.data('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.' + ); + } - this.options = Defaults.apply(this.options); + $e.attr('ajax--url', $e.data('ajaxUrl')); + $e.data('ajax--url', $e.data('ajaxUrl')); + } - if ($element && $element.is('input')) { - var InputCompat = require(this.get('amdBase') + 'compat/inputData'); + var dataset = {}; - this.options.dataAdapter = Utils.Decorate( - this.options.dataAdapter, - InputCompat - ); - } - } + // 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(); + } - Options.prototype.fromElement = function ($e) { - var excludedData = ['select2']; + var data = $.extend(true, {}, dataset); - if (this.options.multiple == null) { - this.options.multiple = $e.prop('multiple'); - } + data = Utils._convertData(data); - if (this.options.disabled == null) { - this.options.disabled = $e.prop('disabled'); - } + for (var key in data) { + if ($.inArray(key, excludedData) > -1) { + continue; + } - 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 ($.isPlainObject(this.options[key])) { + $.extend(this.options[key], data[key]); + } else { + this.options[key] = data[key]; + } + } - if (this.options.dir == null) { - if ($e.prop('dir')) { - this.options.dir = $e.prop('dir'); - } else if ($e.closest('[dir]').prop('dir')) { - this.options.dir = $e.closest('[dir]').prop('dir'); - } else { - this.options.dir = 'ltr'; - } - } + return this; + }; - $e.prop('disabled', this.options.disabled); - $e.prop('multiple', this.options.multiple); + Options.prototype.get = function (key) { + return this.options[key]; + }; - if ($e.data('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.' - ); - } + Options.prototype.set = function (key, val) { + this.options[key] = val; + }; - $e.data('data', $e.data('select2Tags')); - $e.data('tags', true); - } + return Options; + }); - if ($e.data('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.' - ); - } + S2.define('select2/core',[ + 'jquery', + './options', + './utils', + './keys' + ], function ($, Options, Utils, KEYS) { + var Select2 = function ($element, options) { + if ($element.data('select2') != null) { + $element.data('select2').destroy(); + } - $e.attr('ajax--url', $e.data('ajaxUrl')); - $e.data('ajax--url', $e.data('ajaxUrl')); - } + this.$element = $element; - var dataset = {}; + this.id = this._generateId($element); - // 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(); - } + options = options || {}; - var data = $.extend(true, {}, dataset); + this.options = new Options(options, $element); - data = Utils._convertData(data); + Select2.__super__.constructor.call(this); - for (var key in data) { - if ($.inArray(key, excludedData) > -1) { - continue; - } + // Set up the tabindex - if ($.isPlainObject(this.options[key])) { - $.extend(this.options[key], data[key]); - } else { - this.options[key] = data[key]; - } - } + var tabindex = $element.attr('tabindex') || 0; + $element.data('old-tabindex', tabindex); + $element.attr('tabindex', '-1'); - return this; - }; - - Options.prototype.get = function (key) { - return this.options[key]; - }; - - Options.prototype.set = function (key, val) { - this.options[key] = val; - }; - - return Options; -}); - -S2.define('select2/core',[ - 'jquery', - './options', - './utils', - './keys' -], function ($, Options, Utils, KEYS) { - var Select2 = function ($element, options) { - if ($element.data('select2') != null) { - $element.data('select2').destroy(); - } + // Set up containers and adapters - this.$element = $element; + var DataAdapter = this.options.get('dataAdapter'); + this.dataAdapter = new DataAdapter($element, this.options); - this.id = this._generateId($element); + var $container = this.render(); - options = options || {}; + this._placeContainer($container); - this.options = new Options(options, $element); + var SelectionAdapter = this.options.get('selectionAdapter'); + this.selection = new SelectionAdapter($element, this.options); + this.$selection = this.selection.render(); - Select2.__super__.constructor.call(this); + this.selection.position(this.$selection, $container); - // Set up the tabindex + var DropdownAdapter = this.options.get('dropdownAdapter'); + this.dropdown = new DropdownAdapter($element, this.options); + this.$dropdown = this.dropdown.render(); - var tabindex = $element.attr('tabindex') || 0; - $element.data('old-tabindex', tabindex); - $element.attr('tabindex', '-1'); + this.dropdown.position(this.$dropdown, $container); - // Set up containers and adapters + var ResultsAdapter = this.options.get('resultsAdapter'); + this.results = new ResultsAdapter($element, this.options, this.dataAdapter); + this.$results = this.results.render(); - var DataAdapter = this.options.get('dataAdapter'); - this.dataAdapter = new DataAdapter($element, this.options); + this.results.position(this.$results, this.$dropdown); - var $container = this.render(); + // Bind events - this._placeContainer($container); + var self = this; - var SelectionAdapter = this.options.get('selectionAdapter'); - this.selection = new SelectionAdapter($element, this.options); - this.$selection = this.selection.render(); + // Bind the container to all of the adapters + this._bindAdapters(); - this.selection.position(this.$selection, $container); + // Register any DOM event handlers + this._registerDomEvents(); - var DropdownAdapter = this.options.get('dropdownAdapter'); - this.dropdown = new DropdownAdapter($element, this.options); - this.$dropdown = this.dropdown.render(); + // Register any internal event handlers + this._registerDataEvents(); + this._registerSelectionEvents(); + this._registerDropdownEvents(); + this._registerResultsEvents(); + this._registerEvents(); - this.dropdown.position(this.$dropdown, $container); + // Set the initial state + this.dataAdapter.current(function (initialData) { + self.trigger('selection:update', { + data: initialData + }); + }); - var ResultsAdapter = this.options.get('resultsAdapter'); - this.results = new ResultsAdapter($element, this.options, this.dataAdapter); - this.$results = this.results.render(); + // Hide the original select + $element.addClass('select2-hidden-accessible'); + $element.attr('aria-hidden', 'true'); - this.results.position(this.$results, this.$dropdown); + // Synchronize any monitored attributes + this._syncAttributes(); - // Bind events + $element.data('select2', this); + }; - var self = this; + Utils.Extend(Select2, Utils.Observable); - // Bind the container to all of the adapters - this._bindAdapters(); + Select2.prototype._generateId = function ($element) { + var id = ''; - // Register any DOM event handlers - this._registerDomEvents(); + if ($element.attr('id') != null) { + id = $element.attr('id'); + } else if ($element.attr('name') != null) { + id = $element.attr('name') + '-' + Utils.generateChars(2); + } else { + id = Utils.generateChars(4); + } - // Register any internal event handlers - this._registerDataEvents(); - this._registerSelectionEvents(); - this._registerDropdownEvents(); - this._registerResultsEvents(); - this._registerEvents(); + id = id.replace(/(:|\.|\[|\]|,)/g, ''); + id = 'select2-' + id; - // Set the initial state - this.dataAdapter.current(function (initialData) { - self.trigger('selection:update', { - data: initialData - }); - }); + return id; + }; - // Hide the original select - $element.addClass('select2-hidden-accessible'); - $element.attr('aria-hidden', 'true'); + Select2.prototype._placeContainer = function ($container) { + $container.insertAfter(this.$element); - // Synchronize any monitored attributes - this._syncAttributes(); + var width = this._resolveWidth(this.$element, this.options.get('width')); - $element.data('select2', this); - }; + if (width != null) { + $container.css('width', width); + } + }; - Utils.Extend(Select2, Utils.Observable); + Select2.prototype._resolveWidth = function ($element, method) { + var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i; - Select2.prototype._generateId = function ($element) { - var id = ''; + if (method == 'resolve') { + var styleWidth = this._resolveWidth($element, 'style'); - if ($element.attr('id') != null) { - id = $element.attr('id'); - } else if ($element.attr('name') != null) { - id = $element.attr('name') + '-' + Utils.generateChars(2); - } else { - id = Utils.generateChars(4); - } + if (styleWidth != null) { + return styleWidth; + } - id = id.replace(/(:|\.|\[|\]|,)/g, ''); - id = 'select2-' + id; + return this._resolveWidth($element, 'element'); + } - return id; - }; + if (method == 'element') { + var elementWidth = $element.outerWidth(false); - Select2.prototype._placeContainer = function ($container) { - $container.insertAfter(this.$element); + if (elementWidth <= 0) { + return 'auto'; + } - var width = this._resolveWidth(this.$element, this.options.get('width')); + return elementWidth + 'px'; + } - if (width != null) { - $container.css('width', width); - } - }; + if (method == 'style') { + var style = $element.attr('style'); - Select2.prototype._resolveWidth = function ($element, method) { - var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i; + if (typeof(style) !== 'string') { + return null; + } - if (method == 'resolve') { - var styleWidth = this._resolveWidth($element, 'style'); + var attrs = style.split(';'); - if (styleWidth != null) { - return styleWidth; - } + for (var i = 0, l = attrs.length; i < l; i = i + 1) { + var attr = attrs[i].replace(/\s/g, ''); + var matches = attr.match(WIDTH); - return this._resolveWidth($element, 'element'); - } + if (matches !== null && matches.length >= 1) { + return matches[1]; + } + } - if (method == 'element') { - var elementWidth = $element.outerWidth(false); + return null; + } - if (elementWidth <= 0) { - return 'auto'; - } + return method; + }; - return elementWidth + 'px'; - } + Select2.prototype._bindAdapters = function () { + this.dataAdapter.bind(this, this.$container); + this.selection.bind(this, this.$container); + + this.dropdown.bind(this, this.$container); + this.results.bind(this, this.$container); + }; - if (method == 'style') { - var style = $element.attr('style'); + Select2.prototype._registerDomEvents = function () { + var self = this; - if (typeof(style) !== 'string') { - return null; - } + this.$element.on('change.select2', function () { + self.dataAdapter.current(function (data) { + self.trigger('selection:update', { + data: data + }); + }); + }); - var attrs = style.split(';'); + this.$element.on('focus.select2', function (evt) { + self.trigger('focus', evt); + }); - for (var i = 0, l = attrs.length; i < l; i = i + 1) { - var attr = attrs[i].replace(/\s/g, ''); - var matches = attr.match(WIDTH); + this._syncA = Utils.bind(this._syncAttributes, this); + this._syncS = Utils.bind(this._syncSubtree, this); - if (matches !== null && matches.length >= 1) { - return matches[1]; + if (this.$element[0].attachEvent) { + this.$element[0].attachEvent('onpropertychange', this._syncA); } - } - return null; - } + var observer = window.MutationObserver || + window.WebKitMutationObserver || + window.MozMutationObserver + ; - return method; - }; + if (observer != null) { + this._observer = new observer(function (mutations) { + $.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._syncA, + false + ); + this.$element[0].addEventListener( + 'DOMNodeInserted', + self._syncS, + false + ); + this.$element[0].addEventListener( + 'DOMNodeRemoved', + self._syncS, + false + ); + } + }; - Select2.prototype._bindAdapters = function () { - this.dataAdapter.bind(this, this.$container); - this.selection.bind(this, this.$container); + Select2.prototype._registerDataEvents = function () { + var self = this; - this.dropdown.bind(this, this.$container); - this.results.bind(this, this.$container); - }; + this.dataAdapter.on('*', function (name, params) { + self.trigger(name, params); + }); + }; - Select2.prototype._registerDomEvents = function () { - var self = this; + Select2.prototype._registerSelectionEvents = function () { + var self = this; + var nonRelayEvents = ['toggle', 'focus']; - this.$element.on('change.select2', function () { - self.dataAdapter.current(function (data) { - self.trigger('selection:update', { - data: data + this.selection.on('toggle', function () { + self.toggleDropdown(); }); - }); - }); - this.$element.on('focus.select2', function (evt) { - self.trigger('focus', evt); - }); + this.selection.on('focus', function (params) { + self.focus(params); + }); - this._syncA = Utils.bind(this._syncAttributes, this); - this._syncS = Utils.bind(this._syncSubtree, this); + this.selection.on('*', function (name, params) { + if ($.inArray(name, nonRelayEvents) !== -1) { + return; + } - if (this.$element[0].attachEvent) { - this.$element[0].attachEvent('onpropertychange', this._syncA); - } + self.trigger(name, params); + }); + }; - var observer = window.MutationObserver || - window.WebKitMutationObserver || - window.MozMutationObserver - ; + Select2.prototype._registerDropdownEvents = function () { + var self = this; - if (observer != null) { - this._observer = new observer(function (mutations) { - $.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._syncA, - false - ); - this.$element[0].addEventListener( - 'DOMNodeInserted', - self._syncS, - false - ); - this.$element[0].addEventListener( - 'DOMNodeRemoved', - self._syncS, - false - ); - } - }; + this.dropdown.on('*', function (name, params) { + self.trigger(name, params); + }); + }; - Select2.prototype._registerDataEvents = function () { - var self = this; + Select2.prototype._registerResultsEvents = function () { + var self = this; - this.dataAdapter.on('*', function (name, params) { - self.trigger(name, params); - }); - }; + this.results.on('*', function (name, params) { + self.trigger(name, params); + }); + }; - Select2.prototype._registerSelectionEvents = function () { - var self = this; - var nonRelayEvents = ['toggle', 'focus']; + Select2.prototype._registerEvents = function () { + var self = this; - this.selection.on('toggle', function () { - self.toggleDropdown(); - }); + this.on('open', function () { + self.$container.addClass('select2-container--open'); + }); - this.selection.on('focus', function (params) { - self.focus(params); - }); + this.on('close', function () { + self.$container.removeClass('select2-container--open'); + }); - this.selection.on('*', function (name, params) { - if ($.inArray(name, nonRelayEvents) !== -1) { - return; - } + this.on('enable', function () { + self.$container.removeClass('select2-container--disabled'); + }); - self.trigger(name, params); - }); - }; + this.on('disable', function () { + self.$container.addClass('select2-container--disabled'); + }); - Select2.prototype._registerDropdownEvents = function () { - var self = this; + this.on('blur', function () { + self.$container.removeClass('select2-container--focus'); + }); - this.dropdown.on('*', function (name, params) { - self.trigger(name, params); - }); - }; + this.on('query', function (params) { + if (!self.isOpen()) { + self.trigger('open', {}); + } - Select2.prototype._registerResultsEvents = function () { - var self = this; + this.dataAdapter.query(params, function (data) { + self.trigger('results:all', { + data: data, + query: params + }); + }); + }); - this.results.on('*', function (name, params) { - self.trigger(name, params); - }); - }; + this.on('query:append', function (params) { + this.dataAdapter.query(params, function (data) { + self.trigger('results:append', { + data: data, + query: params + }); + }); + }); - Select2.prototype._registerEvents = function () { - var self = this; + this.on('open', function(){ + // Focus on the active element when opening dropdown. + // Needs 1 ms delay because of other 1 ms setTimeouts when rendering. + setTimeout(function(){ + self.focusOnActiveElement(); + }, 1); + }); - this.on('open', function () { - self.$container.addClass('select2-container--open'); - }); + $(document).on('keydown', function (evt) { + var key = evt.which; + if (self.isOpen()) { + if (key === KEYS.ESC || (key === KEYS.UP && evt.altKey)) { + self.close(); - this.on('close', function () { - self.$container.removeClass('select2-container--open'); - }); + evt.preventDefault(); + } else if (key === KEYS.ENTER || key === KEYS.TAB) { + self.trigger('results:select', {}); - this.on('enable', function () { - self.$container.removeClass('select2-container--disabled'); - }); + evt.preventDefault(); + } else if ((key === KEYS.SPACE && evt.ctrlKey)) { + self.trigger('results:toggle', {}); - this.on('disable', function () { - self.$container.addClass('select2-container--disabled'); - }); + evt.preventDefault(); + } else if (key === KEYS.UP) { + self.trigger('results:previous', {}); - this.on('blur', function () { - self.$container.removeClass('select2-container--focus'); - }); + evt.preventDefault(); + } else if (key === KEYS.DOWN) { + self.trigger('results:next', {}); - this.on('query', function (params) { - if (!self.isOpen()) { - self.trigger('open', {}); - } + evt.preventDefault(); + } - this.dataAdapter.query(params, function (data) { - self.trigger('results:all', { - data: data, - query: params + var $searchField = self.$dropdown.find('.select2-search__field'); + if (! $searchField.length) { + $searchField = self.$container.find('.select2-search__field'); + } + + // Move the focus to the selected element on keyboard navigation. + // Required for screen readers to work properly. + if (key === KEYS.DOWN || key === KEYS.UP) { + self.focusOnActiveElement(); + } else { + // Focus on the search if user starts typing. + $searchField.focus(); + // Focus back to active selection when finished typing. + // Small delay so typed character can be read by screen reader. + setTimeout(function(){ + self.focusOnActiveElement(); + }, 1000); + } + } else if (self.hasFocus()) { + if (key === KEYS.ENTER || key === KEYS.SPACE || + key === KEYS.DOWN) { + self.open(); + evt.preventDefault(); + } + } }); - }); - }); + }; + + Select2.prototype.focusOnActiveElement = function () { + // Don't mess with the focus on touchscreens because it causes havoc with on-screen keyboards. + if (this.isOpen() && ! Utils.isTouchscreen()) { + this.$results.find('li.select2-results__option--highlighted').focus(); + } + }; + + Select2.prototype._syncAttributes = function () { + this.options.set('disabled', this.$element.prop('disabled')); + + if (this.options.get('disabled')) { + if (this.isOpen()) { + this.close(); + } + + this.trigger('disable', {}); + } else { + this.trigger('enable', {}); + } + }; + + 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 + }); + }); + } + }; - this.on('query:append', function (params) { - this.dataAdapter.query(params, function (data) { - self.trigger('results:append', { - data: data, - query: params - }); - }); - }); + /** + * Override the trigger method to automatically trigger pre-events when + * there are events that can be prevented. + */ + Select2.prototype.trigger = function (name, args) { + var actualTrigger = Select2.__super__.trigger; + var preTriggerMap = { + 'open': 'opening', + 'close': 'closing', + 'select': 'selecting', + 'unselect': 'unselecting' + }; - this.on('open', function(){ - // Focus on the active element when opening dropdown. - // Needs 1 ms delay because of other 1 ms setTimeouts when rendering. - setTimeout(function(){ - self.focusOnActiveElement(); - }, 1); - }); + if (args === undefined) { + args = {}; + } - $(document).on('keydown', function (evt) { - var key = evt.which; - if (self.isOpen()) { - if (key === KEYS.ESC || key === KEYS.TAB || - (key === KEYS.UP && evt.altKey)) { - self.close(); + if (name in preTriggerMap) { + var preTriggerName = preTriggerMap[name]; + var preTriggerArgs = { + prevented: false, + name: name, + args: args + }; - evt.preventDefault(); - } else if (key === KEYS.ENTER) { - self.trigger('results:select', {}); + actualTrigger.call(this, preTriggerName, preTriggerArgs); - evt.preventDefault(); - } else if ((key === KEYS.SPACE && evt.ctrlKey)) { - self.trigger('results:toggle', {}); + if (preTriggerArgs.prevented) { + args.prevented = true; - evt.preventDefault(); - } else if (key === KEYS.UP) { - self.trigger('results:previous', {}); + return; + } + } - evt.preventDefault(); - } else if (key === KEYS.DOWN) { - self.trigger('results:next', {}); + actualTrigger.call(this, name, args); + }; - evt.preventDefault(); + Select2.prototype.toggleDropdown = function () { + if (this.options.get('disabled')) { + return; } - // Move the focus to the selected element on keyboard navigation. - // Required for screen readers to work properly. - if (key === KEYS.DOWN || key === KEYS.UP) { - self.focusOnActiveElement(); + if (this.isOpen()) { + this.close(); } else { - // Focus on the search if user starts typing. - var $searchField = self.$dropdown.find('.select2-search__field'); - if (! $searchField.length) { - $searchField = self.$container.find('.select2-search__field'); - } - $searchField.focus(); - // Focus back to active selection when finished typing. - // Small delay so typed character can be read by screen reader. - setTimeout(function(){ - self.focusOnActiveElement(); - }, 1000); + this.open(); } + }; - } else if (self.hasFocus()) { - if (key === KEYS.ENTER || key === KEYS.SPACE || - (key === KEYS.DOWN && evt.altKey)) { - self.open(); - evt.preventDefault(); + Select2.prototype.open = function () { + if (this.isOpen()) { + return; } - } - }); - }; - Select2.prototype.focusOnActiveElement = function () { - // Don't mess with the focus on touchscreens because it causes havoc with on-screen keyboards. - if (! Utils.isTouchscreen()) { - this.$results.find('li.select2-results__option--highlighted').focus(); - } - }; + this.trigger('query', {}); + }; - Select2.prototype._syncAttributes = function () { - this.options.set('disabled', this.$element.prop('disabled')); + Select2.prototype.close = function () { + if (!this.isOpen()) { + return; + } - if (this.options.get('disabled')) { - if (this.isOpen()) { - this.close(); - } + this.trigger('close', {}); + }; - this.trigger('disable', {}); - } else { - this.trigger('enable', {}); - } - }; - - 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; - } + Select2.prototype.isOpen = function () { + return this.$container.hasClass('select2-container--open'); + }; - 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]; + Select2.prototype.hasFocus = function () { + return this.$container.hasClass('select2-container--focus'); + }; - if (node.selected) { - changed = true; + Select2.prototype.focus = function (data) { + // No need to re-trigger focus events if we are already focused + if (this.hasFocus()) { + return; } - } - } 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. - */ - Select2.prototype.trigger = function (name, args) { - var actualTrigger = Select2.__super__.trigger; - var preTriggerMap = { - 'open': 'opening', - 'close': 'closing', - 'select': 'selecting', - 'unselect': 'unselecting' - }; - - if (args === undefined) { - args = {}; - } - if (name in preTriggerMap) { - var preTriggerName = preTriggerMap[name]; - var preTriggerArgs = { - prevented: false, - name: name, - args: args + this.$container.addClass('select2-container--focus'); + this.trigger('focus', {}); }; - actualTrigger.call(this, preTriggerName, preTriggerArgs); + Select2.prototype.enable = function (args) { + if (this.options.get('debug') && window.console && console.warn) { + console.warn( + 'Select2: The `select2("enable")` method has been deprecated and will' + + ' be removed in later Select2 versions. Use $element.prop("disabled")' + + ' instead.' + ); + } - if (preTriggerArgs.prevented) { - args.prevented = true; + if (args == null || args.length === 0) { + args = [true]; + } - return; - } - } + var disabled = !args[0]; - actualTrigger.call(this, name, args); - }; + this.$element.prop('disabled', disabled); + }; - Select2.prototype.toggleDropdown = function () { - if (this.options.get('disabled')) { - return; - } + Select2.prototype.data = function () { + if (this.options.get('debug') && + arguments.length > 0 && window.console && console.warn) { + console.warn( + 'Select2: Data can no longer be set using `select2("data")`. You ' + + 'should consider setting the value instead using `$element.val()`.' + ); + } - if (this.isOpen()) { - this.close(); - } else { - this.open(); - } - }; + var data = []; - Select2.prototype.open = function () { - if (this.isOpen()) { - return; - } + this.dataAdapter.current(function (currentData) { + data = currentData; + }); - this.trigger('query', {}); - }; + return data; + }; - Select2.prototype.close = function () { - if (!this.isOpen()) { - return; - } + Select2.prototype.val = function (args) { + if (this.options.get('debug') && window.console && console.warn) { + console.warn( + 'Select2: The `select2("val")` method has been deprecated and will be' + + ' removed in later Select2 versions. Use $element.val() instead.' + ); + } - this.trigger('close', {}); - }; + if (args == null || args.length === 0) { + return this.$element.val(); + } - Select2.prototype.isOpen = function () { - return this.$container.hasClass('select2-container--open'); - }; + var newVal = args[0]; - Select2.prototype.hasFocus = function () { - return this.$container.hasClass('select2-container--focus'); - }; + if ($.isArray(newVal)) { + newVal = $.map(newVal, function (obj) { + return obj.toString(); + }); + } - Select2.prototype.focus = function (data) { - // No need to re-trigger focus events if we are already focused - if (this.hasFocus()) { - return; - } + this.$element.val(newVal).trigger('change'); + }; - this.$container.addClass('select2-container--focus'); - this.trigger('focus', {}); - }; - - Select2.prototype.enable = function (args) { - if (this.options.get('debug') && window.console && console.warn) { - console.warn( - 'Select2: The `select2("enable")` method has been deprecated and will' + - ' be removed in later Select2 versions. Use $element.prop("disabled")' + - ' instead.' - ); - } + Select2.prototype.destroy = function () { + this.$container.remove(); - if (args == null || args.length === 0) { - args = [true]; - } + if (this.$element[0].detachEvent) { + this.$element[0].detachEvent('onpropertychange', this._syncA); + } - var disabled = !args[0]; + if (this._observer != null) { + this._observer.disconnect(); + this._observer = null; + } else if (this.$element[0].removeEventListener) { + this.$element[0] + .removeEventListener('DOMAttrModified', this._syncA, false); + this.$element[0] + .removeEventListener('DOMNodeInserted', this._syncS, false); + this.$element[0] + .removeEventListener('DOMNodeRemoved', this._syncS, false); + } - this.$element.prop('disabled', disabled); - }; + this._syncA = null; + this._syncS = null; - Select2.prototype.data = function () { - if (this.options.get('debug') && - arguments.length > 0 && window.console && console.warn) { - console.warn( - 'Select2: Data can no longer be set using `select2("data")`. You ' + - 'should consider setting the value instead using `$element.val()`.' - ); - } + this.$element.off('.select2'); + this.$element.attr('tabindex', this.$element.data('old-tabindex')); - var data = []; + this.$element.removeClass('select2-hidden-accessible'); + this.$element.attr('aria-hidden', 'false'); + this.$element.removeData('select2'); - this.dataAdapter.current(function (currentData) { - data = currentData; - }); + this.dataAdapter.destroy(); + this.selection.destroy(); + this.dropdown.destroy(); + this.results.destroy(); - return data; - }; + this.dataAdapter = null; + this.selection = null; + this.dropdown = null; + this.results = null; + }; - Select2.prototype.val = function (args) { - if (this.options.get('debug') && window.console && console.warn) { - console.warn( - 'Select2: The `select2("val")` method has been deprecated and will be' + - ' removed in later Select2 versions. Use $element.val() instead.' - ); - } + Select2.prototype.render = function () { + var $container = $( + '' + + '' + + '' + + '' + ); - if (args == null || args.length === 0) { - return this.$element.val(); - } + $container.attr('dir', this.options.get('dir')); - var newVal = args[0]; + this.$container = $container; - if ($.isArray(newVal)) { - newVal = $.map(newVal, function (obj) { - return obj.toString(); - }); - } + this.$container.addClass('select2-container--' + this.options.get('theme')); - this.$element.val(newVal).trigger('change'); - }; + $container.data('element', this.$element); - Select2.prototype.destroy = function () { - this.$container.remove(); + return $container; + }; - if (this.$element[0].detachEvent) { - this.$element[0].detachEvent('onpropertychange', this._syncA); - } + return Select2; + }); - if (this._observer != null) { - this._observer.disconnect(); - this._observer = null; - } else if (this.$element[0].removeEventListener) { - this.$element[0] - .removeEventListener('DOMAttrModified', this._syncA, false); - this.$element[0] - .removeEventListener('DOMNodeInserted', this._syncS, false); - this.$element[0] - .removeEventListener('DOMNodeRemoved', this._syncS, false); - } + S2.define('select2/compat/utils',[ + 'jquery' + ], function ($) { + function syncCssClasses ($dest, $src, adapter) { + var classes, replacements = [], adapted; - this._syncA = null; - this._syncS = null; + classes = $.trim($dest.attr('class')); - this.$element.off('.select2'); - this.$element.attr('tabindex', this.$element.data('old-tabindex')); + if (classes) { + classes = '' + classes; // for IE which returns object - this.$element.removeClass('select2-hidden-accessible'); - this.$element.attr('aria-hidden', 'false'); - this.$element.removeData('select2'); + $(classes.split(/\s+/)).each(function () { + // Save all Select2 classes + if (this.indexOf('select2-') === 0) { + replacements.push(this); + } + }); + } - this.dataAdapter.destroy(); - this.selection.destroy(); - this.dropdown.destroy(); - this.results.destroy(); + classes = $.trim($src.attr('class')); - this.dataAdapter = null; - this.selection = null; - this.dropdown = null; - this.results = null; - }; + if (classes) { + classes = '' + classes; // for IE which returns object - Select2.prototype.render = function () { - var $container = $( - '' + - '' + - '' + - '' - ); + $(classes.split(/\s+/)).each(function () { + // Only adapt non-Select2 classes + if (this.indexOf('select2-') !== 0) { + adapted = adapter(this); - $container.attr('dir', this.options.get('dir')); + if (adapted != null) { + replacements.push(adapted); + } + } + }); + } - this.$container = $container; + $dest.attr('class', replacements.join(' ')); + } - this.$container.addClass('select2-container--' + this.options.get('theme')); + return { + syncCssClasses: syncCssClasses + }; + }); - $container.data('element', this.$element); + S2.define('select2/compat/containerCss',[ + 'jquery', + './utils' + ], function ($, CompatUtils) { + // No-op CSS adapter that discards all classes by default + function _containerAdapter (clazz) { + return null; + } - return $container; - }; + function ContainerCSS () { } - return Select2; -}); + ContainerCSS.prototype.render = function (decorated) { + var $container = decorated.call(this); -S2.define('select2/compat/utils',[ - 'jquery' -], function ($) { - function syncCssClasses ($dest, $src, adapter) { - var classes, replacements = [], adapted; + var containerCssClass = this.options.get('containerCssClass') || ''; - classes = $.trim($dest.attr('class')); + if ($.isFunction(containerCssClass)) { + containerCssClass = containerCssClass(this.$element); + } - if (classes) { - classes = '' + classes; // for IE which returns object + var containerCssAdapter = this.options.get('adaptContainerCssClass'); + containerCssAdapter = containerCssAdapter || _containerAdapter; - $(classes.split(/\s+/)).each(function () { - // Save all Select2 classes - if (this.indexOf('select2-') === 0) { - replacements.push(this); - } - }); - } + if (containerCssClass.indexOf(':all:') !== -1) { + containerCssClass = containerCssClass.replace(':all:', ''); - classes = $.trim($src.attr('class')); + var _cssAdapter = containerCssAdapter; - if (classes) { - classes = '' + classes; // for IE which returns object + containerCssAdapter = function (clazz) { + var adapted = _cssAdapter(clazz); - $(classes.split(/\s+/)).each(function () { - // Only adapt non-Select2 classes - if (this.indexOf('select2-') !== 0) { - adapted = adapter(this); + if (adapted != null) { + // Append the old one along with the adapted one + return adapted + ' ' + clazz; + } - if (adapted != null) { - replacements.push(adapted); - } + return clazz; + }; } - }); - } - $dest.attr('class', replacements.join(' ')); - } + var containerCss = this.options.get('containerCss') || {}; - return { - syncCssClasses: syncCssClasses - }; -}); - -S2.define('select2/compat/containerCss',[ - 'jquery', - './utils' -], function ($, CompatUtils) { - // No-op CSS adapter that discards all classes by default - function _containerAdapter (clazz) { - return null; - } + if ($.isFunction(containerCss)) { + containerCss = containerCss(this.$element); + } - function ContainerCSS () { } + CompatUtils.syncCssClasses($container, this.$element, containerCssAdapter); - ContainerCSS.prototype.render = function (decorated) { - var $container = decorated.call(this); + $container.css(containerCss); + $container.addClass(containerCssClass); - var containerCssClass = this.options.get('containerCssClass') || ''; + return $container; + }; - if ($.isFunction(containerCssClass)) { - containerCssClass = containerCssClass(this.$element); - } + return ContainerCSS; + }); - var containerCssAdapter = this.options.get('adaptContainerCssClass'); - containerCssAdapter = containerCssAdapter || _containerAdapter; + S2.define('select2/compat/dropdownCss',[ + 'jquery', + './utils' + ], function ($, CompatUtils) { + // No-op CSS adapter that discards all classes by default + function _dropdownAdapter (clazz) { + return null; + } - if (containerCssClass.indexOf(':all:') !== -1) { - containerCssClass = containerCssClass.replace(':all:', ''); + function DropdownCSS () { } - var _cssAdapter = containerCssAdapter; + DropdownCSS.prototype.render = function (decorated) { + var $dropdown = decorated.call(this); - containerCssAdapter = function (clazz) { - var adapted = _cssAdapter(clazz); + var dropdownCssClass = this.options.get('dropdownCssClass') || ''; - if (adapted != null) { - // Append the old one along with the adapted one - return adapted + ' ' + clazz; + if ($.isFunction(dropdownCssClass)) { + dropdownCssClass = dropdownCssClass(this.$element); } - return clazz; - }; - } - - var containerCss = this.options.get('containerCss') || {}; - - if ($.isFunction(containerCss)) { - containerCss = containerCss(this.$element); - } - - CompatUtils.syncCssClasses($container, this.$element, containerCssAdapter); + var dropdownCssAdapter = this.options.get('adaptDropdownCssClass'); + dropdownCssAdapter = dropdownCssAdapter || _dropdownAdapter; - $container.css(containerCss); - $container.addClass(containerCssClass); + if (dropdownCssClass.indexOf(':all:') !== -1) { + dropdownCssClass = dropdownCssClass.replace(':all:', ''); - return $container; - }; + var _cssAdapter = dropdownCssAdapter; - return ContainerCSS; -}); + dropdownCssAdapter = function (clazz) { + var adapted = _cssAdapter(clazz); -S2.define('select2/compat/dropdownCss',[ - 'jquery', - './utils' -], function ($, CompatUtils) { - // No-op CSS adapter that discards all classes by default - function _dropdownAdapter (clazz) { - return null; - } - - function DropdownCSS () { } + if (adapted != null) { + // Append the old one along with the adapted one + return adapted + ' ' + clazz; + } - DropdownCSS.prototype.render = function (decorated) { - var $dropdown = decorated.call(this); + return clazz; + }; + } - var dropdownCssClass = this.options.get('dropdownCssClass') || ''; + var dropdownCss = this.options.get('dropdownCss') || {}; - if ($.isFunction(dropdownCssClass)) { - dropdownCssClass = dropdownCssClass(this.$element); - } + if ($.isFunction(dropdownCss)) { + dropdownCss = dropdownCss(this.$element); + } - var dropdownCssAdapter = this.options.get('adaptDropdownCssClass'); - dropdownCssAdapter = dropdownCssAdapter || _dropdownAdapter; + CompatUtils.syncCssClasses($dropdown, this.$element, dropdownCssAdapter); - if (dropdownCssClass.indexOf(':all:') !== -1) { - dropdownCssClass = dropdownCssClass.replace(':all:', ''); + $dropdown.css(dropdownCss); + $dropdown.addClass(dropdownCssClass); - var _cssAdapter = dropdownCssAdapter; + return $dropdown; + }; - dropdownCssAdapter = function (clazz) { - var adapted = _cssAdapter(clazz); + return DropdownCSS; + }); - if (adapted != null) { - // Append the old one along with the adapted one - return adapted + ' ' + clazz; + S2.define('select2/compat/initSelection',[ + 'jquery' + ], function ($) { + function InitSelection (decorated, $element, options) { + if (options.get('debug') && window.console && console.warn) { + console.warn( + 'Select2: The `initSelection` option has been deprecated in favor' + + ' of a custom data adapter that overrides the `current` method. ' + + 'This method is now called multiple times instead of a single ' + + 'time when the instance is initialized. Support will be removed ' + + 'for the `initSelection` option in future versions of Select2' + ); } - return clazz; - }; - } + this.initSelection = options.get('initSelection'); + this._isInitialized = false; - var dropdownCss = this.options.get('dropdownCss') || {}; + decorated.call(this, $element, options); + } - if ($.isFunction(dropdownCss)) { - dropdownCss = dropdownCss(this.$element); - } + InitSelection.prototype.current = function (decorated, callback) { + var self = this; - CompatUtils.syncCssClasses($dropdown, this.$element, dropdownCssAdapter); - - $dropdown.css(dropdownCss); - $dropdown.addClass(dropdownCssClass); - - return $dropdown; - }; - - return DropdownCSS; -}); - -S2.define('select2/compat/initSelection',[ - 'jquery' -], function ($) { - function InitSelection (decorated, $element, options) { - if (options.get('debug') && window.console && console.warn) { - console.warn( - 'Select2: The `initSelection` option has been deprecated in favor' + - ' of a custom data adapter that overrides the `current` method. ' + - 'This method is now called multiple times instead of a single ' + - 'time when the instance is initialized. Support will be removed ' + - 'for the `initSelection` option in future versions of Select2' - ); - } + if (this._isInitialized) { + decorated.call(this, callback); - this.initSelection = options.get('initSelection'); - this._isInitialized = false; + return; + } - decorated.call(this, $element, options); - } + this.initSelection.call(null, this.$element, function (data) { + self._isInitialized = true; - InitSelection.prototype.current = function (decorated, callback) { - var self = this; + if (!$.isArray(data)) { + data = [data]; + } - if (this._isInitialized) { - decorated.call(this, callback); + callback(data); + }); + }; - return; - } + return InitSelection; + }); - this.initSelection.call(null, this.$element, function (data) { - self._isInitialized = true; + S2.define('select2/compat/inputData',[ + 'jquery' + ], function ($) { + function InputData (decorated, $element, options) { + this._currentData = []; + this._valueSeparator = options.get('valueSeparator') || ','; + + if ($element.prop('type') === 'hidden') { + if (options.get('debug') && console && console.warn) { + console.warn( + 'Select2: Using a hidden input with Select2 is no longer ' + + 'supported and may stop working in the future. It is recommended ' + + 'to use a `` element instead.' - ); - } - } + InputData.prototype.current = function (_, callback) { + function getSelected (data, selectedIds) { + var selected = []; - decorated.call(this, $element, options); - } + if (data.selected || $.inArray(data.id, selectedIds) !== -1) { + data.selected = true; + selected.push(data); + } else { + data.selected = false; + } - InputData.prototype.current = function (_, callback) { - function getSelected (data, selectedIds) { - var selected = []; + if (data.children) { + selected.push.apply(selected, getSelected(data.children, selectedIds)); + } - if (data.selected || $.inArray(data.id, selectedIds) !== -1) { - data.selected = true; - selected.push(data); - } else { - data.selected = false; - } + return selected; + } - if (data.children) { - selected.push.apply(selected, getSelected(data.children, selectedIds)); - } + var selected = []; - return selected; - } + for (var d = 0; d < this._currentData.length; d++) { + var data = this._currentData[d]; - var selected = []; + selected.push.apply( + selected, + getSelected( + data, + this.$element.val().split( + this._valueSeparator + ) + ) + ); + } - for (var d = 0; d < this._currentData.length; d++) { - var data = this._currentData[d]; + callback(selected); + }; - selected.push.apply( - selected, - getSelected( - data, - this.$element.val().split( - this._valueSeparator - ) - ) - ); - } + InputData.prototype.select = function (_, data) { + if (!this.options.get('multiple')) { + this.current(function (allData) { + $.map(allData, function (data) { + data.selected = false; + }); + }); - callback(selected); - }; + this.$element.val(data.id); + this.$element.trigger('change'); + } else { + var value = this.$element.val(); + value += this._valueSeparator + data.id; - InputData.prototype.select = function (_, data) { - if (!this.options.get('multiple')) { - this.current(function (allData) { - $.map(allData, function (data) { - data.selected = false; - }); - }); + this.$element.val(value); + this.$element.trigger('change'); + } + }; - this.$element.val(data.id); - this.$element.trigger('change'); - } else { - var value = this.$element.val(); - value += this._valueSeparator + data.id; + InputData.prototype.unselect = function (_, data) { + var self = this; - this.$element.val(value); - this.$element.trigger('change'); - } - }; + data.selected = false; - InputData.prototype.unselect = function (_, data) { - var self = this; + this.current(function (allData) { + var values = []; - data.selected = false; + for (var d = 0; d < allData.length; d++) { + var item = allData[d]; - this.current(function (allData) { - var values = []; + if (data.id == item.id) { + continue; + } - for (var d = 0; d < allData.length; d++) { - var item = allData[d]; + values.push(item.id); + } - if (data.id == item.id) { - continue; - } + self.$element.val(values.join(self._valueSeparator)); + self.$element.trigger('change'); + }); + }; - values.push(item.id); - } + InputData.prototype.query = function (_, params, callback) { + var results = []; - self.$element.val(values.join(self._valueSeparator)); - self.$element.trigger('change'); - }); - }; + for (var d = 0; d < this._currentData.length; d++) { + var data = this._currentData[d]; - InputData.prototype.query = function (_, params, callback) { - var results = []; + var matches = this.matches(params, data); - for (var d = 0; d < this._currentData.length; d++) { - var data = this._currentData[d]; + if (matches !== null) { + results.push(matches); + } + } - var matches = this.matches(params, data); + callback({ + results: results + }); + }; - if (matches !== null) { - results.push(matches); - } - } + InputData.prototype.addOptions = function (_, $options) { + var options = $.map($options, function ($option) { + return $.data($option[0], 'data'); + }); - callback({ - results: results - }); - }; + this._currentData.push.apply(this._currentData, options); + }; - InputData.prototype.addOptions = function (_, $options) { - var options = $.map($options, function ($option) { - return $.data($option[0], 'data'); + return InputData; }); - this._currentData.push.apply(this._currentData, options); - }; + S2.define('select2/compat/matcher',[ + 'jquery' + ], function ($) { + function oldMatcher (matcher) { + function wrappedMatcher (params, data) { + var match = $.extend(true, {}, data); - return InputData; -}); + if (params.term == null || $.trim(params.term) === '') { + return match; + } -S2.define('select2/compat/matcher',[ - 'jquery' -], function ($) { - function oldMatcher (matcher) { - function wrappedMatcher (params, data) { - var match = $.extend(true, {}, data); + if (data.children) { + for (var c = data.children.length - 1; c >= 0; c--) { + var child = data.children[c]; - if (params.term == null || $.trim(params.term) === '') { - return match; - } + // Check if the child object matches + // The old matcher returned a boolean true or false + var doesMatch = matcher(params.term, child.text, child); - if (data.children) { - for (var c = data.children.length - 1; c >= 0; c--) { - var child = data.children[c]; + // If the child didn't match, pop it off + if (!doesMatch) { + match.children.splice(c, 1); + } + } - // Check if the child object matches - // The old matcher returned a boolean true or false - var doesMatch = matcher(params.term, child.text, child); + if (match.children.length > 0) { + return match; + } + } - // If the child didn't match, pop it off - if (!doesMatch) { - match.children.splice(c, 1); + if (matcher(params.term, data.text, data)) { + return match; } - } - if (match.children.length > 0) { - return match; + return null; } - } - if (matcher(params.term, data.text, data)) { - return match; + return wrappedMatcher; } - return null; - } + return oldMatcher; + }); - return wrappedMatcher; - } + S2.define('select2/compat/query',[ - return oldMatcher; -}); + ], function () { + function Query (decorated, $element, options) { + if (options.get('debug') && window.console && console.warn) { + console.warn( + 'Select2: The `query` option has been deprecated in favor of a ' + + 'custom data adapter that overrides the `query` method. Support ' + + 'will be removed for the `query` option in future versions of ' + + 'Select2.' + ); + } -S2.define('select2/compat/query',[ + decorated.call(this, $element, options); + } -], function () { - function Query (decorated, $element, options) { - if (options.get('debug') && window.console && console.warn) { - console.warn( - 'Select2: The `query` option has been deprecated in favor of a ' + - 'custom data adapter that overrides the `query` method. Support ' + - 'will be removed for the `query` option in future versions of ' + - 'Select2.' - ); - } + Query.prototype.query = function (_, params, callback) { + params.callback = callback; - decorated.call(this, $element, options); - } + var query = this.options.get('query'); - Query.prototype.query = function (_, params, callback) { - params.callback = callback; + query.call(null, params); + }; - var query = this.options.get('query'); + return Query; + }); - query.call(null, params); - }; + S2.define('select2/dropdown/attachContainer',[ - return Query; -}); + ], function () { + function AttachContainer (decorated, $element, options) { + decorated.call(this, $element, options); + } -S2.define('select2/dropdown/attachContainer',[ + AttachContainer.prototype.position = + function (decorated, $dropdown, $container) { + var $dropdownContainer = $container.find('.dropdown-wrapper'); + $dropdownContainer.append($dropdown); -], function () { - function AttachContainer (decorated, $element, options) { - decorated.call(this, $element, options); - } + $dropdown.addClass('select2-dropdown--below'); + $container.addClass('select2-container--below'); + }; - AttachContainer.prototype.position = - function (decorated, $dropdown, $container) { - var $dropdownContainer = $container.find('.dropdown-wrapper'); - $dropdownContainer.append($dropdown); - - $dropdown.addClass('select2-dropdown--below'); - $container.addClass('select2-container--below'); - }; - - return AttachContainer; -}); - -S2.define('select2/dropdown/stopPropagation',[ - -], function () { - function StopPropagation () { } - - StopPropagation.prototype.bind = function (decorated, container, $container) { - decorated.call(this, container, $container); - - var stoppedEvents = [ - 'blur', - 'change', - 'click', - 'dblclick', - 'focus', - 'focusin', - 'focusout', - 'input', - 'keydown', - 'keyup', - 'keypress', - 'mousedown', - 'mouseenter', - 'mouseleave', - 'mousemove', - 'mouseover', - 'mouseup', - 'search', - 'touchend', - 'touchstart' - ]; - - this.$dropdown.on(stoppedEvents.join(' '), function (evt) { - evt.stopPropagation(); + return AttachContainer; }); - }; - - return StopPropagation; -}); - -S2.define('select2/selection/stopPropagation',[ - -], function () { - function StopPropagation () { } - - StopPropagation.prototype.bind = function (decorated, container, $container) { - decorated.call(this, container, $container); - - var stoppedEvents = [ - 'blur', - 'change', - 'click', - 'dblclick', - 'focus', - 'focusin', - 'focusout', - 'input', - 'keydown', - 'keyup', - 'keypress', - 'mousedown', - 'mouseenter', - 'mouseleave', - 'mousemove', - 'mouseover', - 'mouseup', - 'search', - 'touchend', - 'touchstart' - ]; - - this.$selection.on(stoppedEvents.join(' '), function (evt) { - evt.stopPropagation(); + + S2.define('select2/dropdown/stopPropagation',[ + + ], function () { + function StopPropagation () { } + + StopPropagation.prototype.bind = function (decorated, container, $container) { + decorated.call(this, container, $container); + + var stoppedEvents = [ + 'blur', + 'change', + 'click', + 'dblclick', + 'focus', + 'focusin', + 'focusout', + 'input', + 'keydown', + 'keyup', + 'keypress', + 'mousedown', + 'mouseenter', + 'mouseleave', + 'mousemove', + 'mouseover', + 'mouseup', + 'search', + 'touchend', + 'touchstart' + ]; + + this.$dropdown.on(stoppedEvents.join(' '), function (evt) { + evt.stopPropagation(); + }); + }; + + return StopPropagation; }); - }; - return StopPropagation; -}); + S2.define('select2/selection/stopPropagation',[ + + ], function () { + function StopPropagation () { } + + StopPropagation.prototype.bind = function (decorated, container, $container) { + decorated.call(this, container, $container); + + var stoppedEvents = [ + 'blur', + 'change', + 'click', + 'dblclick', + 'focus', + 'focusin', + 'focusout', + 'input', + 'keydown', + 'keyup', + 'keypress', + 'mousedown', + 'mouseenter', + 'mouseleave', + 'mousemove', + 'mouseover', + 'mouseup', + 'search', + 'touchend', + 'touchstart' + ]; + + this.$selection.on(stoppedEvents.join(' '), function (evt) { + evt.stopPropagation(); + }); + }; -/*! + return StopPropagation; + }); + + /*! * jQuery Mousewheel 3.1.13 * * Copyright jQuery Foundation and other contributors @@ -6252,99 +6312,99 @@ S2.define('select2/selection/stopPropagation',[ * http://jquery.org/license */ -(function (factory) { - if ( typeof S2.define === 'function' && S2.define.amd ) { + (function (factory) { + if ( typeof S2.define === 'function' && S2.define.amd ) { // AMD. Register as an anonymous module. S2.define('jquery-mousewheel',['jquery'], factory); - } else if (typeof exports === 'object') { + } else if (typeof exports === 'object') { // Node/CommonJS style for Browserify module.exports = factory; - } else { + } else { // Browser globals factory(jQuery); - } -}(function ($) { + } + }(function ($) { - var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'], + var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'], toBind = ( 'onwheel' in document || document.documentMode >= 9 ) ? - ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'], + ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'], slice = Array.prototype.slice, nullLowestDeltaTimeout, lowestDelta; - if ( $.event.fixHooks ) { + if ( $.event.fixHooks ) { for ( var i = toFix.length; i; ) { - $.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks; + $.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks; } - } + } - var special = $.event.special.mousewheel = { + var special = $.event.special.mousewheel = { version: '3.1.12', setup: function() { - if ( this.addEventListener ) { - for ( var i = toBind.length; i; ) { - this.addEventListener( toBind[--i], handler, false ); - } - } else { - this.onmousewheel = handler; + if ( this.addEventListener ) { + for ( var i = toBind.length; i; ) { + this.addEventListener( toBind[--i], handler, false ); } - // Store the line height and page height for this particular element - $.data(this, 'mousewheel-line-height', special.getLineHeight(this)); - $.data(this, 'mousewheel-page-height', special.getPageHeight(this)); + } else { + this.onmousewheel = handler; + } + // Store the line height and page height for this particular element + $.data(this, 'mousewheel-line-height', special.getLineHeight(this)); + $.data(this, 'mousewheel-page-height', special.getPageHeight(this)); }, teardown: function() { - if ( this.removeEventListener ) { - for ( var i = toBind.length; i; ) { - this.removeEventListener( toBind[--i], handler, false ); - } - } else { - this.onmousewheel = null; + if ( this.removeEventListener ) { + for ( var i = toBind.length; i; ) { + this.removeEventListener( toBind[--i], handler, false ); } - // Clean up the data we added to the element - $.removeData(this, 'mousewheel-line-height'); - $.removeData(this, 'mousewheel-page-height'); + } else { + this.onmousewheel = null; + } + // Clean up the data we added to the element + $.removeData(this, 'mousewheel-line-height'); + $.removeData(this, 'mousewheel-page-height'); }, getLineHeight: function(elem) { - var $elem = $(elem), - $parent = $elem['offsetParent' in $.fn ? 'offsetParent' : 'parent'](); - if (!$parent.length) { - $parent = $('body'); - } - return parseInt($parent.css('fontSize'), 10) || parseInt($elem.css('fontSize'), 10) || 16; + var $elem = $(elem), + $parent = $elem['offsetParent' in $.fn ? 'offsetParent' : 'parent'](); + if (!$parent.length) { + $parent = $('body'); + } + return parseInt($parent.css('fontSize'), 10) || parseInt($elem.css('fontSize'), 10) || 16; }, getPageHeight: function(elem) { - return $(elem).height(); + return $(elem).height(); }, settings: { - adjustOldDeltas: true, // see shouldAdjustOldDeltas() below - normalizeOffset: true // calls getBoundingClientRect for each event + adjustOldDeltas: true, // see shouldAdjustOldDeltas() below + normalizeOffset: true // calls getBoundingClientRect for each event } - }; + }; - $.fn.extend({ + $.fn.extend({ mousewheel: function(fn) { - return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel'); + return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel'); }, unmousewheel: function(fn) { - return this.unbind('mousewheel', fn); + return this.unbind('mousewheel', fn); } - }); + }); - function handler(event) { + function handler(event) { var orgEvent = event || window.event, - args = slice.call(arguments, 1), - delta = 0, - deltaX = 0, - deltaY = 0, - absDelta = 0, - offsetX = 0, - offsetY = 0; + args = slice.call(arguments, 1), + delta = 0, + deltaX = 0, + deltaY = 0, + absDelta = 0, + offsetX = 0, + offsetY = 0; event = $.event.fix(orgEvent); event.type = 'mousewheel'; @@ -6356,8 +6416,8 @@ S2.define('select2/selection/stopPropagation',[ // Firefox < 17 horizontal scrolling related to DOMMouseScroll event if ( 'axis' in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) { - deltaX = deltaY * -1; - deltaY = 0; + deltaX = deltaY * -1; + deltaY = 0; } // Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy @@ -6365,12 +6425,12 @@ S2.define('select2/selection/stopPropagation',[ // New school wheel delta (wheel event) if ( 'deltaY' in orgEvent ) { - deltaY = orgEvent.deltaY * -1; - delta = deltaY; + deltaY = orgEvent.deltaY * -1; + delta = deltaY; } if ( 'deltaX' in orgEvent ) { - deltaX = orgEvent.deltaX; - if ( deltaY === 0 ) { delta = deltaX * -1; } + deltaX = orgEvent.deltaX; + if ( deltaY === 0 ) { delta = deltaX * -1; } } // No change actually happened, no reason to go any further @@ -6382,35 +6442,35 @@ S2.define('select2/selection/stopPropagation',[ // * deltaMode 1 is by lines // * deltaMode 2 is by pages if ( orgEvent.deltaMode === 1 ) { - var lineHeight = $.data(this, 'mousewheel-line-height'); - delta *= lineHeight; - deltaY *= lineHeight; - deltaX *= lineHeight; + var lineHeight = $.data(this, 'mousewheel-line-height'); + delta *= lineHeight; + deltaY *= lineHeight; + deltaX *= lineHeight; } else if ( orgEvent.deltaMode === 2 ) { - var pageHeight = $.data(this, 'mousewheel-page-height'); - delta *= pageHeight; - deltaY *= pageHeight; - deltaX *= pageHeight; + var pageHeight = $.data(this, 'mousewheel-page-height'); + delta *= pageHeight; + deltaY *= pageHeight; + deltaX *= pageHeight; } // Store lowest absolute delta to normalize the delta values absDelta = Math.max( Math.abs(deltaY), Math.abs(deltaX) ); if ( !lowestDelta || absDelta < lowestDelta ) { - lowestDelta = absDelta; + lowestDelta = absDelta; - // Adjust older deltas if necessary - if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) { - lowestDelta /= 40; - } + // Adjust older deltas if necessary + if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) { + lowestDelta /= 40; + } } // Adjust older deltas if necessary if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) { - // Divide all the things by 40! - delta /= 40; - deltaX /= 40; - deltaY /= 40; + // Divide all the things by 40! + delta /= 40; + deltaX /= 40; + deltaY /= 40; } // Get a whole, normalized value for the deltas @@ -6420,9 +6480,9 @@ S2.define('select2/selection/stopPropagation',[ // Normalise offsetX and offsetY properties if ( special.settings.normalizeOffset && this.getBoundingClientRect ) { - var boundingRect = this.getBoundingClientRect(); - offsetX = event.clientX - boundingRect.left; - offsetY = event.clientY - boundingRect.top; + var boundingRect = this.getBoundingClientRect(); + offsetX = event.clientX - boundingRect.left; + offsetY = event.clientY - boundingRect.top; } // Add information to the event object @@ -6447,13 +6507,13 @@ S2.define('select2/selection/stopPropagation',[ nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200); return ($.event.dispatch || $.event.handle).apply(this, args); - } + } - function nullLowestDelta() { + function nullLowestDelta() { lowestDelta = null; - } + } - function shouldAdjustOldDeltas(orgEvent, absDelta) { + function shouldAdjustOldDeltas(orgEvent, absDelta) { // If this is an older event and the delta is divisable by 120, // then we are assuming that the browser is treating this as an // older mouse wheel event and that we should divide the deltas @@ -6462,81 +6522,81 @@ S2.define('select2/selection/stopPropagation',[ // in older browsers and can cause scrolling to be slower than native. // Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false. return special.settings.adjustOldDeltas && orgEvent.type === 'mousewheel' && absDelta % 120 === 0; - } + } -})); + })); -S2.define('jquery.select2',[ - 'jquery', - 'jquery-mousewheel', + S2.define('jquery.select2',[ + 'jquery', + 'jquery-mousewheel', - './select2/core', - './select2/defaults' -], function ($, _, Select2, Defaults) { - if ($.fn.selectWoo == null) { - // All methods that should return the element - var thisMethods = ['open', 'close', 'destroy']; + './select2/core', + './select2/defaults' + ], function ($, _, Select2, Defaults) { + if ($.fn.selectWoo == null) { + // All methods that should return the element + var thisMethods = ['open', 'close', 'destroy']; - $.fn.selectWoo = function (options) { - options = options || {}; + $.fn.selectWoo = function (options) { + options = options || {}; - if (typeof options === 'object') { - this.each(function () { - var instanceOptions = $.extend(true, {}, options); + if (typeof options === 'object') { + this.each(function () { + var instanceOptions = $.extend(true, {}, options); - var instance = new Select2($(this), instanceOptions); - }); + var instance = new Select2($(this), instanceOptions); + }); - return this; - } else if (typeof options === 'string') { - var ret; - var args = Array.prototype.slice.call(arguments, 1); + 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'); + this.each(function () { + var instance = $(this).data('select2'); - if (instance == null && window.console && console.error) { - console.error( - 'The select2(\'' + options + '\') method was called on an ' + - 'element that is not using Select2.' - ); - } + if (instance == null && window.console && console.error) { + console.error( + 'The select2(\'' + options + '\') method was called on an ' + + 'element that is not using Select2.' + ); + } - ret = instance[options].apply(instance, args); - }); + ret = instance[options].apply(instance, args); + }); - // Check if we should be returning `this` - if ($.inArray(options, thisMethods) > -1) { - return this; - } + // Check if we should be returning `this` + if ($.inArray(options, thisMethods) > -1) { + return this; + } - return ret; - } else { - throw new Error('Invalid arguments for Select2: ' + options); + return ret; + } else { + throw new Error('Invalid arguments for Select2: ' + options); + } + }; } - }; - } - if ($.fn.select2 != null && $.fn.select2.defaults != null) { - $.fn.selectWoo.defaults = $.fn.select2.defaults; - } + if ($.fn.select2 != null && $.fn.select2.defaults != null) { + $.fn.selectWoo.defaults = $.fn.select2.defaults; + } - if ($.fn.selectWoo.defaults == null) { - $.fn.selectWoo.defaults = Defaults; - } + if ($.fn.selectWoo.defaults == null) { + $.fn.selectWoo.defaults = Defaults; + } - // Also register selectWoo under select2 if select2 is not already present. - $.fn.select2 = $.fn.select2 || $.fn.selectWoo; + // Also register selectWoo under select2 if select2 is not already present. + $.fn.select2 = $.fn.select2 || $.fn.selectWoo; - return Select2; -}); + return Select2; + }); - // Return the AMD loader configuration so it can be used outside of this file - return { - define: S2.define, - require: S2.require - }; -}()); + // Return the AMD loader configuration so it can be used outside of this file + return { + define: S2.define, + require: S2.require + }; + }()); // Autoload the jQuery bindings // We know that all of the modules exist above this, so we're safe diff --git a/package.json b/package.json index f2a69870a8..d36ba1a401 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "src", "dist" ], - "version": "1.0.10", + "version": "1.0.11", "jspm": { "main": "js/select2", "directories": { diff --git a/src/js/select2/options.js b/src/js/select2/options.js index 3e48deea50..cb702e217d 100644 --- a/src/js/select2/options.js +++ b/src/js/select2/options.js @@ -34,6 +34,10 @@ define([ this.options.disabled = $e.prop('disabled'); } + if (!this.options.required) { + this.options.required = $e.prop('required'); + } + if (this.options.language == null) { if ($e.prop('lang')) { this.options.language = $e.prop('lang').toLowerCase(); diff --git a/src/js/select2/selection/base.js b/src/js/select2/selection/base.js index 96702b2917..37bc4fdab5 100644 --- a/src/js/select2/selection/base.js +++ b/src/js/select2/selection/base.js @@ -41,9 +41,14 @@ define([ var id = container.id + '-container'; var resultsId = container.id + '-results'; var searchHidden = this.options.get('minimumResultsForSearch') === Infinity; + var isRequired = this.options.get('required') === true; this.container = container; + if (isRequired) { + this.$selection.attr('aria-required', 'true') + } + this.$selection.on('focus', function (evt) { self.trigger('focus', evt); }); diff --git a/src/js/select2/selection/single.js b/src/js/select2/selection/single.js index 6aba2c0183..49d3493258 100644 --- a/src/js/select2/selection/single.js +++ b/src/js/select2/selection/single.js @@ -30,6 +30,11 @@ define([ SingleSelection.__super__.bind.apply(this, arguments); + var isRequired = this.options.get('required') === true; + if (isRequired) { + this.$selection.find('.select2-selection__rendered').attr('aria-required', 'true') + } + var id = container.id + '-container'; this.$selection.find('.select2-selection__rendered')