3
* https://select2.github.io
5
* Released under the MIT license
6
* https://github.com/select2/select2/blob/master/LICENSE.md
9
if (typeof define === 'function' && define.amd) {
10
// AMD. Register as an anonymous module.
11
define(['jquery'], factory);
12
} else if (typeof module === 'object' && module.exports) {
14
module.exports = function (root, jQuery) {
15
if (jQuery === undefined) {
16
// require('jQuery') returns a factory that requires window to
17
// build a jQuery instance, we normalize how we use modules
18
// that require this pattern but the window provided is a noop
19
// if it's defined (how jquery works)
20
if (typeof window !== 'undefined') {
21
jQuery = require('jquery');
24
jQuery = require('jquery')(root);
34
} (function (jQuery) {
35
// This is needed so we can catch the AMD loader configuration and use it
36
// The inner file should be wrapped (by `banner.start.js`) in a function that
37
// returns the AMD loader references.
38
var S2 =(function () {
39
// Restore the Select2 AMD loader so it can be used
40
// Needed mostly in the language files, where the loader is not inserted
41
if (jQuery && jQuery.fn && jQuery.fn.select2 && jQuery.fn.select2.amd) {
42
var S2 = jQuery.fn.select2.amd;
44
var S2;(function () { if (!S2 || !S2.requirejs) {
45
if (!S2) { S2 = {}; } else { require = S2; }
47
* @license almond 0.3.3 Copyright jQuery Foundation and other contributors.
48
* Released under MIT license, http://github.com/requirejs/almond/LICENSE
50
//Going sloppy to avoid 'use strict' string cost, but strict practices should
52
/*global setTimeout: false */
54
var requirejs, require, define;
56
var main, req, makeMap, handlers,
61
hasOwn = Object.prototype.hasOwnProperty,
63
jsSuffixRegExp = /\.js$/;
65
function hasProp(obj, prop) {
66
return hasOwn.call(obj, prop);
70
* Given a relative module name, like ./something, normalize it to
71
* a real name that can be mapped to a path.
72
* @param {String} name the relative name
73
* @param {String} baseName a real name that the name arg is relative
75
* @returns {String} normalized name
77
function normalize(name, baseName) {
78
var nameParts, nameSegment, mapValue, foundMap, lastIndex,
79
foundI, foundStarMap, starI, i, j, part, normalizedBaseParts,
80
baseParts = baseName && baseName.split("/"),
82
starMap = (map && map['*']) || {};
84
//Adjust any relative paths.
86
name = name.split('/');
87
lastIndex = name.length - 1;
89
// If wanting node ID compatibility, strip .js from end
90
// of IDs. Have to do this here, and not in nameToUrl
91
// because node allows either .js or non .js to map
93
if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
94
name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
97
// Starts with a '.' so need the baseName
98
if (name[0].charAt(0) === '.' && baseParts) {
99
//Convert baseName to array, and lop off the last part,
100
//so that . matches that 'directory' and not name of the baseName's
101
//module. For instance, baseName of 'one/two/three', maps to
102
//'one/two/three.js', but we want the directory, 'one/two' for
103
//this normalization.
104
normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
105
name = normalizedBaseParts.concat(name);
109
for (i = 0; i < name.length; i++) {
114
} else if (part === '..') {
115
// If at the start, or previous value is still ..,
116
// keep them so that when converted to a path it may
117
// still work when converted to a path, even though
118
// as an ID it is less than ideal. In larger point
119
// releases, may be better to just kick out an error.
120
if (i === 0 || (i === 1 && name[2] === '..') || name[i - 1] === '..') {
123
name.splice(i - 1, 2);
130
name = name.join('/');
133
//Apply map config if available.
134
if ((baseParts || starMap) && map) {
135
nameParts = name.split('/');
137
for (i = nameParts.length; i > 0; i -= 1) {
138
nameSegment = nameParts.slice(0, i).join("/");
141
//Find the longest baseName segment match in the config.
142
//So, do joins on the biggest to smallest lengths of baseParts.
143
for (j = baseParts.length; j > 0; j -= 1) {
144
mapValue = map[baseParts.slice(0, j).join('/')];
146
//baseName segment has config, find if it has one for
149
mapValue = mapValue[nameSegment];
151
//Match, update name to the new value.
164
//Check for a star map match, but just hold on to it,
165
//if there is a shorter segment match later in a matching
166
//config, then favor over this star map.
167
if (!foundStarMap && starMap && starMap[nameSegment]) {
168
foundStarMap = starMap[nameSegment];
173
if (!foundMap && foundStarMap) {
174
foundMap = foundStarMap;
179
nameParts.splice(0, foundI, foundMap);
180
name = nameParts.join('/');
187
function makeRequire(relName, forceSync) {
189
//A version of a require function that passes a moduleName
190
//value for items that may need to
191
//look up paths relative to the moduleName
192
var args = aps.call(arguments, 0);
194
//If first arg is not require('string'), and there is only
195
//one arg, it is the array form without a callback. Insert
196
//a null so that the following concat is correct.
197
if (typeof args[0] !== 'string' && args.length === 1) {
200
return req.apply(undef, args.concat([relName, forceSync]));
204
function makeNormalize(relName) {
205
return function (name) {
206
return normalize(name, relName);
210
function makeLoad(depName) {
211
return function (value) {
212
defined[depName] = value;
216
function callDep(name) {
217
if (hasProp(waiting, name)) {
218
var args = waiting[name];
219
delete waiting[name];
220
defining[name] = true;
221
main.apply(undef, args);
224
if (!hasProp(defined, name) && !hasProp(defining, name)) {
225
throw new Error('No ' + name);
227
return defined[name];
230
//Turns a plugin!resource to [plugin, resource]
231
//with the plugin being undefined if the name
232
//did not have a plugin prefix.
233
function splitPrefix(name) {
235
index = name ? name.indexOf('!') : -1;
237
prefix = name.substring(0, index);
238
name = name.substring(index + 1, name.length);
240
return [prefix, name];
243
//Creates a parts array for a relName where first part is plugin ID,
244
//second part is resource ID. Assumes relName has already been normalized.
245
function makeRelParts(relName) {
246
return relName ? splitPrefix(relName) : [];
250
* Makes a name map, normalizing the name, and using a plugin
251
* for normalization if necessary. Grabs a ref to plugin
252
* too, as an optimization.
254
makeMap = function (name, relParts) {
256
parts = splitPrefix(name),
258
relResourceName = relParts[1];
263
prefix = normalize(prefix, relResourceName);
264
plugin = callDep(prefix);
267
//Normalize according
269
if (plugin && plugin.normalize) {
270
name = plugin.normalize(name, makeNormalize(relResourceName));
272
name = normalize(name, relResourceName);
275
name = normalize(name, relResourceName);
276
parts = splitPrefix(name);
280
plugin = callDep(prefix);
284
//Using ridiculous property names for space reasons
286
f: prefix ? prefix + '!' + name : name, //fullName
293
function makeConfig(name) {
295
return (config && config.config && config.config[name]) || {};
300
require: function (name) {
301
return makeRequire(name);
303
exports: function (name) {
304
var e = defined[name];
305
if (typeof e !== 'undefined') {
308
return (defined[name] = {});
311
module: function (name) {
315
exports: defined[name],
316
config: makeConfig(name)
321
main = function (name, deps, callback, relName) {
322
var cjsModule, depName, ret, map, i, relParts,
324
callbackType = typeof callback,
327
//Use name if no relName
328
relName = relName || name;
329
relParts = makeRelParts(relName);
331
//Call the callback to define the module, if necessary.
332
if (callbackType === 'undefined' || callbackType === 'function') {
333
//Pull out the defined dependencies and pass the ordered
334
//values to the callback.
335
//Default to [require, exports, module] if no deps
336
deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
337
for (i = 0; i < deps.length; i += 1) {
338
map = makeMap(deps[i], relParts);
341
//Fast path CommonJS standard dependencies.
342
if (depName === "require") {
343
args[i] = handlers.require(name);
344
} else if (depName === "exports") {
345
//CommonJS module spec 1.1
346
args[i] = handlers.exports(name);
348
} else if (depName === "module") {
349
//CommonJS module spec 1.1
350
cjsModule = args[i] = handlers.module(name);
351
} else if (hasProp(defined, depName) ||
352
hasProp(waiting, depName) ||
353
hasProp(defining, depName)) {
354
args[i] = callDep(depName);
356
map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
357
args[i] = defined[depName];
359
throw new Error(name + ' missing ' + depName);
363
ret = callback ? callback.apply(defined[name], args) : undefined;
366
//If setting exports via "module" is in play,
367
//favor that over return value and exports. After that,
368
//favor a non-undefined return value over exports use.
369
if (cjsModule && cjsModule.exports !== undef &&
370
cjsModule.exports !== defined[name]) {
371
defined[name] = cjsModule.exports;
372
} else if (ret !== undef || !usingExports) {
373
//Use the return value from the function.
378
//May just be an object definition for the module. Only
379
//worry about defining if have a module name.
380
defined[name] = callback;
384
requirejs = require = req = function (deps, callback, relName, forceSync, alt) {
385
if (typeof deps === "string") {
386
if (handlers[deps]) {
387
//callback in this case is really relName
388
return handlers[deps](callback);
390
//Just return the module wanted. In this scenario, the
391
//deps arg is the module name, and second arg (if passed)
392
//is just the relName.
393
//Normalize module name, if it contains . or ..
394
return callDep(makeMap(deps, makeRelParts(callback)).f);
395
} else if (!deps.splice) {
396
//deps is a config object, not an array.
399
req(config.deps, config.callback);
405
if (callback.splice) {
406
//callback is an array, which means it is a dependency list.
407
//Adjust args if there are dependencies
416
//Support require(['a'])
417
callback = callback || function () {};
419
//If relName is a function, it is an errback handler,
421
if (typeof relName === 'function') {
426
//Simulate async callback;
428
main(undef, deps, callback, relName);
430
//Using a non-zero value because of concern for what old browsers
431
//do, and latest browsers "upgrade" to 4 if lower value is used:
432
//http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:
433
//If want a value immediately, use require('id') instead -- something
434
//that works in almond on the global level, but not guaranteed and
435
//unlikely to work in other AMD implementations.
436
setTimeout(function () {
437
main(undef, deps, callback, relName);
445
* Just drops the config on the floor, but returns req in case
446
* the config return value is used.
448
req.config = function (cfg) {
453
* Expose module registry for debugging and tooling
455
requirejs._defined = defined;
457
define = function (name, deps, callback) {
458
if (typeof name !== 'string') {
459
throw new Error('See almond README: incorrect module build, no module name');
462
//This module may not have dependencies
464
//deps is not an array, so probably means
465
//an object literal or factory function for
466
//the value. Adjust args.
471
if (!hasProp(defined, name) && !hasProp(waiting, name)) {
472
waiting[name] = [name, deps, callback];
481
S2.requirejs = requirejs;S2.require = require;S2.define = define;
484
S2.define("almond", function(){});
486
/* global jQuery:false, $:false */
487
S2.define('jquery',[],function () {
488
var _$ = jQuery || $;
490
if (_$ == null && console && console.error) {
492
'Select2: An instance of jQuery or a jQuery-compatible library was not ' +
493
'found. Make sure that you are including jQuery before Select2 on your ' +
501
S2.define('select2/utils',[
506
Utils.Extend = function (ChildClass, SuperClass) {
507
var __hasProp = {}.hasOwnProperty;
509
function BaseConstructor () {
510
this.constructor = ChildClass;
513
for (var key in SuperClass) {
514
if (__hasProp.call(SuperClass, key)) {
515
ChildClass[key] = SuperClass[key];
519
BaseConstructor.prototype = SuperClass.prototype;
520
ChildClass.prototype = new BaseConstructor();
521
ChildClass.__super__ = SuperClass.prototype;
526
function getMethods (theClass) {
527
var proto = theClass.prototype;
531
for (var methodName in proto) {
532
var m = proto[methodName];
534
if (typeof m !== 'function') {
538
if (methodName === 'constructor') {
542
methods.push(methodName);
548
Utils.Decorate = function (SuperClass, DecoratorClass) {
549
var decoratedMethods = getMethods(DecoratorClass);
550
var superMethods = getMethods(SuperClass);
552
function DecoratedClass () {
553
var unshift = Array.prototype.unshift;
555
var argCount = DecoratorClass.prototype.constructor.length;
557
var calledConstructor = SuperClass.prototype.constructor;
560
unshift.call(arguments, SuperClass.prototype.constructor);
562
calledConstructor = DecoratorClass.prototype.constructor;
565
calledConstructor.apply(this, arguments);
568
DecoratorClass.displayName = SuperClass.displayName;
571
this.constructor = DecoratedClass;
574
DecoratedClass.prototype = new ctr();
576
for (var m = 0; m < superMethods.length; m++) {
577
var superMethod = superMethods[m];
579
DecoratedClass.prototype[superMethod] =
580
SuperClass.prototype[superMethod];
583
var calledMethod = function (methodName) {
584
// Stub out the original method if it's not decorating an actual method
585
var originalMethod = function () {};
587
if (methodName in DecoratedClass.prototype) {
588
originalMethod = DecoratedClass.prototype[methodName];
591
var decoratedMethod = DecoratorClass.prototype[methodName];
594
var unshift = Array.prototype.unshift;
596
unshift.call(arguments, originalMethod);
598
return decoratedMethod.apply(this, arguments);
602
for (var d = 0; d < decoratedMethods.length; d++) {
603
var decoratedMethod = decoratedMethods[d];
605
DecoratedClass.prototype[decoratedMethod] = calledMethod(decoratedMethod);
608
return DecoratedClass;
611
var Observable = function () {
615
Observable.prototype.on = function (event, callback) {
616
this.listeners = this.listeners || {};
618
if (event in this.listeners) {
619
this.listeners[event].push(callback);
621
this.listeners[event] = [callback];
625
Observable.prototype.trigger = function (event) {
626
var slice = Array.prototype.slice;
627
var params = slice.call(arguments, 1);
629
this.listeners = this.listeners || {};
631
// Params should always come in as an array
632
if (params == null) {
636
// If there are no arguments to the event, use a temporary object
637
if (params.length === 0) {
641
// Set the `_type` of the first object to the event
642
params[0]._type = event;
644
if (event in this.listeners) {
645
this.invoke(this.listeners[event], slice.call(arguments, 1));
648
if ('*' in this.listeners) {
649
this.invoke(this.listeners['*'], arguments);
653
Observable.prototype.invoke = function (listeners, params) {
654
for (var i = 0, len = listeners.length; i < len; i++) {
655
listeners[i].apply(this, params);
659
Utils.Observable = Observable;
661
Utils.generateChars = function (length) {
664
for (var i = 0; i < length; i++) {
665
var randomChar = Math.floor(Math.random() * 36);
666
chars += randomChar.toString(36);
672
Utils.bind = function (func, context) {
674
func.apply(context, arguments);
678
Utils._convertData = function (data) {
679
for (var originalKey in data) {
680
var keys = originalKey.split('-');
682
var dataLevel = data;
684
if (keys.length === 1) {
688
for (var k = 0; k < keys.length; k++) {
691
// Lowercase the first letter
692
// By default, dash-separated becomes camelCase
693
key = key.substring(0, 1).toLowerCase() + key.substring(1);
695
if (!(key in dataLevel)) {
699
if (k == keys.length - 1) {
700
dataLevel[key] = data[originalKey];
703
dataLevel = dataLevel[key];
706
delete data[originalKey];
712
Utils.hasScroll = function (index, el) {
713
// Adapted from the function created by @ShadowScripter
714
// and adapted by @BillBarry on the Stack Exchange Code Review website.
715
// The original code can be found at
716
// http://codereview.stackexchange.com/q/13338
717
// and was designed to be used with the Sizzle selector engine.
720
var overflowX = el.style.overflowX;
721
var overflowY = el.style.overflowY;
723
//Check both x and y declarations
724
if (overflowX === overflowY &&
725
(overflowY === 'hidden' || overflowY === 'visible')) {
729
if (overflowX === 'scroll' || overflowY === 'scroll') {
733
return ($el.innerHeight() < el.scrollHeight ||
734
$el.innerWidth() < el.scrollWidth);
737
Utils.escapeMarkup = function (markup) {
748
// Do not try to escape the markup if it's not a string
749
if (typeof markup !== 'string') {
753
return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
754
return replaceMap[match];
758
// Append an array of jQuery nodes to a given element.
759
Utils.appendMany = function ($element, $nodes) {
760
// jQuery 1.7.x does not support $.fn.append() with an array
761
// Fall back to a jQuery object collection using $.fn.add()
762
if ($.fn.jquery.substr(0, 3) === '1.7') {
765
$.map($nodes, function (node) {
766
$jqNodes = $jqNodes.add(node);
772
$element.append($nodes);
778
S2.define('select2/results',[
781
], function ($, Utils) {
782
function Results ($element, options, dataAdapter) {
783
this.$element = $element;
784
this.data = dataAdapter;
785
this.options = options;
787
Results.__super__.constructor.call(this);
790
Utils.Extend(Results, Utils.Observable);
792
Results.prototype.render = function () {
794
'<ul class="select2-results__options" role="tree"></ul>'
797
if (this.options.get('multiple')) {
798
$results.attr('aria-multiselectable', 'true');
801
this.$results = $results;
806
Results.prototype.clear = function () {
807
this.$results.empty();
810
Results.prototype.displayMessage = function (params) {
811
var escapeMarkup = this.options.get('escapeMarkup');
817
'<li role="treeitem" aria-live="assertive"' +
818
' class="select2-results__option"></li>'
821
var message = this.options.get('translations').get(params.message);
829
$message[0].className += ' select2-results__message';
831
this.$results.append($message);
834
Results.prototype.hideMessages = function () {
835
this.$results.find('.select2-results__message').remove();
838
Results.prototype.append = function (data) {
843
if (data.results == null || data.results.length === 0) {
844
if (this.$results.children().length === 0) {
845
this.trigger('results:message', {
853
data.results = this.sort(data.results);
855
for (var d = 0; d < data.results.length; d++) {
856
var item = data.results[d];
858
var $option = this.option(item);
860
$options.push($option);
863
this.$results.append($options);
866
Results.prototype.position = function ($results, $dropdown) {
867
var $resultsContainer = $dropdown.find('.select2-results');
868
$resultsContainer.append($results);
871
Results.prototype.sort = function (data) {
872
var sorter = this.options.get('sorter');
877
Results.prototype.highlightFirstItem = function () {
878
var $options = this.$results
879
.find('.select2-results__option[aria-selected]');
881
var $selected = $options.filter('[aria-selected=true]');
883
// Check if there are any selected options
884
if ($selected.length > 0) {
885
// If there are selected options, highlight the first
886
$selected.first().trigger('mouseenter');
888
// If there are no selected options, highlight the first option
890
$options.first().trigger('mouseenter');
893
this.ensureHighlightVisible();
896
Results.prototype.setClasses = function () {
899
this.data.current(function (selected) {
900
var selectedIds = $.map(selected, function (s) {
901
return s.id.toString();
904
var $options = self.$results
905
.find('.select2-results__option[aria-selected]');
907
$options.each(function () {
908
var $option = $(this);
910
var item = $.data(this, 'data');
912
// id needs to be converted to a string when comparing
913
var id = '' + item.id;
915
if ((item.element != null && item.element.selected) ||
916
(item.element == null && $.inArray(id, selectedIds) > -1)) {
917
$option.attr('aria-selected', 'true');
919
$option.attr('aria-selected', 'false');
926
Results.prototype.showLoading = function (params) {
929
var loadingMore = this.options.get('translations').get('searching');
934
text: loadingMore(params)
936
var $loading = this.option(loading);
937
$loading.className += ' loading-results';
939
this.$results.prepend($loading);
942
Results.prototype.hideLoading = function () {
943
this.$results.find('.loading-results').remove();
946
Results.prototype.option = function (data) {
947
var option = document.createElement('li');
948
option.className = 'select2-results__option';
952
'aria-selected': 'false'
956
delete attrs['aria-selected'];
957
attrs['aria-disabled'] = 'true';
960
if (data.id == null) {
961
delete attrs['aria-selected'];
964
if (data._resultId != null) {
965
option.id = data._resultId;
969
option.title = data.title;
973
attrs.role = 'group';
974
attrs['aria-label'] = data.text;
975
delete attrs['aria-selected'];
978
for (var attr in attrs) {
979
var val = attrs[attr];
981
option.setAttribute(attr, val);
985
var $option = $(option);
987
var label = document.createElement('strong');
988
label.className = 'select2-results__group';
990
var $label = $(label);
991
this.template(data, label);
995
for (var c = 0; c < data.children.length; c++) {
996
var child = data.children[c];
998
var $child = this.option(child);
1000
$children.push($child);
1003
var $childrenContainer = $('<ul></ul>', {
1004
'class': 'select2-results__options select2-results__options--nested'
1007
$childrenContainer.append($children);
1009
$option.append(label);
1010
$option.append($childrenContainer);
1012
this.template(data, option);
1015
$.data(option, 'data', data);
1020
Results.prototype.bind = function (container, $container) {
1023
var id = container.id + '-results';
1025
this.$results.attr('id', id);
1027
container.on('results:all', function (params) {
1029
self.append(params.data);
1031
if (container.isOpen()) {
1033
self.highlightFirstItem();
1037
container.on('results:append', function (params) {
1038
self.append(params.data);
1040
if (container.isOpen()) {
1045
container.on('query', function (params) {
1046
self.hideMessages();
1047
self.showLoading(params);
1050
container.on('select', function () {
1051
if (!container.isOpen()) {
1056
self.highlightFirstItem();
1059
container.on('unselect', function () {
1060
if (!container.isOpen()) {
1065
self.highlightFirstItem();
1068
container.on('open', function () {
1069
// When the dropdown is open, aria-expended="true"
1070
self.$results.attr('aria-expanded', 'true');
1071
self.$results.attr('aria-hidden', 'false');
1074
self.ensureHighlightVisible();
1077
container.on('close', function () {
1078
// When the dropdown is closed, aria-expended="false"
1079
self.$results.attr('aria-expanded', 'false');
1080
self.$results.attr('aria-hidden', 'true');
1081
self.$results.removeAttr('aria-activedescendant');
1084
container.on('results:toggle', function () {
1085
var $highlighted = self.getHighlightedResults();
1087
if ($highlighted.length === 0) {
1091
$highlighted.trigger('mouseup');
1094
container.on('results:select', function () {
1095
var $highlighted = self.getHighlightedResults();
1097
if ($highlighted.length === 0) {
1101
var data = $highlighted.data('data');
1103
if ($highlighted.attr('aria-selected') == 'true') {
1104
self.trigger('close', {});
1106
self.trigger('select', {
1112
container.on('results:previous', function () {
1113
var $highlighted = self.getHighlightedResults();
1115
var $options = self.$results.find('[aria-selected]');
1117
var currentIndex = $options.index($highlighted);
1119
// If we are already at te top, don't move further
1120
if (currentIndex === 0) {
1124
var nextIndex = currentIndex - 1;
1126
// If none are highlighted, highlight the first
1127
if ($highlighted.length === 0) {
1131
var $next = $options.eq(nextIndex);
1133
$next.trigger('mouseenter');
1135
var currentOffset = self.$results.offset().top;
1136
var nextTop = $next.offset().top;
1137
var nextOffset = self.$results.scrollTop() + (nextTop - currentOffset);
1139
if (nextIndex === 0) {
1140
self.$results.scrollTop(0);
1141
} else if (nextTop - currentOffset < 0) {
1142
self.$results.scrollTop(nextOffset);
1146
container.on('results:next', function () {
1147
var $highlighted = self.getHighlightedResults();
1149
var $options = self.$results.find('[aria-selected]');
1151
var currentIndex = $options.index($highlighted);
1153
var nextIndex = currentIndex + 1;
1155
// If we are at the last option, stay there
1156
if (nextIndex >= $options.length) {
1160
var $next = $options.eq(nextIndex);
1162
$next.trigger('mouseenter');
1164
var currentOffset = self.$results.offset().top +
1165
self.$results.outerHeight(false);
1166
var nextBottom = $next.offset().top + $next.outerHeight(false);
1167
var nextOffset = self.$results.scrollTop() + nextBottom - currentOffset;
1169
if (nextIndex === 0) {
1170
self.$results.scrollTop(0);
1171
} else if (nextBottom > currentOffset) {
1172
self.$results.scrollTop(nextOffset);
1176
container.on('results:focus', function (params) {
1177
params.element.addClass('select2-results__option--highlighted');
1180
container.on('results:message', function (params) {
1181
self.displayMessage(params);
1184
if ($.fn.mousewheel) {
1185
this.$results.on('mousewheel', function (e) {
1186
var top = self.$results.scrollTop();
1188
var bottom = self.$results.get(0).scrollHeight - top + e.deltaY;
1190
var isAtTop = e.deltaY > 0 && top - e.deltaY <= 0;
1191
var isAtBottom = e.deltaY < 0 && bottom <= self.$results.height();
1194
self.$results.scrollTop(0);
1197
e.stopPropagation();
1198
} else if (isAtBottom) {
1199
self.$results.scrollTop(
1200
self.$results.get(0).scrollHeight - self.$results.height()
1204
e.stopPropagation();
1209
this.$results.on('mouseup', '.select2-results__option[aria-selected]',
1211
var $this = $(this);
1213
var data = $this.data('data');
1215
if ($this.attr('aria-selected') === 'true') {
1216
if (self.options.get('multiple')) {
1217
self.trigger('unselect', {
1222
self.trigger('close', {});
1228
self.trigger('select', {
1234
this.$results.on('mouseenter', '.select2-results__option[aria-selected]',
1236
var data = $(this).data('data');
1238
self.getHighlightedResults()
1239
.removeClass('select2-results__option--highlighted');
1241
self.trigger('results:focus', {
1248
Results.prototype.getHighlightedResults = function () {
1249
var $highlighted = this.$results
1250
.find('.select2-results__option--highlighted');
1252
return $highlighted;
1255
Results.prototype.destroy = function () {
1256
this.$results.remove();
1259
Results.prototype.ensureHighlightVisible = function () {
1260
var $highlighted = this.getHighlightedResults();
1262
if ($highlighted.length === 0) {
1266
var $options = this.$results.find('[aria-selected]');
1268
var currentIndex = $options.index($highlighted);
1270
var currentOffset = this.$results.offset().top;
1271
var nextTop = $highlighted.offset().top;
1272
var nextOffset = this.$results.scrollTop() + (nextTop - currentOffset);
1274
var offsetDelta = nextTop - currentOffset;
1275
nextOffset -= $highlighted.outerHeight(false) * 2;
1277
if (currentIndex <= 2) {
1278
this.$results.scrollTop(0);
1279
} else if (offsetDelta > this.$results.outerHeight() || offsetDelta < 0) {
1280
this.$results.scrollTop(nextOffset);
1284
Results.prototype.template = function (result, container) {
1285
var template = this.options.get('templateResult');
1286
var escapeMarkup = this.options.get('escapeMarkup');
1288
var content = template(result, container);
1290
if (content == null) {
1291
container.style.display = 'none';
1292
} else if (typeof content === 'string') {
1293
container.innerHTML = escapeMarkup(content);
1295
$(container).append(content);
1302
S2.define('select2/keys',[
1328
S2.define('select2/selection/base',[
1332
], function ($, Utils, KEYS) {
1333
function BaseSelection ($element, options) {
1334
this.$element = $element;
1335
this.options = options;
1337
BaseSelection.__super__.constructor.call(this);
1340
Utils.Extend(BaseSelection, Utils.Observable);
1342
BaseSelection.prototype.render = function () {
1344
'<span class="select2-selection" role="combobox" ' +
1345
' aria-haspopup="true" aria-expanded="false">' +
1351
if (this.$element.data('old-tabindex') != null) {
1352
this._tabindex = this.$element.data('old-tabindex');
1353
} else if (this.$element.attr('tabindex') != null) {
1354
this._tabindex = this.$element.attr('tabindex');
1357
$selection.attr('title', this.$element.attr('title'));
1358
$selection.attr('tabindex', this._tabindex);
1360
this.$selection = $selection;
1365
BaseSelection.prototype.bind = function (container, $container) {
1368
var id = container.id + '-container';
1369
var resultsId = container.id + '-results';
1371
this.container = container;
1373
this.$selection.on('focus', function (evt) {
1374
self.trigger('focus', evt);
1377
this.$selection.on('blur', function (evt) {
1378
self._handleBlur(evt);
1381
this.$selection.on('keydown', function (evt) {
1382
self.trigger('keypress', evt);
1384
if (evt.which === KEYS.SPACE) {
1385
evt.preventDefault();
1389
container.on('results:focus', function (params) {
1390
self.$selection.attr('aria-activedescendant', params.data._resultId);
1393
container.on('selection:update', function (params) {
1394
self.update(params.data);
1397
container.on('open', function () {
1398
// When the dropdown is open, aria-expanded="true"
1399
self.$selection.attr('aria-expanded', 'true');
1400
self.$selection.attr('aria-owns', resultsId);
1402
self._attachCloseHandler(container);
1405
container.on('close', function () {
1406
// When the dropdown is closed, aria-expanded="false"
1407
self.$selection.attr('aria-expanded', 'false');
1408
self.$selection.removeAttr('aria-activedescendant');
1409
self.$selection.removeAttr('aria-owns');
1411
self.$selection.focus();
1413
self._detachCloseHandler(container);
1416
container.on('enable', function () {
1417
self.$selection.attr('tabindex', self._tabindex);
1420
container.on('disable', function () {
1421
self.$selection.attr('tabindex', '-1');
1425
BaseSelection.prototype._handleBlur = function (evt) {
1428
// This needs to be delayed as the active element is the body when the tab
1429
// key is pressed, possibly along with others.
1430
window.setTimeout(function () {
1431
// Don't trigger `blur` if the focus is still in the selection
1433
(document.activeElement == self.$selection[0]) ||
1434
($.contains(self.$selection[0], document.activeElement))
1439
self.trigger('blur', evt);
1443
BaseSelection.prototype._attachCloseHandler = function (container) {
1446
$(document.body).on('mousedown.select2.' + container.id, function (e) {
1447
var $target = $(e.target);
1449
var $select = $target.closest('.select2');
1451
var $all = $('.select2.select2-container--open');
1453
$all.each(function () {
1454
var $this = $(this);
1456
if (this == $select[0]) {
1460
var $element = $this.data('element');
1462
$element.select2('close');
1467
BaseSelection.prototype._detachCloseHandler = function (container) {
1468
$(document.body).off('mousedown.select2.' + container.id);
1471
BaseSelection.prototype.position = function ($selection, $container) {
1472
var $selectionContainer = $container.find('.selection');
1473
$selectionContainer.append($selection);
1476
BaseSelection.prototype.destroy = function () {
1477
this._detachCloseHandler(this.container);
1480
BaseSelection.prototype.update = function (data) {
1481
throw new Error('The `update` method must be defined in child classes.');
1484
return BaseSelection;
1487
S2.define('select2/selection/single',[
1492
], function ($, BaseSelection, Utils, KEYS) {
1493
function SingleSelection () {
1494
SingleSelection.__super__.constructor.apply(this, arguments);
1497
Utils.Extend(SingleSelection, BaseSelection);
1499
SingleSelection.prototype.render = function () {
1500
var $selection = SingleSelection.__super__.render.call(this);
1502
$selection.addClass('select2-selection--single');
1505
'<span class="select2-selection__rendered"></span>' +
1506
'<span class="select2-selection__arrow" role="presentation">' +
1507
'<b role="presentation"></b>' +
1514
SingleSelection.prototype.bind = function (container, $container) {
1517
SingleSelection.__super__.bind.apply(this, arguments);
1519
var id = container.id + '-container';
1521
this.$selection.find('.select2-selection__rendered').attr('id', id);
1522
this.$selection.attr('aria-labelledby', id);
1524
this.$selection.on('mousedown', function (evt) {
1525
// Only respond to left clicks
1526
if (evt.which !== 1) {
1530
self.trigger('toggle', {
1535
this.$selection.on('focus', function (evt) {
1536
// User focuses on the container
1539
this.$selection.on('blur', function (evt) {
1540
// User exits the container
1543
container.on('focus', function (evt) {
1544
if (!container.isOpen()) {
1545
self.$selection.focus();
1549
container.on('selection:update', function (params) {
1550
self.update(params.data);
1554
SingleSelection.prototype.clear = function () {
1555
this.$selection.find('.select2-selection__rendered').empty();
1558
SingleSelection.prototype.display = function (data, container) {
1559
var template = this.options.get('templateSelection');
1560
var escapeMarkup = this.options.get('escapeMarkup');
1562
return escapeMarkup(template(data, container));
1565
SingleSelection.prototype.selectionContainer = function () {
1566
return $('<span></span>');
1569
SingleSelection.prototype.update = function (data) {
1570
if (data.length === 0) {
1575
var selection = data[0];
1577
var $rendered = this.$selection.find('.select2-selection__rendered');
1578
var formatted = this.display(selection, $rendered);
1580
$rendered.empty().append(formatted);
1581
$rendered.prop('title', selection.title || selection.text);
1584
return SingleSelection;
1587
S2.define('select2/selection/multiple',[
1591
], function ($, BaseSelection, Utils) {
1592
function MultipleSelection ($element, options) {
1593
MultipleSelection.__super__.constructor.apply(this, arguments);
1596
Utils.Extend(MultipleSelection, BaseSelection);
1598
MultipleSelection.prototype.render = function () {
1599
var $selection = MultipleSelection.__super__.render.call(this);
1601
$selection.addClass('select2-selection--multiple');
1604
'<ul class="select2-selection__rendered"></ul>'
1610
MultipleSelection.prototype.bind = function (container, $container) {
1613
MultipleSelection.__super__.bind.apply(this, arguments);
1615
this.$selection.on('click', function (evt) {
1616
self.trigger('toggle', {
1623
'.select2-selection__choice__remove',
1625
// Ignore the event if it is disabled
1626
if (self.options.get('disabled')) {
1630
var $remove = $(this);
1631
var $selection = $remove.parent();
1633
var data = $selection.data('data');
1635
self.trigger('unselect', {
1643
MultipleSelection.prototype.clear = function () {
1644
this.$selection.find('.select2-selection__rendered').empty();
1647
MultipleSelection.prototype.display = function (data, container) {
1648
var template = this.options.get('templateSelection');
1649
var escapeMarkup = this.options.get('escapeMarkup');
1651
return escapeMarkup(template(data, container));
1654
MultipleSelection.prototype.selectionContainer = function () {
1656
'<li class="select2-selection__choice">' +
1657
'<span class="select2-selection__choice__remove" role="presentation">' +
1666
MultipleSelection.prototype.update = function (data) {
1669
if (data.length === 0) {
1673
var $selections = [];
1675
for (var d = 0; d < data.length; d++) {
1676
var selection = data[d];
1678
var $selection = this.selectionContainer();
1679
var formatted = this.display(selection, $selection);
1681
$selection.append(formatted);
1682
$selection.prop('title', selection.title || selection.text);
1684
$selection.data('data', selection);
1686
$selections.push($selection);
1689
var $rendered = this.$selection.find('.select2-selection__rendered');
1691
Utils.appendMany($rendered, $selections);
1694
return MultipleSelection;
1697
S2.define('select2/selection/placeholder',[
1699
], function (Utils) {
1700
function Placeholder (decorated, $element, options) {
1701
this.placeholder = this.normalizePlaceholder(options.get('placeholder'));
1703
decorated.call(this, $element, options);
1706
Placeholder.prototype.normalizePlaceholder = function (_, placeholder) {
1707
if (typeof placeholder === 'string') {
1717
Placeholder.prototype.createPlaceholder = function (decorated, placeholder) {
1718
var $placeholder = this.selectionContainer();
1720
$placeholder.html(this.display(placeholder));
1721
$placeholder.addClass('select2-selection__placeholder')
1722
.removeClass('select2-selection__choice');
1724
return $placeholder;
1727
Placeholder.prototype.update = function (decorated, data) {
1728
var singlePlaceholder = (
1729
data.length == 1 && data[0].id != this.placeholder.id
1731
var multipleSelections = data.length > 1;
1733
if (multipleSelections || singlePlaceholder) {
1734
return decorated.call(this, data);
1739
var $placeholder = this.createPlaceholder(this.placeholder);
1741
this.$selection.find('.select2-selection__rendered').append($placeholder);
1747
S2.define('select2/selection/allowClear',[
1750
], function ($, KEYS) {
1751
function AllowClear () { }
1753
AllowClear.prototype.bind = function (decorated, container, $container) {
1756
decorated.call(this, container, $container);
1758
if (this.placeholder == null) {
1759
if (this.options.get('debug') && window.console && console.error) {
1761
'Select2: The `allowClear` option should be used in combination ' +
1762
'with the `placeholder` option.'
1767
this.$selection.on('mousedown', '.select2-selection__clear',
1769
self._handleClear(evt);
1772
container.on('keypress', function (evt) {
1773
self._handleKeyboardClear(evt, container);
1777
AllowClear.prototype._handleClear = function (_, evt) {
1778
// Ignore the event if it is disabled
1779
if (this.options.get('disabled')) {
1783
var $clear = this.$selection.find('.select2-selection__clear');
1785
// Ignore the event if nothing has been selected
1786
if ($clear.length === 0) {
1790
evt.stopPropagation();
1792
var data = $clear.data('data');
1794
for (var d = 0; d < data.length; d++) {
1795
var unselectData = {
1799
// Trigger the `unselect` event, so people can prevent it from being
1801
this.trigger('unselect', unselectData);
1803
// If the event was prevented, don't clear it out.
1804
if (unselectData.prevented) {
1809
this.$element.val(this.placeholder.id).trigger('change');
1811
this.trigger('toggle', {});
1814
AllowClear.prototype._handleKeyboardClear = function (_, evt, container) {
1815
if (container.isOpen()) {
1819
if (evt.which == KEYS.DELETE || evt.which == KEYS.BACKSPACE) {
1820
this._handleClear(evt);
1824
AllowClear.prototype.update = function (decorated, data) {
1825
decorated.call(this, data);
1827
if (this.$selection.find('.select2-selection__placeholder').length > 0 ||
1828
data.length === 0) {
1833
'<span class="select2-selection__clear">' +
1837
$remove.data('data', data);
1839
this.$selection.find('.select2-selection__rendered').prepend($remove);
1845
S2.define('select2/selection/search',[
1849
], function ($, Utils, KEYS) {
1850
function Search (decorated, $element, options) {
1851
decorated.call(this, $element, options);
1854
Search.prototype.render = function (decorated) {
1856
'<li class="select2-search select2-search--inline">' +
1857
'<input class="select2-search__field" type="search" tabindex="-1"' +
1858
' autocomplete="off" autocorrect="off" autocapitalize="none"' +
1859
' spellcheck="false" role="textbox" aria-autocomplete="list" />' +
1863
this.$searchContainer = $search;
1864
this.$search = $search.find('input');
1866
var $rendered = decorated.call(this);
1868
this._transferTabIndex();
1873
Search.prototype.bind = function (decorated, container, $container) {
1876
decorated.call(this, container, $container);
1878
container.on('open', function () {
1879
self.$search.trigger('focus');
1882
container.on('close', function () {
1883
self.$search.val('');
1884
self.$search.removeAttr('aria-activedescendant');
1885
self.$search.trigger('focus');
1888
container.on('enable', function () {
1889
self.$search.prop('disabled', false);
1891
self._transferTabIndex();
1894
container.on('disable', function () {
1895
self.$search.prop('disabled', true);
1898
container.on('focus', function (evt) {
1899
self.$search.trigger('focus');
1902
container.on('results:focus', function (params) {
1903
self.$search.attr('aria-activedescendant', params.id);
1906
this.$selection.on('focusin', '.select2-search--inline', function (evt) {
1907
self.trigger('focus', evt);
1910
this.$selection.on('focusout', '.select2-search--inline', function (evt) {
1911
self._handleBlur(evt);
1914
this.$selection.on('keydown', '.select2-search--inline', function (evt) {
1915
evt.stopPropagation();
1917
self.trigger('keypress', evt);
1919
self._keyUpPrevented = evt.isDefaultPrevented();
1921
var key = evt.which;
1923
if (key === KEYS.BACKSPACE && self.$search.val() === '') {
1924
var $previousChoice = self.$searchContainer
1925
.prev('.select2-selection__choice');
1927
if ($previousChoice.length > 0) {
1928
var item = $previousChoice.data('data');
1930
self.searchRemoveChoice(item);
1932
evt.preventDefault();
1937
// Try to detect the IE version should the `documentMode` property that
1938
// is stored on the document. This is only implemented in IE and is
1939
// slightly cleaner than doing a user agent check.
1940
// This property is not available in Edge, but Edge also doesn't have
1942
var msie = document.documentMode;
1943
var disableInputEvents = msie && msie <= 11;
1945
// Workaround for browsers which do not support the `input` event
1946
// This will prevent double-triggering of events for browsers which support
1947
// both the `keyup` and `input` events.
1949
'input.searchcheck',
1950
'.select2-search--inline',
1952
// IE will trigger the `input` event when a placeholder is used on a
1953
// search box. To get around this issue, we are forced to ignore all
1954
// `input` events in IE and keep using `keyup`.
1955
if (disableInputEvents) {
1956
self.$selection.off('input.search input.searchcheck');
1960
// Unbind the duplicated `keyup` event
1961
self.$selection.off('keyup.search');
1966
'keyup.search input.search',
1967
'.select2-search--inline',
1969
// IE will trigger the `input` event when a placeholder is used on a
1970
// search box. To get around this issue, we are forced to ignore all
1971
// `input` events in IE and keep using `keyup`.
1972
if (disableInputEvents && evt.type === 'input') {
1973
self.$selection.off('input.search input.searchcheck');
1977
var key = evt.which;
1979
// We can freely ignore events from modifier keys
1980
if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) {
1984
// Tabbing will be handled during the `keydown` phase
1985
if (key == KEYS.TAB) {
1989
self.handleSearch(evt);
1995
* This method will transfer the tabindex attribute from the rendered
1996
* selection to the search box. This allows for the search box to be used as
1997
* the primary focus instead of the selection container.
2001
Search.prototype._transferTabIndex = function (decorated) {
2002
this.$search.attr('tabindex', this.$selection.attr('tabindex'));
2003
this.$selection.attr('tabindex', '-1');
2006
Search.prototype.createPlaceholder = function (decorated, placeholder) {
2007
this.$search.attr('placeholder', placeholder.text);
2010
Search.prototype.update = function (decorated, data) {
2011
var searchHadFocus = this.$search[0] == document.activeElement;
2013
this.$search.attr('placeholder', '');
2015
decorated.call(this, data);
2017
this.$selection.find('.select2-selection__rendered')
2018
.append(this.$searchContainer);
2020
this.resizeSearch();
2021
if (searchHadFocus) {
2022
this.$search.focus();
2026
Search.prototype.handleSearch = function () {
2027
this.resizeSearch();
2029
if (!this._keyUpPrevented) {
2030
var input = this.$search.val();
2032
this.trigger('query', {
2037
this._keyUpPrevented = false;
2040
Search.prototype.searchRemoveChoice = function (decorated, item) {
2041
this.trigger('unselect', {
2045
this.$search.val(item.text);
2046
this.handleSearch();
2049
Search.prototype.resizeSearch = function () {
2050
this.$search.css('width', '25px');
2054
if (this.$search.attr('placeholder') !== '') {
2055
width = this.$selection.find('.select2-selection__rendered').innerWidth();
2057
var minimumWidth = this.$search.val().length + 1;
2059
width = (minimumWidth * 0.75) + 'em';
2062
this.$search.css('width', width);
2068
S2.define('select2/selection/eventRelay',[
2071
function EventRelay () { }
2073
EventRelay.prototype.bind = function (decorated, container, $container) {
2078
'select', 'selecting',
2079
'unselect', 'unselecting'
2082
var preventableEvents = ['opening', 'closing', 'selecting', 'unselecting'];
2084
decorated.call(this, container, $container);
2086
container.on('*', function (name, params) {
2087
// Ignore events that should not be relayed
2088
if ($.inArray(name, relayEvents) === -1) {
2092
// The parameters should always be an object
2093
params = params || {};
2095
// Generate the jQuery event for the Select2 event
2096
var evt = $.Event('select2:' + name, {
2100
self.$element.trigger(evt);
2102
// Only handle preventable events if it was one
2103
if ($.inArray(name, preventableEvents) === -1) {
2107
params.prevented = evt.isDefaultPrevented();
2114
S2.define('select2/translation',[
2117
], function ($, require) {
2118
function Translation (dict) {
2119
this.dict = dict || {};
2122
Translation.prototype.all = function () {
2126
Translation.prototype.get = function (key) {
2127
return this.dict[key];
2130
Translation.prototype.extend = function (translation) {
2131
this.dict = $.extend({}, translation.all(), this.dict);
2136
Translation._cache = {};
2138
Translation.loadPath = function (path) {
2139
if (!(path in Translation._cache)) {
2140
var translations = require(path);
2142
Translation._cache[path] = translations;
2145
return new Translation(Translation._cache[path]);
2151
S2.define('select2/diacritics',[
2999
S2.define('select2/data/base',[
3001
], function (Utils) {
3002
function BaseAdapter ($element, options) {
3003
BaseAdapter.__super__.constructor.call(this);
3006
Utils.Extend(BaseAdapter, Utils.Observable);
3008
BaseAdapter.prototype.current = function (callback) {
3009
throw new Error('The `current` method must be defined in child classes.');
3012
BaseAdapter.prototype.query = function (params, callback) {
3013
throw new Error('The `query` method must be defined in child classes.');
3016
BaseAdapter.prototype.bind = function (container, $container) {
3017
// Can be implemented in subclasses
3020
BaseAdapter.prototype.destroy = function () {
3021
// Can be implemented in subclasses
3024
BaseAdapter.prototype.generateResultId = function (container, data) {
3025
var id = container.id + '-result-';
3027
id += Utils.generateChars(4);
3029
if (data.id != null) {
3030
id += '-' + data.id.toString();
3032
id += '-' + Utils.generateChars(4);
3040
S2.define('select2/data/select',[
3044
], function (BaseAdapter, Utils, $) {
3045
function SelectAdapter ($element, options) {
3046
this.$element = $element;
3047
this.options = options;
3049
SelectAdapter.__super__.constructor.call(this);
3052
Utils.Extend(SelectAdapter, BaseAdapter);
3054
SelectAdapter.prototype.current = function (callback) {
3058
this.$element.find(':selected').each(function () {
3059
var $option = $(this);
3061
var option = self.item($option);
3069
SelectAdapter.prototype.select = function (data) {
3072
data.selected = true;
3074
// If data.element is a DOM node, use it instead
3075
if ($(data.element).is('option')) {
3076
data.element.selected = true;
3078
this.$element.trigger('change');
3083
if (this.$element.prop('multiple')) {
3084
this.current(function (currentData) {
3088
data.push.apply(data, currentData);
3090
for (var d = 0; d < data.length; d++) {
3091
var id = data[d].id;
3093
if ($.inArray(id, val) === -1) {
3098
self.$element.val(val);
3099
self.$element.trigger('change');
3104
this.$element.val(val);
3105
this.$element.trigger('change');
3109
SelectAdapter.prototype.unselect = function (data) {
3112
if (!this.$element.prop('multiple')) {
3116
data.selected = false;
3118
if ($(data.element).is('option')) {
3119
data.element.selected = false;
3121
this.$element.trigger('change');
3126
this.current(function (currentData) {
3129
for (var d = 0; d < currentData.length; d++) {
3130
var id = currentData[d].id;
3132
if (id !== data.id && $.inArray(id, val) === -1) {
3137
self.$element.val(val);
3139
self.$element.trigger('change');
3143
SelectAdapter.prototype.bind = function (container, $container) {
3146
this.container = container;
3148
container.on('select', function (params) {
3149
self.select(params.data);
3152
container.on('unselect', function (params) {
3153
self.unselect(params.data);
3157
SelectAdapter.prototype.destroy = function () {
3158
// Remove anything added to child elements
3159
this.$element.find('*').each(function () {
3160
// Remove any custom data set by Select2
3161
$.removeData(this, 'data');
3165
SelectAdapter.prototype.query = function (params, callback) {
3169
var $options = this.$element.children();
3171
$options.each(function () {
3172
var $option = $(this);
3174
if (!$option.is('option') && !$option.is('optgroup')) {
3178
var option = self.item($option);
3180
var matches = self.matches(params, option);
3182
if (matches !== null) {
3192
SelectAdapter.prototype.addOptions = function ($options) {
3193
Utils.appendMany(this.$element, $options);
3196
SelectAdapter.prototype.option = function (data) {
3199
if (data.children) {
3200
option = document.createElement('optgroup');
3201
option.label = data.text;
3203
option = document.createElement('option');
3205
if (option.textContent !== undefined) {
3206
option.textContent = data.text;
3208
option.innerText = data.text;
3212
if (data.id !== undefined) {
3213
option.value = data.id;
3216
if (data.disabled) {
3217
option.disabled = true;
3220
if (data.selected) {
3221
option.selected = true;
3225
option.title = data.title;
3228
var $option = $(option);
3230
var normalizedData = this._normalizeItem(data);
3231
normalizedData.element = option;
3233
// Override the option's data with the combined data
3234
$.data(option, 'data', normalizedData);
3239
SelectAdapter.prototype.item = function ($option) {
3242
data = $.data($option[0], 'data');
3248
if ($option.is('option')) {
3251
text: $option.text(),
3252
disabled: $option.prop('disabled'),
3253
selected: $option.prop('selected'),
3254
title: $option.prop('title')
3256
} else if ($option.is('optgroup')) {
3258
text: $option.prop('label'),
3260
title: $option.prop('title')
3263
var $children = $option.children('option');
3266
for (var c = 0; c < $children.length; c++) {
3267
var $child = $($children[c]);
3269
var child = this.item($child);
3271
children.push(child);
3274
data.children = children;
3277
data = this._normalizeItem(data);
3278
data.element = $option[0];
3280
$.data($option[0], 'data', data);
3285
SelectAdapter.prototype._normalizeItem = function (item) {
3286
if (!$.isPlainObject(item)) {
3293
item = $.extend({}, {
3302
if (item.id != null) {
3303
item.id = item.id.toString();
3306
if (item.text != null) {
3307
item.text = item.text.toString();
3310
if (item._resultId == null && item.id && this.container != null) {
3311
item._resultId = this.generateResultId(this.container, item);
3314
return $.extend({}, defaults, item);
3317
SelectAdapter.prototype.matches = function (params, data) {
3318
var matcher = this.options.get('matcher');
3320
return matcher(params, data);
3323
return SelectAdapter;
3326
S2.define('select2/data/array',[
3330
], function (SelectAdapter, Utils, $) {
3331
function ArrayAdapter ($element, options) {
3332
var data = options.get('data') || [];
3334
ArrayAdapter.__super__.constructor.call(this, $element, options);
3336
this.addOptions(this.convertToOptions(data));
3339
Utils.Extend(ArrayAdapter, SelectAdapter);
3341
ArrayAdapter.prototype.select = function (data) {
3342
var $option = this.$element.find('option').filter(function (i, elm) {
3343
return elm.value == data.id.toString();
3346
if ($option.length === 0) {
3347
$option = this.option(data);
3349
this.addOptions($option);
3352
ArrayAdapter.__super__.select.call(this, data);
3355
ArrayAdapter.prototype.convertToOptions = function (data) {
3358
var $existing = this.$element.find('option');
3359
var existingIds = $existing.map(function () {
3360
return self.item($(this)).id;
3365
// Filter out all items except for the one passed in the argument
3366
function onlyItem (item) {
3367
return function () {
3368
return $(this).val() == item.id;
3372
for (var d = 0; d < data.length; d++) {
3373
var item = this._normalizeItem(data[d]);
3375
// Skip items which were pre-loaded, only merge the data
3376
if ($.inArray(item.id, existingIds) >= 0) {
3377
var $existingOption = $existing.filter(onlyItem(item));
3379
var existingData = this.item($existingOption);
3380
var newData = $.extend(true, {}, item, existingData);
3382
var $newOption = this.option(newData);
3384
$existingOption.replaceWith($newOption);
3389
var $option = this.option(item);
3391
if (item.children) {
3392
var $children = this.convertToOptions(item.children);
3394
Utils.appendMany($option, $children);
3397
$options.push($option);
3403
return ArrayAdapter;
3406
S2.define('select2/data/ajax',[
3410
], function (ArrayAdapter, Utils, $) {
3411
function AjaxAdapter ($element, options) {
3412
this.ajaxOptions = this._applyDefaults(options.get('ajax'));
3414
if (this.ajaxOptions.processResults != null) {
3415
this.processResults = this.ajaxOptions.processResults;
3418
AjaxAdapter.__super__.constructor.call(this, $element, options);
3421
Utils.Extend(AjaxAdapter, ArrayAdapter);
3423
AjaxAdapter.prototype._applyDefaults = function (options) {
3425
data: function (params) {
3426
return $.extend({}, params, {
3430
transport: function (params, success, failure) {
3431
var $request = $.ajax(params);
3433
$request.then(success);
3434
$request.fail(failure);
3440
return $.extend({}, defaults, options, true);
3443
AjaxAdapter.prototype.processResults = function (results) {
3447
AjaxAdapter.prototype.query = function (params, callback) {
3451
if (this._request != null) {
3452
// JSONP requests cannot always be aborted
3453
if ($.isFunction(this._request.abort)) {
3454
this._request.abort();
3457
this._request = null;
3460
var options = $.extend({
3462
}, this.ajaxOptions);
3464
if (typeof options.url === 'function') {
3465
options.url = options.url.call(this.$element, params);
3468
if (typeof options.data === 'function') {
3469
options.data = options.data.call(this.$element, params);
3472
function request () {
3473
var $request = options.transport(options, function (data) {
3474
var results = self.processResults(data, params);
3476
if (self.options.get('debug') && window.console && console.error) {
3477
// Check to make sure that the response included a `results` key.
3478
if (!results || !results.results || !$.isArray(results.results)) {
3480
'Select2: The AJAX results did not return an array in the ' +
3481
'`results` key of the response.'
3488
// Attempt to detect if a request was aborted
3489
// Only works if the transport exposes a status property
3490
if ($request.status && $request.status === '0') {
3494
self.trigger('results:message', {
3495
message: 'errorLoading'
3499
self._request = $request;
3502
if (this.ajaxOptions.delay && params.term != null) {
3503
if (this._queryTimeout) {
3504
window.clearTimeout(this._queryTimeout);
3507
this._queryTimeout = window.setTimeout(request, this.ajaxOptions.delay);
3516
S2.define('select2/data/tags',[
3519
function Tags (decorated, $element, options) {
3520
var tags = options.get('tags');
3522
var createTag = options.get('createTag');
3524
if (createTag !== undefined) {
3525
this.createTag = createTag;
3528
var insertTag = options.get('insertTag');
3530
if (insertTag !== undefined) {
3531
this.insertTag = insertTag;
3534
decorated.call(this, $element, options);
3536
if ($.isArray(tags)) {
3537
for (var t = 0; t < tags.length; t++) {
3539
var item = this._normalizeItem(tag);
3541
var $option = this.option(item);
3543
this.$element.append($option);
3548
Tags.prototype.query = function (decorated, params, callback) {
3551
this._removeOldTags();
3553
if (params.term == null || params.page != null) {
3554
decorated.call(this, params, callback);
3558
function wrapper (obj, child) {
3559
var data = obj.results;
3561
for (var i = 0; i < data.length; i++) {
3562
var option = data[i];
3564
var checkChildren = (
3565
option.children != null &&
3567
results: option.children
3571
var optionText = (option.text || '').toUpperCase();
3572
var paramsTerm = (params.term || '').toUpperCase();
3574
var checkText = optionText === paramsTerm;
3576
if (checkText || checkChildren) {
3592
var tag = self.createTag(params);
3595
var $option = self.option(tag);
3596
$option.attr('data-select2-tag', true);
3598
self.addOptions([$option]);
3600
self.insertTag(data, tag);
3608
decorated.call(this, params, wrapper);
3611
Tags.prototype.createTag = function (decorated, params) {
3612
var term = $.trim(params.term);
3624
Tags.prototype.insertTag = function (_, data, tag) {
3628
Tags.prototype._removeOldTags = function (_) {
3629
var tag = this._lastTag;
3631
var $options = this.$element.find('option[data-select2-tag]');
3633
$options.each(function () {
3634
if (this.selected) {
3645
S2.define('select2/data/tokenizer',[
3648
function Tokenizer (decorated, $element, options) {
3649
var tokenizer = options.get('tokenizer');
3651
if (tokenizer !== undefined) {
3652
this.tokenizer = tokenizer;
3655
decorated.call(this, $element, options);
3658
Tokenizer.prototype.bind = function (decorated, container, $container) {
3659
decorated.call(this, container, $container);
3661
this.$search = container.dropdown.$search || container.selection.$search ||
3662
$container.find('.select2-search__field');
3665
Tokenizer.prototype.query = function (decorated, params, callback) {
3668
function createAndSelect (data) {
3669
// Normalize the data object so we can use it for checks
3670
var item = self._normalizeItem(data);
3672
// Check if the data object already exists as a tag
3673
// Select it if it doesn't
3674
var $existingOptions = self.$element.find('option').filter(function () {
3675
return $(this).val() === item.id;
3678
// If an existing option wasn't found for it, create the option
3679
if (!$existingOptions.length) {
3680
var $option = self.option(item);
3681
$option.attr('data-select2-tag', true);
3683
self._removeOldTags();
3684
self.addOptions([$option]);
3687
// Select the item, now that we know there is an option for it
3691
function select (data) {
3692
self.trigger('select', {
3697
params.term = params.term || '';
3699
var tokenData = this.tokenizer(params, this.options, createAndSelect);
3701
if (tokenData.term !== params.term) {
3702
// Replace the search term if we have the search box
3703
if (this.$search.length) {
3704
this.$search.val(tokenData.term);
3705
this.$search.focus();
3708
params.term = tokenData.term;
3711
decorated.call(this, params, callback);
3714
Tokenizer.prototype.tokenizer = function (_, params, options, callback) {
3715
var separators = options.get('tokenSeparators') || [];
3716
var term = params.term;
3719
var createTag = this.createTag || function (params) {
3726
while (i < term.length) {
3727
var termChar = term[i];
3729
if ($.inArray(termChar, separators) === -1) {
3735
var part = term.substr(0, i);
3736
var partParams = $.extend({}, params, {
3740
var data = createTag(partParams);
3749
// Reset the term to not include the tokenized portion
3750
term = term.substr(i + 1) || '';
3762
S2.define('select2/data/minimumInputLength',[
3765
function MinimumInputLength (decorated, $e, options) {
3766
this.minimumInputLength = options.get('minimumInputLength');
3768
decorated.call(this, $e, options);
3771
MinimumInputLength.prototype.query = function (decorated, params, callback) {
3772
params.term = params.term || '';
3774
if (params.term.length < this.minimumInputLength) {
3775
this.trigger('results:message', {
3776
message: 'inputTooShort',
3778
minimum: this.minimumInputLength,
3787
decorated.call(this, params, callback);
3790
return MinimumInputLength;
3793
S2.define('select2/data/maximumInputLength',[
3796
function MaximumInputLength (decorated, $e, options) {
3797
this.maximumInputLength = options.get('maximumInputLength');
3799
decorated.call(this, $e, options);
3802
MaximumInputLength.prototype.query = function (decorated, params, callback) {
3803
params.term = params.term || '';
3805
if (this.maximumInputLength > 0 &&
3806
params.term.length > this.maximumInputLength) {
3807
this.trigger('results:message', {
3808
message: 'inputTooLong',
3810
maximum: this.maximumInputLength,
3819
decorated.call(this, params, callback);
3822
return MaximumInputLength;
3825
S2.define('select2/data/maximumSelectionLength',[
3828
function MaximumSelectionLength (decorated, $e, options) {
3829
this.maximumSelectionLength = options.get('maximumSelectionLength');
3831
decorated.call(this, $e, options);
3834
MaximumSelectionLength.prototype.query =
3835
function (decorated, params, callback) {
3838
this.current(function (currentData) {
3839
var count = currentData != null ? currentData.length : 0;
3840
if (self.maximumSelectionLength > 0 &&
3841
count >= self.maximumSelectionLength) {
3842
self.trigger('results:message', {
3843
message: 'maximumSelected',
3845
maximum: self.maximumSelectionLength
3850
decorated.call(self, params, callback);
3854
return MaximumSelectionLength;
3857
S2.define('select2/dropdown',[
3860
], function ($, Utils) {
3861
function Dropdown ($element, options) {
3862
this.$element = $element;
3863
this.options = options;
3865
Dropdown.__super__.constructor.call(this);
3868
Utils.Extend(Dropdown, Utils.Observable);
3870
Dropdown.prototype.render = function () {
3872
'<span class="select2-dropdown">' +
3873
'<span class="select2-results"></span>' +
3877
$dropdown.attr('dir', this.options.get('dir'));
3879
this.$dropdown = $dropdown;
3884
Dropdown.prototype.bind = function () {
3885
// Should be implemented in subclasses
3888
Dropdown.prototype.position = function ($dropdown, $container) {
3889
// Should be implmented in subclasses
3892
Dropdown.prototype.destroy = function () {
3893
// Remove the dropdown from the DOM
3894
this.$dropdown.remove();
3900
S2.define('select2/dropdown/search',[
3903
], function ($, Utils) {
3904
function Search () { }
3906
Search.prototype.render = function (decorated) {
3907
var $rendered = decorated.call(this);
3910
'<span class="select2-search select2-search--dropdown">' +
3911
'<input class="select2-search__field" type="search" tabindex="-1"' +
3912
' autocomplete="off" autocorrect="off" autocapitalize="none"' +
3913
' spellcheck="false" role="textbox" />' +
3917
this.$searchContainer = $search;
3918
this.$search = $search.find('input');
3920
$rendered.prepend($search);
3925
Search.prototype.bind = function (decorated, container, $container) {
3928
decorated.call(this, container, $container);
3930
this.$search.on('keydown', function (evt) {
3931
self.trigger('keypress', evt);
3933
self._keyUpPrevented = evt.isDefaultPrevented();
3936
// Workaround for browsers which do not support the `input` event
3937
// This will prevent double-triggering of events for browsers which support
3938
// both the `keyup` and `input` events.
3939
this.$search.on('input', function (evt) {
3940
// Unbind the duplicated `keyup` event
3941
$(this).off('keyup');
3944
this.$search.on('keyup input', function (evt) {
3945
self.handleSearch(evt);
3948
container.on('open', function () {
3949
self.$search.attr('tabindex', 0);
3951
self.$search.focus();
3953
window.setTimeout(function () {
3954
self.$search.focus();
3958
container.on('close', function () {
3959
self.$search.attr('tabindex', -1);
3961
self.$search.val('');
3964
container.on('focus', function () {
3965
if (!container.isOpen()) {
3966
self.$search.focus();
3970
container.on('results:all', function (params) {
3971
if (params.query.term == null || params.query.term === '') {
3972
var showSearch = self.showSearch(params);
3975
self.$searchContainer.removeClass('select2-search--hide');
3977
self.$searchContainer.addClass('select2-search--hide');
3983
Search.prototype.handleSearch = function (evt) {
3984
if (!this._keyUpPrevented) {
3985
var input = this.$search.val();
3987
this.trigger('query', {
3992
this._keyUpPrevented = false;
3995
Search.prototype.showSearch = function (_, params) {
4002
S2.define('select2/dropdown/hidePlaceholder',[
4005
function HidePlaceholder (decorated, $element, options, dataAdapter) {
4006
this.placeholder = this.normalizePlaceholder(options.get('placeholder'));
4008
decorated.call(this, $element, options, dataAdapter);
4011
HidePlaceholder.prototype.append = function (decorated, data) {
4012
data.results = this.removePlaceholder(data.results);
4014
decorated.call(this, data);
4017
HidePlaceholder.prototype.normalizePlaceholder = function (_, placeholder) {
4018
if (typeof placeholder === 'string') {
4028
HidePlaceholder.prototype.removePlaceholder = function (_, data) {
4029
var modifiedData = data.slice(0);
4031
for (var d = data.length - 1; d >= 0; d--) {
4034
if (this.placeholder.id === item.id) {
4035
modifiedData.splice(d, 1);
4039
return modifiedData;
4042
return HidePlaceholder;
4045
S2.define('select2/dropdown/infiniteScroll',[
4048
function InfiniteScroll (decorated, $element, options, dataAdapter) {
4049
this.lastParams = {};
4051
decorated.call(this, $element, options, dataAdapter);
4053
this.$loadingMore = this.createLoadingMore();
4054
this.loading = false;
4057
InfiniteScroll.prototype.append = function (decorated, data) {
4058
this.$loadingMore.remove();
4059
this.loading = false;
4061
decorated.call(this, data);
4063
if (this.showLoadingMore(data)) {
4064
this.$results.append(this.$loadingMore);
4068
InfiniteScroll.prototype.bind = function (decorated, container, $container) {
4071
decorated.call(this, container, $container);
4073
container.on('query', function (params) {
4074
self.lastParams = params;
4075
self.loading = true;
4078
container.on('query:append', function (params) {
4079
self.lastParams = params;
4080
self.loading = true;
4083
this.$results.on('scroll', function () {
4084
var isLoadMoreVisible = $.contains(
4085
document.documentElement,
4086
self.$loadingMore[0]
4089
if (self.loading || !isLoadMoreVisible) {
4093
var currentOffset = self.$results.offset().top +
4094
self.$results.outerHeight(false);
4095
var loadingMoreOffset = self.$loadingMore.offset().top +
4096
self.$loadingMore.outerHeight(false);
4098
if (currentOffset + 50 >= loadingMoreOffset) {
4104
InfiniteScroll.prototype.loadMore = function () {
4105
this.loading = true;
4107
var params = $.extend({}, {page: 1}, this.lastParams);
4111
this.trigger('query:append', params);
4114
InfiniteScroll.prototype.showLoadingMore = function (_, data) {
4115
return data.pagination && data.pagination.more;
4118
InfiniteScroll.prototype.createLoadingMore = function () {
4121
'class="select2-results__option select2-results__option--load-more"' +
4122
'role="treeitem" aria-disabled="true"></li>'
4125
var message = this.options.get('translations').get('loadingMore');
4127
$option.html(message(this.lastParams));
4132
return InfiniteScroll;
4135
S2.define('select2/dropdown/attachBody',[
4138
], function ($, Utils) {
4139
function AttachBody (decorated, $element, options) {
4140
this.$dropdownParent = options.get('dropdownParent') || $(document.body);
4142
decorated.call(this, $element, options);
4145
AttachBody.prototype.bind = function (decorated, container, $container) {
4148
var setupResultsEvents = false;
4150
decorated.call(this, container, $container);
4152
container.on('open', function () {
4153
self._showDropdown();
4154
self._attachPositioningHandler(container);
4156
if (!setupResultsEvents) {
4157
setupResultsEvents = true;
4159
container.on('results:all', function () {
4160
self._positionDropdown();
4161
self._resizeDropdown();
4164
container.on('results:append', function () {
4165
self._positionDropdown();
4166
self._resizeDropdown();
4171
container.on('close', function () {
4172
self._hideDropdown();
4173
self._detachPositioningHandler(container);
4176
this.$dropdownContainer.on('mousedown', function (evt) {
4177
evt.stopPropagation();
4181
AttachBody.prototype.destroy = function (decorated) {
4182
decorated.call(this);
4184
this.$dropdownContainer.remove();
4187
AttachBody.prototype.position = function (decorated, $dropdown, $container) {
4188
// Clone all of the container classes
4189
$dropdown.attr('class', $container.attr('class'));
4191
$dropdown.removeClass('select2');
4192
$dropdown.addClass('select2-container--open');
4195
position: 'absolute',
4199
this.$container = $container;
4202
AttachBody.prototype.render = function (decorated) {
4203
var $container = $('<span></span>');
4205
var $dropdown = decorated.call(this);
4206
$container.append($dropdown);
4208
this.$dropdownContainer = $container;
4213
AttachBody.prototype._hideDropdown = function (decorated) {
4214
this.$dropdownContainer.detach();
4217
AttachBody.prototype._attachPositioningHandler =
4218
function (decorated, container) {
4221
var scrollEvent = 'scroll.select2.' + container.id;
4222
var resizeEvent = 'resize.select2.' + container.id;
4223
var orientationEvent = 'orientationchange.select2.' + container.id;
4225
var $watchers = this.$container.parents().filter(Utils.hasScroll);
4226
$watchers.each(function () {
4227
$(this).data('select2-scroll-position', {
4228
x: $(this).scrollLeft(),
4229
y: $(this).scrollTop()
4233
$watchers.on(scrollEvent, function (ev) {
4234
var position = $(this).data('select2-scroll-position');
4235
$(this).scrollTop(position.y);
4238
$(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent,
4240
self._positionDropdown();
4241
self._resizeDropdown();
4245
AttachBody.prototype._detachPositioningHandler =
4246
function (decorated, container) {
4247
var scrollEvent = 'scroll.select2.' + container.id;
4248
var resizeEvent = 'resize.select2.' + container.id;
4249
var orientationEvent = 'orientationchange.select2.' + container.id;
4251
var $watchers = this.$container.parents().filter(Utils.hasScroll);
4252
$watchers.off(scrollEvent);
4254
$(window).off(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent);
4257
AttachBody.prototype._positionDropdown = function () {
4258
var $window = $(window);
4260
var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above');
4261
var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below');
4263
var newDirection = null;
4265
var offset = this.$container.offset();
4267
offset.bottom = offset.top + this.$container.outerHeight(false);
4270
height: this.$container.outerHeight(false)
4273
container.top = offset.top;
4274
container.bottom = offset.top + container.height;
4277
height: this.$dropdown.outerHeight(false)
4281
top: $window.scrollTop(),
4282
bottom: $window.scrollTop() + $window.height()
4285
var enoughRoomAbove = viewport.top < (offset.top - dropdown.height);
4286
var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height);
4290
top: container.bottom
4293
// Determine what the parent element is to use for calciulating the offset
4294
var $offsetParent = this.$dropdownParent;
4296
// For statically positoned elements, we need to get the element
4297
// that is determining the offset
4298
if ($offsetParent.css('position') === 'static') {
4299
$offsetParent = $offsetParent.offsetParent();
4302
var parentOffset = $offsetParent.offset();
4304
css.top -= parentOffset.top;
4305
css.left -= parentOffset.left;
4307
if (!isCurrentlyAbove && !isCurrentlyBelow) {
4308
newDirection = 'below';
4311
if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) {
4312
newDirection = 'above';
4313
} else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) {
4314
newDirection = 'below';
4317
if (newDirection == 'above' ||
4318
(isCurrentlyAbove && newDirection !== 'below')) {
4319
css.top = container.top - parentOffset.top - dropdown.height;
4322
if (newDirection != null) {
4324
.removeClass('select2-dropdown--below select2-dropdown--above')
4325
.addClass('select2-dropdown--' + newDirection);
4327
.removeClass('select2-container--below select2-container--above')
4328
.addClass('select2-container--' + newDirection);
4331
this.$dropdownContainer.css(css);
4334
AttachBody.prototype._resizeDropdown = function () {
4336
width: this.$container.outerWidth(false) + 'px'
4339
if (this.options.get('dropdownAutoWidth')) {
4340
css.minWidth = css.width;
4341
css.position = 'relative';
4345
this.$dropdown.css(css);
4348
AttachBody.prototype._showDropdown = function (decorated) {
4349
this.$dropdownContainer.appendTo(this.$dropdownParent);
4351
this._positionDropdown();
4352
this._resizeDropdown();
4358
S2.define('select2/dropdown/minimumResultsForSearch',[
4361
function countResults (data) {
4364
for (var d = 0; d < data.length; d++) {
4367
if (item.children) {
4368
count += countResults(item.children);
4377
function MinimumResultsForSearch (decorated, $element, options, dataAdapter) {
4378
this.minimumResultsForSearch = options.get('minimumResultsForSearch');
4380
if (this.minimumResultsForSearch < 0) {
4381
this.minimumResultsForSearch = Infinity;
4384
decorated.call(this, $element, options, dataAdapter);
4387
MinimumResultsForSearch.prototype.showSearch = function (decorated, params) {
4388
if (countResults(params.data.results) < this.minimumResultsForSearch) {
4392
return decorated.call(this, params);
4395
return MinimumResultsForSearch;
4398
S2.define('select2/dropdown/selectOnClose',[
4401
function SelectOnClose () { }
4403
SelectOnClose.prototype.bind = function (decorated, container, $container) {
4406
decorated.call(this, container, $container);
4408
container.on('close', function (params) {
4409
self._handleSelectOnClose(params);
4413
SelectOnClose.prototype._handleSelectOnClose = function (_, params) {
4414
if (params && params.originalSelect2Event != null) {
4415
var event = params.originalSelect2Event;
4417
// Don't select an item if the close event was triggered from a select or
4419
if (event._type === 'select' || event._type === 'unselect') {
4424
var $highlightedResults = this.getHighlightedResults();
4426
// Only select highlighted results
4427
if ($highlightedResults.length < 1) {
4431
var data = $highlightedResults.data('data');
4433
// Don't re-select already selected resulte
4435
(data.element != null && data.element.selected) ||
4436
(data.element == null && data.selected)
4441
this.trigger('select', {
4446
return SelectOnClose;
4449
S2.define('select2/dropdown/closeOnSelect',[
4452
function CloseOnSelect () { }
4454
CloseOnSelect.prototype.bind = function (decorated, container, $container) {
4457
decorated.call(this, container, $container);
4459
container.on('select', function (evt) {
4460
self._selectTriggered(evt);
4463
container.on('unselect', function (evt) {
4464
self._selectTriggered(evt);
4468
CloseOnSelect.prototype._selectTriggered = function (_, evt) {
4469
var originalEvent = evt.originalEvent;
4471
// Don't close if the control key is being held
4472
if (originalEvent && originalEvent.ctrlKey) {
4476
this.trigger('close', {
4477
originalEvent: originalEvent,
4478
originalSelect2Event: evt
4482
return CloseOnSelect;
4485
S2.define('select2/i18n/en',[],function () {
4488
errorLoading: function () {
4489
return 'The results could not be loaded.';
4491
inputTooLong: function (args) {
4492
var overChars = args.input.length - args.maximum;
4494
var message = 'Please delete ' + overChars + ' character';
4496
if (overChars != 1) {
4502
inputTooShort: function (args) {
4503
var remainingChars = args.minimum - args.input.length;
4505
var message = 'Please enter ' + remainingChars + ' or more characters';
4509
loadingMore: function () {
4510
return 'Loading more results…';
4512
maximumSelected: function (args) {
4513
var message = 'You can only select ' + args.maximum + ' item';
4515
if (args.maximum != 1) {
4521
noResults: function () {
4522
return 'No results found';
4524
searching: function () {
4525
return 'Searching…';
4530
S2.define('select2/defaults',[
4536
'./selection/single',
4537
'./selection/multiple',
4538
'./selection/placeholder',
4539
'./selection/allowClear',
4540
'./selection/search',
4541
'./selection/eventRelay',
4552
'./data/minimumInputLength',
4553
'./data/maximumInputLength',
4554
'./data/maximumSelectionLength',
4557
'./dropdown/search',
4558
'./dropdown/hidePlaceholder',
4559
'./dropdown/infiniteScroll',
4560
'./dropdown/attachBody',
4561
'./dropdown/minimumResultsForSearch',
4562
'./dropdown/selectOnClose',
4563
'./dropdown/closeOnSelect',
4566
], function ($, require,
4570
SingleSelection, MultipleSelection, Placeholder, AllowClear,
4571
SelectionSearch, EventRelay,
4573
Utils, Translation, DIACRITICS,
4575
SelectData, ArrayData, AjaxData, Tags, Tokenizer,
4576
MinimumInputLength, MaximumInputLength, MaximumSelectionLength,
4578
Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll,
4579
AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect,
4581
EnglishTranslation) {
4582
function Defaults () {
4586
Defaults.prototype.apply = function (options) {
4587
options = $.extend(true, {}, this.defaults, options);
4589
if (options.dataAdapter == null) {
4590
if (options.ajax != null) {
4591
options.dataAdapter = AjaxData;
4592
} else if (options.data != null) {
4593
options.dataAdapter = ArrayData;
4595
options.dataAdapter = SelectData;
4598
if (options.minimumInputLength > 0) {
4599
options.dataAdapter = Utils.Decorate(
4600
options.dataAdapter,
4605
if (options.maximumInputLength > 0) {
4606
options.dataAdapter = Utils.Decorate(
4607
options.dataAdapter,
4612
if (options.maximumSelectionLength > 0) {
4613
options.dataAdapter = Utils.Decorate(
4614
options.dataAdapter,
4615
MaximumSelectionLength
4620
options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags);
4623
if (options.tokenSeparators != null || options.tokenizer != null) {
4624
options.dataAdapter = Utils.Decorate(
4625
options.dataAdapter,
4630
if (options.query != null) {
4631
var Query = require(options.amdBase + 'compat/query');
4633
options.dataAdapter = Utils.Decorate(
4634
options.dataAdapter,
4639
if (options.initSelection != null) {
4640
var InitSelection = require(options.amdBase + 'compat/initSelection');
4642
options.dataAdapter = Utils.Decorate(
4643
options.dataAdapter,
4649
if (options.resultsAdapter == null) {
4650
options.resultsAdapter = ResultsList;
4652
if (options.ajax != null) {
4653
options.resultsAdapter = Utils.Decorate(
4654
options.resultsAdapter,
4659
if (options.placeholder != null) {
4660
options.resultsAdapter = Utils.Decorate(
4661
options.resultsAdapter,
4666
if (options.selectOnClose) {
4667
options.resultsAdapter = Utils.Decorate(
4668
options.resultsAdapter,
4674
if (options.dropdownAdapter == null) {
4675
if (options.multiple) {
4676
options.dropdownAdapter = Dropdown;
4678
var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch);
4680
options.dropdownAdapter = SearchableDropdown;
4683
if (options.minimumResultsForSearch !== 0) {
4684
options.dropdownAdapter = Utils.Decorate(
4685
options.dropdownAdapter,
4686
MinimumResultsForSearch
4690
if (options.closeOnSelect) {
4691
options.dropdownAdapter = Utils.Decorate(
4692
options.dropdownAdapter,
4698
options.dropdownCssClass != null ||
4699
options.dropdownCss != null ||
4700
options.adaptDropdownCssClass != null
4702
var DropdownCSS = require(options.amdBase + 'compat/dropdownCss');
4704
options.dropdownAdapter = Utils.Decorate(
4705
options.dropdownAdapter,
4710
options.dropdownAdapter = Utils.Decorate(
4711
options.dropdownAdapter,
4716
if (options.selectionAdapter == null) {
4717
if (options.multiple) {
4718
options.selectionAdapter = MultipleSelection;
4720
options.selectionAdapter = SingleSelection;
4723
// Add the placeholder mixin if a placeholder was specified
4724
if (options.placeholder != null) {
4725
options.selectionAdapter = Utils.Decorate(
4726
options.selectionAdapter,
4731
if (options.allowClear) {
4732
options.selectionAdapter = Utils.Decorate(
4733
options.selectionAdapter,
4738
if (options.multiple) {
4739
options.selectionAdapter = Utils.Decorate(
4740
options.selectionAdapter,
4746
options.containerCssClass != null ||
4747
options.containerCss != null ||
4748
options.adaptContainerCssClass != null
4750
var ContainerCSS = require(options.amdBase + 'compat/containerCss');
4752
options.selectionAdapter = Utils.Decorate(
4753
options.selectionAdapter,
4758
options.selectionAdapter = Utils.Decorate(
4759
options.selectionAdapter,
4764
if (typeof options.language === 'string') {
4765
// Check if the language is specified with a region
4766
if (options.language.indexOf('-') > 0) {
4767
// Extract the region information if it is included
4768
var languageParts = options.language.split('-');
4769
var baseLanguage = languageParts[0];
4771
options.language = [options.language, baseLanguage];
4773
options.language = [options.language];
4777
if ($.isArray(options.language)) {
4778
var languages = new Translation();
4779
options.language.push('en');
4781
var languageNames = options.language;
4783
for (var l = 0; l < languageNames.length; l++) {
4784
var name = languageNames[l];
4788
// Try to load it with the original name
4789
language = Translation.loadPath(name);
4792
// If we couldn't load it, check if it wasn't the full path
4793
name = this.defaults.amdLanguageBase + name;
4794
language = Translation.loadPath(name);
4796
// The translation could not be loaded at all. Sometimes this is
4797
// because of a configuration problem, other times this can be
4798
// because of how Select2 helps load all possible translation files.
4799
if (options.debug && window.console && console.warn) {
4801
'Select2: The language file for "' + name + '" could not be ' +
4802
'automatically loaded. A fallback will be used instead.'
4810
languages.extend(language);
4813
options.translations = languages;
4815
var baseTranslation = Translation.loadPath(
4816
this.defaults.amdLanguageBase + 'en'
4818
var customTranslation = new Translation(options.language);
4820
customTranslation.extend(baseTranslation);
4822
options.translations = customTranslation;
4828
Defaults.prototype.reset = function () {
4829
function stripDiacritics (text) {
4830
// Used 'uni range + named function' from http://jsperf.com/diacritics/18
4832
return DIACRITICS[a] || a;
4835
return text.replace(/[^\u0000-\u007E]/g, match);
4838
function matcher (params, data) {
4839
// Always return the object if there is nothing to compare
4840
if ($.trim(params.term) === '') {
4844
// Do a recursive check for options with children
4845
if (data.children && data.children.length > 0) {
4846
// Clone the data object if there are children
4847
// This is required as we modify the object to remove any non-matches
4848
var match = $.extend(true, {}, data);
4850
// Check each child of the option
4851
for (var c = data.children.length - 1; c >= 0; c--) {
4852
var child = data.children[c];
4854
var matches = matcher(params, child);
4856
// If there wasn't a match, remove the object in the array
4857
if (matches == null) {
4858
match.children.splice(c, 1);
4862
// If any children matched, return the new object
4863
if (match.children.length > 0) {
4867
// If there were no matching children, check just the plain object
4868
return matcher(params, match);
4871
var original = stripDiacritics(data.text).toUpperCase();
4872
var term = stripDiacritics(params.term).toUpperCase();
4874
// Check if the text contains the term
4875
if (original.indexOf(term) > -1) {
4879
// If it doesn't contain the term, don't return anything
4885
amdLanguageBase: './i18n/',
4886
closeOnSelect: true,
4888
dropdownAutoWidth: false,
4889
escapeMarkup: Utils.escapeMarkup,
4890
language: EnglishTranslation,
4892
minimumInputLength: 0,
4893
maximumInputLength: 0,
4894
maximumSelectionLength: 0,
4895
minimumResultsForSearch: 0,
4896
selectOnClose: false,
4897
sorter: function (data) {
4900
templateResult: function (result) {
4903
templateSelection: function (selection) {
4904
return selection.text;
4911
Defaults.prototype.set = function (key, value) {
4912
var camelKey = $.camelCase(key);
4915
data[camelKey] = value;
4917
var convertedData = Utils._convertData(data);
4919
$.extend(this.defaults, convertedData);
4922
var defaults = new Defaults();
4927
S2.define('select2/options',[
4932
], function (require, $, Defaults, Utils) {
4933
function Options (options, $element) {
4934
this.options = options;
4936
if ($element != null) {
4937
this.fromElement($element);
4940
this.options = Defaults.apply(this.options);
4942
if ($element && $element.is('input')) {
4943
var InputCompat = require(this.get('amdBase') + 'compat/inputData');
4945
this.options.dataAdapter = Utils.Decorate(
4946
this.options.dataAdapter,
4952
Options.prototype.fromElement = function ($e) {
4953
var excludedData = ['select2'];
4955
if (this.options.multiple == null) {
4956
this.options.multiple = $e.prop('multiple');
4959
if (this.options.disabled == null) {
4960
this.options.disabled = $e.prop('disabled');
4963
if (this.options.language == null) {
4964
if ($e.prop('lang')) {
4965
this.options.language = $e.prop('lang').toLowerCase();
4966
} else if ($e.closest('[lang]').prop('lang')) {
4967
this.options.language = $e.closest('[lang]').prop('lang');
4971
if (this.options.dir == null) {
4972
if ($e.prop('dir')) {
4973
this.options.dir = $e.prop('dir');
4974
} else if ($e.closest('[dir]').prop('dir')) {
4975
this.options.dir = $e.closest('[dir]').prop('dir');
4977
this.options.dir = 'ltr';
4981
$e.prop('disabled', this.options.disabled);
4982
$e.prop('multiple', this.options.multiple);
4984
if ($e.data('select2Tags')) {
4985
if (this.options.debug && window.console && console.warn) {
4987
'Select2: The `data-select2-tags` attribute has been changed to ' +
4988
'use the `data-data` and `data-tags="true"` attributes and will be ' +
4989
'removed in future versions of Select2.'
4993
$e.data('data', $e.data('select2Tags'));
4994
$e.data('tags', true);
4997
if ($e.data('ajaxUrl')) {
4998
if (this.options.debug && window.console && console.warn) {
5000
'Select2: The `data-ajax-url` attribute has been changed to ' +
5001
'`data-ajax--url` and support for the old attribute will be removed' +
5002
' in future versions of Select2.'
5006
$e.attr('ajax--url', $e.data('ajaxUrl'));
5007
$e.data('ajax--url', $e.data('ajaxUrl'));
5012
// Prefer the element's `dataset` attribute if it exists
5013
// jQuery 1.x does not correctly handle data attributes with multiple dashes
5014
if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) {
5015
dataset = $.extend(true, {}, $e[0].dataset, $e.data());
5017
dataset = $e.data();
5020
var data = $.extend(true, {}, dataset);
5022
data = Utils._convertData(data);
5024
for (var key in data) {
5025
if ($.inArray(key, excludedData) > -1) {
5029
if ($.isPlainObject(this.options[key])) {
5030
$.extend(this.options[key], data[key]);
5032
this.options[key] = data[key];
5039
Options.prototype.get = function (key) {
5040
return this.options[key];
5043
Options.prototype.set = function (key, val) {
5044
this.options[key] = val;
5050
S2.define('select2/core',[
5055
], function ($, Options, Utils, KEYS) {
5056
var Select2 = function ($element, options) {
5057
if ($element.data('select2') != null) {
5058
$element.data('select2').destroy();
5061
this.$element = $element;
5063
this.id = this._generateId($element);
5065
options = options || {};
5067
this.options = new Options(options, $element);
5069
Select2.__super__.constructor.call(this);
5071
// Set up the tabindex
5073
var tabindex = $element.attr('tabindex') || 0;
5074
$element.data('old-tabindex', tabindex);
5075
$element.attr('tabindex', '-1');
5077
// Set up containers and adapters
5079
var DataAdapter = this.options.get('dataAdapter');
5080
this.dataAdapter = new DataAdapter($element, this.options);
5082
var $container = this.render();
5084
this._placeContainer($container);
5086
var SelectionAdapter = this.options.get('selectionAdapter');
5087
this.selection = new SelectionAdapter($element, this.options);
5088
this.$selection = this.selection.render();
5090
this.selection.position(this.$selection, $container);
5092
var DropdownAdapter = this.options.get('dropdownAdapter');
5093
this.dropdown = new DropdownAdapter($element, this.options);
5094
this.$dropdown = this.dropdown.render();
5096
this.dropdown.position(this.$dropdown, $container);
5098
var ResultsAdapter = this.options.get('resultsAdapter');
5099
this.results = new ResultsAdapter($element, this.options, this.dataAdapter);
5100
this.$results = this.results.render();
5102
this.results.position(this.$results, this.$dropdown);
5108
// Bind the container to all of the adapters
5109
this._bindAdapters();
5111
// Register any DOM event handlers
5112
this._registerDomEvents();
5114
// Register any internal event handlers
5115
this._registerDataEvents();
5116
this._registerSelectionEvents();
5117
this._registerDropdownEvents();
5118
this._registerResultsEvents();
5119
this._registerEvents();
5121
// Set the initial state
5122
this.dataAdapter.current(function (initialData) {
5123
self.trigger('selection:update', {
5128
// Hide the original select
5129
$element.addClass('select2-hidden-accessible');
5130
$element.attr('aria-hidden', 'true');
5132
// Synchronize any monitored attributes
5133
this._syncAttributes();
5135
$element.data('select2', this);
5138
Utils.Extend(Select2, Utils.Observable);
5140
Select2.prototype._generateId = function ($element) {
5143
if ($element.attr('id') != null) {
5144
id = $element.attr('id');
5145
} else if ($element.attr('name') != null) {
5146
id = $element.attr('name') + '-' + Utils.generateChars(2);
5148
id = Utils.generateChars(4);
5151
id = id.replace(/(:|\.|\[|\]|,)/g, '');
5152
id = 'select2-' + id;
5157
Select2.prototype._placeContainer = function ($container) {
5158
$container.insertAfter(this.$element);
5160
var width = this._resolveWidth(this.$element, this.options.get('width'));
5162
if (width != null) {
5163
$container.css('width', width);
5167
Select2.prototype._resolveWidth = function ($element, method) {
5168
var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;
5170
if (method == 'resolve') {
5171
var styleWidth = this._resolveWidth($element, 'style');
5173
if (styleWidth != null) {
5177
return this._resolveWidth($element, 'element');
5180
if (method == 'element') {
5181
var elementWidth = $element.outerWidth(false);
5183
if (elementWidth <= 0) {
5187
return elementWidth + 'px';
5190
if (method == 'style') {
5191
var style = $element.attr('style');
5193
if (typeof(style) !== 'string') {
5197
var attrs = style.split(';');
5199
for (var i = 0, l = attrs.length; i < l; i = i + 1) {
5200
var attr = attrs[i].replace(/\s/g, '');
5201
var matches = attr.match(WIDTH);
5203
if (matches !== null && matches.length >= 1) {
5214
Select2.prototype._bindAdapters = function () {
5215
this.dataAdapter.bind(this, this.$container);
5216
this.selection.bind(this, this.$container);
5218
this.dropdown.bind(this, this.$container);
5219
this.results.bind(this, this.$container);
5222
Select2.prototype._registerDomEvents = function () {
5225
this.$element.on('change.select2', function () {
5226
self.dataAdapter.current(function (data) {
5227
self.trigger('selection:update', {
5233
this.$element.on('focus.select2', function (evt) {
5234
self.trigger('focus', evt);
5237
this._syncA = Utils.bind(this._syncAttributes, this);
5238
this._syncS = Utils.bind(this._syncSubtree, this);
5240
if (this.$element[0].attachEvent) {
5241
this.$element[0].attachEvent('onpropertychange', this._syncA);
5244
var observer = window.MutationObserver ||
5245
window.WebKitMutationObserver ||
5246
window.MozMutationObserver
5249
if (observer != null) {
5250
this._observer = new observer(function (mutations) {
5251
$.each(mutations, self._syncA);
5252
$.each(mutations, self._syncS);
5254
this._observer.observe(this.$element[0], {
5259
} else if (this.$element[0].addEventListener) {
5260
this.$element[0].addEventListener(
5265
this.$element[0].addEventListener(
5270
this.$element[0].addEventListener(
5278
Select2.prototype._registerDataEvents = function () {
5281
this.dataAdapter.on('*', function (name, params) {
5282
self.trigger(name, params);
5286
Select2.prototype._registerSelectionEvents = function () {
5288
var nonRelayEvents = ['toggle', 'focus'];
5290
this.selection.on('toggle', function () {
5291
self.toggleDropdown();
5294
this.selection.on('focus', function (params) {
5298
this.selection.on('*', function (name, params) {
5299
if ($.inArray(name, nonRelayEvents) !== -1) {
5303
self.trigger(name, params);
5307
Select2.prototype._registerDropdownEvents = function () {
5310
this.dropdown.on('*', function (name, params) {
5311
self.trigger(name, params);
5315
Select2.prototype._registerResultsEvents = function () {
5318
this.results.on('*', function (name, params) {
5319
self.trigger(name, params);
5323
Select2.prototype._registerEvents = function () {
5326
this.on('open', function () {
5327
self.$container.addClass('select2-container--open');
5330
this.on('close', function () {
5331
self.$container.removeClass('select2-container--open');
5334
this.on('enable', function () {
5335
self.$container.removeClass('select2-container--disabled');
5338
this.on('disable', function () {
5339
self.$container.addClass('select2-container--disabled');
5342
this.on('blur', function () {
5343
self.$container.removeClass('select2-container--focus');
5346
this.on('query', function (params) {
5347
if (!self.isOpen()) {
5348
self.trigger('open', {});
5351
this.dataAdapter.query(params, function (data) {
5352
self.trigger('results:all', {
5359
this.on('query:append', function (params) {
5360
this.dataAdapter.query(params, function (data) {
5361
self.trigger('results:append', {
5368
this.on('keypress', function (evt) {
5369
var key = evt.which;
5371
if (self.isOpen()) {
5372
if (key === KEYS.ESC || key === KEYS.TAB ||
5373
(key === KEYS.UP && evt.altKey)) {
5376
evt.preventDefault();
5377
} else if (key === KEYS.ENTER) {
5378
self.trigger('results:select', {});
5380
evt.preventDefault();
5381
} else if ((key === KEYS.SPACE && evt.ctrlKey)) {
5382
self.trigger('results:toggle', {});
5384
evt.preventDefault();
5385
} else if (key === KEYS.UP) {
5386
self.trigger('results:previous', {});
5388
evt.preventDefault();
5389
} else if (key === KEYS.DOWN) {
5390
self.trigger('results:next', {});
5392
evt.preventDefault();
5395
if (key === KEYS.ENTER || key === KEYS.SPACE ||
5396
(key === KEYS.DOWN && evt.altKey)) {
5399
evt.preventDefault();
5405
Select2.prototype._syncAttributes = function () {
5406
this.options.set('disabled', this.$element.prop('disabled'));
5408
if (this.options.get('disabled')) {
5409
if (this.isOpen()) {
5413
this.trigger('disable', {});
5415
this.trigger('enable', {});
5419
Select2.prototype._syncSubtree = function (evt, mutations) {
5420
var changed = false;
5423
// Ignore any mutation events raised for elements that aren't options or
5424
// optgroups. This handles the case when the select element is destroyed
5426
evt && evt.target && (
5427
evt.target.nodeName !== 'OPTION' && evt.target.nodeName !== 'OPTGROUP'
5434
// If mutation events aren't supported, then we can only assume that the
5435
// change affected the selections
5437
} else if (mutations.addedNodes && mutations.addedNodes.length > 0) {
5438
for (var n = 0; n < mutations.addedNodes.length; n++) {
5439
var node = mutations.addedNodes[n];
5441
if (node.selected) {
5445
} else if (mutations.removedNodes && mutations.removedNodes.length > 0) {
5449
// Only re-pull the data if we think there is a change
5451
this.dataAdapter.current(function (currentData) {
5452
self.trigger('selection:update', {
5460
* Override the trigger method to automatically trigger pre-events when
5461
* there are events that can be prevented.
5463
Select2.prototype.trigger = function (name, args) {
5464
var actualTrigger = Select2.__super__.trigger;
5465
var preTriggerMap = {
5468
'select': 'selecting',
5469
'unselect': 'unselecting'
5472
if (args === undefined) {
5476
if (name in preTriggerMap) {
5477
var preTriggerName = preTriggerMap[name];
5478
var preTriggerArgs = {
5484
actualTrigger.call(this, preTriggerName, preTriggerArgs);
5486
if (preTriggerArgs.prevented) {
5487
args.prevented = true;
5493
actualTrigger.call(this, name, args);
5496
Select2.prototype.toggleDropdown = function () {
5497
if (this.options.get('disabled')) {
5501
if (this.isOpen()) {
5508
Select2.prototype.open = function () {
5509
if (this.isOpen()) {
5513
this.trigger('query', {});
5516
Select2.prototype.close = function () {
5517
if (!this.isOpen()) {
5521
this.trigger('close', {});
5524
Select2.prototype.isOpen = function () {
5525
return this.$container.hasClass('select2-container--open');
5528
Select2.prototype.hasFocus = function () {
5529
return this.$container.hasClass('select2-container--focus');
5532
Select2.prototype.focus = function (data) {
5533
// No need to re-trigger focus events if we are already focused
5534
if (this.hasFocus()) {
5538
this.$container.addClass('select2-container--focus');
5539
this.trigger('focus', {});
5542
Select2.prototype.enable = function (args) {
5543
if (this.options.get('debug') && window.console && console.warn) {
5545
'Select2: The `select2("enable")` method has been deprecated and will' +
5546
' be removed in later Select2 versions. Use $element.prop("disabled")' +
5551
if (args == null || args.length === 0) {
5555
var disabled = !args[0];
5557
this.$element.prop('disabled', disabled);
5560
Select2.prototype.data = function () {
5561
if (this.options.get('debug') &&
5562
arguments.length > 0 && window.console && console.warn) {
5564
'Select2: Data can no longer be set using `select2("data")`. You ' +
5565
'should consider setting the value instead using `$element.val()`.'
5571
this.dataAdapter.current(function (currentData) {
5578
Select2.prototype.val = function (args) {
5579
if (this.options.get('debug') && window.console && console.warn) {
5581
'Select2: The `select2("val")` method has been deprecated and will be' +
5582
' removed in later Select2 versions. Use $element.val() instead.'
5586
if (args == null || args.length === 0) {
5587
return this.$element.val();
5590
var newVal = args[0];
5592
if ($.isArray(newVal)) {
5593
newVal = $.map(newVal, function (obj) {
5594
return obj.toString();
5598
this.$element.val(newVal).trigger('change');
5601
Select2.prototype.destroy = function () {
5602
this.$container.remove();
5604
if (this.$element[0].detachEvent) {
5605
this.$element[0].detachEvent('onpropertychange', this._syncA);
5608
if (this._observer != null) {
5609
this._observer.disconnect();
5610
this._observer = null;
5611
} else if (this.$element[0].removeEventListener) {
5613
.removeEventListener('DOMAttrModified', this._syncA, false);
5615
.removeEventListener('DOMNodeInserted', this._syncS, false);
5617
.removeEventListener('DOMNodeRemoved', this._syncS, false);
5623
this.$element.off('.select2');
5624
this.$element.attr('tabindex', this.$element.data('old-tabindex'));
5626
this.$element.removeClass('select2-hidden-accessible');
5627
this.$element.attr('aria-hidden', 'false');
5628
this.$element.removeData('select2');
5630
this.dataAdapter.destroy();
5631
this.selection.destroy();
5632
this.dropdown.destroy();
5633
this.results.destroy();
5635
this.dataAdapter = null;
5636
this.selection = null;
5637
this.dropdown = null;
5638
this.results = null;
5641
Select2.prototype.render = function () {
5643
'<span class="select2 select2-container">' +
5644
'<span class="selection"></span>' +
5645
'<span class="dropdown-wrapper" aria-hidden="true"></span>' +
5649
$container.attr('dir', this.options.get('dir'));
5651
this.$container = $container;
5653
this.$container.addClass('select2-container--' + this.options.get('theme'));
5655
$container.data('element', this.$element);
5663
S2.define('jquery-mousewheel',[
5666
// Used to shim jQuery.mousewheel for non-full builds.
5670
S2.define('jquery.select2',[
5672
'jquery-mousewheel',
5675
'./select2/defaults'
5676
], function ($, _, Select2, Defaults) {
5677
if ($.fn.select2 == null) {
5678
// All methods that should return the element
5679
var thisMethods = ['open', 'close', 'destroy'];
5681
$.fn.select2 = function (options) {
5682
options = options || {};
5684
if (typeof options === 'object') {
5685
this.each(function () {
5686
var instanceOptions = $.extend(true, {}, options);
5688
var instance = new Select2($(this), instanceOptions);
5692
} else if (typeof options === 'string') {
5694
var args = Array.prototype.slice.call(arguments, 1);
5696
this.each(function () {
5697
var instance = $(this).data('select2');
5699
if (instance == null && window.console && console.error) {
5701
'The select2(\'' + options + '\') method was called on an ' +
5702
'element that is not using Select2.'
5706
ret = instance[options].apply(instance, args);
5709
// Check if we should be returning `this`
5710
if ($.inArray(options, thisMethods) > -1) {
5716
throw new Error('Invalid arguments for Select2: ' + options);
5721
if ($.fn.select2.defaults == null) {
5722
$.fn.select2.defaults = Defaults;
5728
// Return the AMD loader configuration so it can be used outside of this file
5735
// Autoload the jQuery bindings
5736
// We know that all of the modules exist above this, so we're safe
5737
var select2 = S2.require('jquery.select2');
5739
// Hold the AMD module references on the jQuery function that was just loaded
5740
// This allows Select2 to use the internal loader outside of this file, such
5741
// as in the language files.
5742
jQuery.fn.select2.amd = S2;
5744
// Return the Select2 instance for anyone who is importing it.