source: public/vendors/select2/js/select2.js@ e651d0d

develop
Last change on this file since e651d0d was 7304c7f, checked in by beratkjufliju <kufliju@…>, 3 years ago

added user authentication, create & forgot password methods and blades

  • Property mode set to 100644
File size: 142.8 KB
Line 
1/*!
2 * Select2 4.0.6-rc.1
3 * https://select2.github.io
4 *
5 * Released under the MIT license
6 * https://github.com/select2/select2/blob/master/LICENSE.md
7 */
8;(function (factory) {
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) {
13 // Node/CommonJS
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');
22 }
23 else {
24 jQuery = require('jquery')(root);
25 }
26 }
27 factory(jQuery);
28 return jQuery;
29 };
30 } else {
31 // Browser globals
32 factory(jQuery);
33 }
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;
43 }
44var S2;(function () { if (!S2 || !S2.requirejs) {
45if (!S2) { S2 = {}; } else { require = S2; }
46/**
47 * @license almond 0.3.3 Copyright jQuery Foundation and other contributors.
48 * Released under MIT license, http://github.com/requirejs/almond/LICENSE
49 */
50//Going sloppy to avoid 'use strict' string cost, but strict practices should
51//be followed.
52/*global setTimeout: false */
53
54var requirejs, require, define;
55(function (undef) {
56 var main, req, makeMap, handlers,
57 defined = {},
58 waiting = {},
59 config = {},
60 defining = {},
61 hasOwn = Object.prototype.hasOwnProperty,
62 aps = [].slice,
63 jsSuffixRegExp = /\.js$/;
64
65 function hasProp(obj, prop) {
66 return hasOwn.call(obj, prop);
67 }
68
69 /**
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
74 * to.
75 * @returns {String} normalized name
76 */
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("/"),
81 map = config.map,
82 starMap = (map && map['*']) || {};
83
84 //Adjust any relative paths.
85 if (name) {
86 name = name.split('/');
87 lastIndex = name.length - 1;
88
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
92 // to same file.
93 if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
94 name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
95 }
96
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);
106 }
107
108 //start trimDots
109 for (i = 0; i < name.length; i++) {
110 part = name[i];
111 if (part === '.') {
112 name.splice(i, 1);
113 i -= 1;
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] === '..') {
121 continue;
122 } else if (i > 0) {
123 name.splice(i - 1, 2);
124 i -= 2;
125 }
126 }
127 }
128 //end trimDots
129
130 name = name.join('/');
131 }
132
133 //Apply map config if available.
134 if ((baseParts || starMap) && map) {
135 nameParts = name.split('/');
136
137 for (i = nameParts.length; i > 0; i -= 1) {
138 nameSegment = nameParts.slice(0, i).join("/");
139
140 if (baseParts) {
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('/')];
145
146 //baseName segment has config, find if it has one for
147 //this name.
148 if (mapValue) {
149 mapValue = mapValue[nameSegment];
150 if (mapValue) {
151 //Match, update name to the new value.
152 foundMap = mapValue;
153 foundI = i;
154 break;
155 }
156 }
157 }
158 }
159
160 if (foundMap) {
161 break;
162 }
163
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];
169 starI = i;
170 }
171 }
172
173 if (!foundMap && foundStarMap) {
174 foundMap = foundStarMap;
175 foundI = starI;
176 }
177
178 if (foundMap) {
179 nameParts.splice(0, foundI, foundMap);
180 name = nameParts.join('/');
181 }
182 }
183
184 return name;
185 }
186
187 function makeRequire(relName, forceSync) {
188 return function () {
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);
193
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) {
198 args.push(null);
199 }
200 return req.apply(undef, args.concat([relName, forceSync]));
201 };
202 }
203
204 function makeNormalize(relName) {
205 return function (name) {
206 return normalize(name, relName);
207 };
208 }
209
210 function makeLoad(depName) {
211 return function (value) {
212 defined[depName] = value;
213 };
214 }
215
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);
222 }
223
224 if (!hasProp(defined, name) && !hasProp(defining, name)) {
225 throw new Error('No ' + name);
226 }
227 return defined[name];
228 }
229
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) {
234 var prefix,
235 index = name ? name.indexOf('!') : -1;
236 if (index > -1) {
237 prefix = name.substring(0, index);
238 name = name.substring(index + 1, name.length);
239 }
240 return [prefix, name];
241 }
242
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) : [];
247 }
248
249 /**
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.
253 */
254 makeMap = function (name, relParts) {
255 var plugin,
256 parts = splitPrefix(name),
257 prefix = parts[0],
258 relResourceName = relParts[1];
259
260 name = parts[1];
261
262 if (prefix) {
263 prefix = normalize(prefix, relResourceName);
264 plugin = callDep(prefix);
265 }
266
267 //Normalize according
268 if (prefix) {
269 if (plugin && plugin.normalize) {
270 name = plugin.normalize(name, makeNormalize(relResourceName));
271 } else {
272 name = normalize(name, relResourceName);
273 }
274 } else {
275 name = normalize(name, relResourceName);
276 parts = splitPrefix(name);
277 prefix = parts[0];
278 name = parts[1];
279 if (prefix) {
280 plugin = callDep(prefix);
281 }
282 }
283
284 //Using ridiculous property names for space reasons
285 return {
286 f: prefix ? prefix + '!' + name : name, //fullName
287 n: name,
288 pr: prefix,
289 p: plugin
290 };
291 };
292
293 function makeConfig(name) {
294 return function () {
295 return (config && config.config && config.config[name]) || {};
296 };
297 }
298
299 handlers = {
300 require: function (name) {
301 return makeRequire(name);
302 },
303 exports: function (name) {
304 var e = defined[name];
305 if (typeof e !== 'undefined') {
306 return e;
307 } else {
308 return (defined[name] = {});
309 }
310 },
311 module: function (name) {
312 return {
313 id: name,
314 uri: '',
315 exports: defined[name],
316 config: makeConfig(name)
317 };
318 }
319 };
320
321 main = function (name, deps, callback, relName) {
322 var cjsModule, depName, ret, map, i, relParts,
323 args = [],
324 callbackType = typeof callback,
325 usingExports;
326
327 //Use name if no relName
328 relName = relName || name;
329 relParts = makeRelParts(relName);
330
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);
339 depName = map.f;
340
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);
347 usingExports = true;
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);
355 } else if (map.p) {
356 map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
357 args[i] = defined[depName];
358 } else {
359 throw new Error(name + ' missing ' + depName);
360 }
361 }
362
363 ret = callback ? callback.apply(defined[name], args) : undefined;
364
365 if (name) {
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.
374 defined[name] = ret;
375 }
376 }
377 } else if (name) {
378 //May just be an object definition for the module. Only
379 //worry about defining if have a module name.
380 defined[name] = callback;
381 }
382 };
383
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);
389 }
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.
397 config = deps;
398 if (config.deps) {
399 req(config.deps, config.callback);
400 }
401 if (!callback) {
402 return;
403 }
404
405 if (callback.splice) {
406 //callback is an array, which means it is a dependency list.
407 //Adjust args if there are dependencies
408 deps = callback;
409 callback = relName;
410 relName = null;
411 } else {
412 deps = undef;
413 }
414 }
415
416 //Support require(['a'])
417 callback = callback || function () {};
418
419 //If relName is a function, it is an errback handler,
420 //so remove it.
421 if (typeof relName === 'function') {
422 relName = forceSync;
423 forceSync = alt;
424 }
425
426 //Simulate async callback;
427 if (forceSync) {
428 main(undef, deps, callback, relName);
429 } else {
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);
438 }, 4);
439 }
440
441 return req;
442 };
443
444 /**
445 * Just drops the config on the floor, but returns req in case
446 * the config return value is used.
447 */
448 req.config = function (cfg) {
449 return req(cfg);
450 };
451
452 /**
453 * Expose module registry for debugging and tooling
454 */
455 requirejs._defined = defined;
456
457 define = function (name, deps, callback) {
458 if (typeof name !== 'string') {
459 throw new Error('See almond README: incorrect module build, no module name');
460 }
461
462 //This module may not have dependencies
463 if (!deps.splice) {
464 //deps is not an array, so probably means
465 //an object literal or factory function for
466 //the value. Adjust args.
467 callback = deps;
468 deps = [];
469 }
470
471 if (!hasProp(defined, name) && !hasProp(waiting, name)) {
472 waiting[name] = [name, deps, callback];
473 }
474 };
475
476 define.amd = {
477 jQuery: true
478 };
479}());
480
481S2.requirejs = requirejs;S2.require = require;S2.define = define;
482}
483}());
484S2.define("almond", function(){});
485
486/* global jQuery:false, $:false */
487S2.define('jquery',[],function () {
488 var _$ = jQuery || $;
489
490 if (_$ == null && console && console.error) {
491 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 ' +
494 'web page.'
495 );
496 }
497
498 return _$;
499});
500
501S2.define('select2/utils',[
502 'jquery'
503], function ($) {
504 var Utils = {};
505
506 Utils.Extend = function (ChildClass, SuperClass) {
507 var __hasProp = {}.hasOwnProperty;
508
509 function BaseConstructor () {
510 this.constructor = ChildClass;
511 }
512
513 for (var key in SuperClass) {
514 if (__hasProp.call(SuperClass, key)) {
515 ChildClass[key] = SuperClass[key];
516 }
517 }
518
519 BaseConstructor.prototype = SuperClass.prototype;
520 ChildClass.prototype = new BaseConstructor();
521 ChildClass.__super__ = SuperClass.prototype;
522
523 return ChildClass;
524 };
525
526 function getMethods (theClass) {
527 var proto = theClass.prototype;
528
529 var methods = [];
530
531 for (var methodName in proto) {
532 var m = proto[methodName];
533
534 if (typeof m !== 'function') {
535 continue;
536 }
537
538 if (methodName === 'constructor') {
539 continue;
540 }
541
542 methods.push(methodName);
543 }
544
545 return methods;
546 }
547
548 Utils.Decorate = function (SuperClass, DecoratorClass) {
549 var decoratedMethods = getMethods(DecoratorClass);
550 var superMethods = getMethods(SuperClass);
551
552 function DecoratedClass () {
553 var unshift = Array.prototype.unshift;
554
555 var argCount = DecoratorClass.prototype.constructor.length;
556
557 var calledConstructor = SuperClass.prototype.constructor;
558
559 if (argCount > 0) {
560 unshift.call(arguments, SuperClass.prototype.constructor);
561
562 calledConstructor = DecoratorClass.prototype.constructor;
563 }
564
565 calledConstructor.apply(this, arguments);
566 }
567
568 DecoratorClass.displayName = SuperClass.displayName;
569
570 function ctr () {
571 this.constructor = DecoratedClass;
572 }
573
574 DecoratedClass.prototype = new ctr();
575
576 for (var m = 0; m < superMethods.length; m++) {
577 var superMethod = superMethods[m];
578
579 DecoratedClass.prototype[superMethod] =
580 SuperClass.prototype[superMethod];
581 }
582
583 var calledMethod = function (methodName) {
584 // Stub out the original method if it's not decorating an actual method
585 var originalMethod = function () {};
586
587 if (methodName in DecoratedClass.prototype) {
588 originalMethod = DecoratedClass.prototype[methodName];
589 }
590
591 var decoratedMethod = DecoratorClass.prototype[methodName];
592
593 return function () {
594 var unshift = Array.prototype.unshift;
595
596 unshift.call(arguments, originalMethod);
597
598 return decoratedMethod.apply(this, arguments);
599 };
600 };
601
602 for (var d = 0; d < decoratedMethods.length; d++) {
603 var decoratedMethod = decoratedMethods[d];
604
605 DecoratedClass.prototype[decoratedMethod] = calledMethod(decoratedMethod);
606 }
607
608 return DecoratedClass;
609 };
610
611 var Observable = function () {
612 this.listeners = {};
613 };
614
615 Observable.prototype.on = function (event, callback) {
616 this.listeners = this.listeners || {};
617
618 if (event in this.listeners) {
619 this.listeners[event].push(callback);
620 } else {
621 this.listeners[event] = [callback];
622 }
623 };
624
625 Observable.prototype.trigger = function (event) {
626 var slice = Array.prototype.slice;
627 var params = slice.call(arguments, 1);
628
629 this.listeners = this.listeners || {};
630
631 // Params should always come in as an array
632 if (params == null) {
633 params = [];
634 }
635
636 // If there are no arguments to the event, use a temporary object
637 if (params.length === 0) {
638 params.push({});
639 }
640
641 // Set the `_type` of the first object to the event
642 params[0]._type = event;
643
644 if (event in this.listeners) {
645 this.invoke(this.listeners[event], slice.call(arguments, 1));
646 }
647
648 if ('*' in this.listeners) {
649 this.invoke(this.listeners['*'], arguments);
650 }
651 };
652
653 Observable.prototype.invoke = function (listeners, params) {
654 for (var i = 0, len = listeners.length; i < len; i++) {
655 listeners[i].apply(this, params);
656 }
657 };
658
659 Utils.Observable = Observable;
660
661 Utils.generateChars = function (length) {
662 var chars = '';
663
664 for (var i = 0; i < length; i++) {
665 var randomChar = Math.floor(Math.random() * 36);
666 chars += randomChar.toString(36);
667 }
668
669 return chars;
670 };
671
672 Utils.bind = function (func, context) {
673 return function () {
674 func.apply(context, arguments);
675 };
676 };
677
678 Utils._convertData = function (data) {
679 for (var originalKey in data) {
680 var keys = originalKey.split('-');
681
682 var dataLevel = data;
683
684 if (keys.length === 1) {
685 continue;
686 }
687
688 for (var k = 0; k < keys.length; k++) {
689 var key = keys[k];
690
691 // Lowercase the first letter
692 // By default, dash-separated becomes camelCase
693 key = key.substring(0, 1).toLowerCase() + key.substring(1);
694
695 if (!(key in dataLevel)) {
696 dataLevel[key] = {};
697 }
698
699 if (k == keys.length - 1) {
700 dataLevel[key] = data[originalKey];
701 }
702
703 dataLevel = dataLevel[key];
704 }
705
706 delete data[originalKey];
707 }
708
709 return data;
710 };
711
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.
718
719 var $el = $(el);
720 var overflowX = el.style.overflowX;
721 var overflowY = el.style.overflowY;
722
723 //Check both x and y declarations
724 if (overflowX === overflowY &&
725 (overflowY === 'hidden' || overflowY === 'visible')) {
726 return false;
727 }
728
729 if (overflowX === 'scroll' || overflowY === 'scroll') {
730 return true;
731 }
732
733 return ($el.innerHeight() < el.scrollHeight ||
734 $el.innerWidth() < el.scrollWidth);
735 };
736
737 Utils.escapeMarkup = function (markup) {
738 var replaceMap = {
739 '\\': '&#92;',
740 '&': '&amp;',
741 '<': '&lt;',
742 '>': '&gt;',
743 '"': '&quot;',
744 '\'': '&#39;',
745 '/': '&#47;'
746 };
747
748 // Do not try to escape the markup if it's not a string
749 if (typeof markup !== 'string') {
750 return markup;
751 }
752
753 return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
754 return replaceMap[match];
755 });
756 };
757
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') {
763 var $jqNodes = $();
764
765 $.map($nodes, function (node) {
766 $jqNodes = $jqNodes.add(node);
767 });
768
769 $nodes = $jqNodes;
770 }
771
772 $element.append($nodes);
773 };
774
775 // Cache objects in Utils.__cache instead of $.data (see #4346)
776 Utils.__cache = {};
777
778 var id = 0;
779 Utils.GetUniqueElementId = function (element) {
780 // Get a unique element Id. If element has no id,
781 // creates a new unique number, stores it in the id
782 // attribute and returns the new id.
783 // If an id already exists, it simply returns it.
784
785 var select2Id = element.getAttribute('data-select2-id');
786 if (select2Id == null) {
787 // If element has id, use it.
788 if (element.id) {
789 select2Id = element.id;
790 element.setAttribute('data-select2-id', select2Id);
791 } else {
792 element.setAttribute('data-select2-id', ++id);
793 select2Id = id.toString();
794 }
795 }
796 return select2Id;
797 };
798
799 Utils.StoreData = function (element, name, value) {
800 // Stores an item in the cache for a specified element.
801 // name is the cache key.
802 var id = Utils.GetUniqueElementId(element);
803 if (!Utils.__cache[id]) {
804 Utils.__cache[id] = {};
805 }
806
807 Utils.__cache[id][name] = value;
808 };
809
810 Utils.GetData = function (element, name) {
811 // Retrieves a value from the cache by its key (name)
812 // name is optional. If no name specified, return
813 // all cache items for the specified element.
814 // and for a specified element.
815 var id = Utils.GetUniqueElementId(element);
816 if (name) {
817 if (Utils.__cache[id]) {
818 return Utils.__cache[id][name] != null ?
819 Utils.__cache[id][name]:
820 $(element).data(name); // Fallback to HTML5 data attribs.
821 }
822 return $(element).data(name); // Fallback to HTML5 data attribs.
823 } else {
824 return Utils.__cache[id];
825 }
826 };
827
828 Utils.RemoveData = function (element) {
829 // Removes all cached items for a specified element.
830 var id = Utils.GetUniqueElementId(element);
831 if (Utils.__cache[id] != null) {
832 delete Utils.__cache[id];
833 }
834 };
835
836 return Utils;
837});
838
839S2.define('select2/results',[
840 'jquery',
841 './utils'
842], function ($, Utils) {
843 function Results ($element, options, dataAdapter) {
844 this.$element = $element;
845 this.data = dataAdapter;
846 this.options = options;
847
848 Results.__super__.constructor.call(this);
849 }
850
851 Utils.Extend(Results, Utils.Observable);
852
853 Results.prototype.render = function () {
854 var $results = $(
855 '<ul class="select2-results__options" role="tree"></ul>'
856 );
857
858 if (this.options.get('multiple')) {
859 $results.attr('aria-multiselectable', 'true');
860 }
861
862 this.$results = $results;
863
864 return $results;
865 };
866
867 Results.prototype.clear = function () {
868 this.$results.empty();
869 };
870
871 Results.prototype.displayMessage = function (params) {
872 var escapeMarkup = this.options.get('escapeMarkup');
873
874 this.clear();
875 this.hideLoading();
876
877 var $message = $(
878 '<li role="treeitem" aria-live="assertive"' +
879 ' class="select2-results__option"></li>'
880 );
881
882 var message = this.options.get('translations').get(params.message);
883
884 $message.append(
885 escapeMarkup(
886 message(params.args)
887 )
888 );
889
890 $message[0].className += ' select2-results__message';
891
892 this.$results.append($message);
893 };
894
895 Results.prototype.hideMessages = function () {
896 this.$results.find('.select2-results__message').remove();
897 };
898
899 Results.prototype.append = function (data) {
900 this.hideLoading();
901
902 var $options = [];
903
904 if (data.results == null || data.results.length === 0) {
905 if (this.$results.children().length === 0) {
906 this.trigger('results:message', {
907 message: 'noResults'
908 });
909 }
910
911 return;
912 }
913
914 data.results = this.sort(data.results);
915
916 for (var d = 0; d < data.results.length; d++) {
917 var item = data.results[d];
918
919 var $option = this.option(item);
920
921 $options.push($option);
922 }
923
924 this.$results.append($options);
925 };
926
927 Results.prototype.position = function ($results, $dropdown) {
928 var $resultsContainer = $dropdown.find('.select2-results');
929 $resultsContainer.append($results);
930 };
931
932 Results.prototype.sort = function (data) {
933 var sorter = this.options.get('sorter');
934
935 return sorter(data);
936 };
937
938 Results.prototype.highlightFirstItem = function () {
939 var $options = this.$results
940 .find('.select2-results__option[aria-selected]');
941
942 var $selected = $options.filter('[aria-selected=true]');
943
944 // Check if there are any selected options
945 if ($selected.length > 0) {
946 // If there are selected options, highlight the first
947 $selected.first().trigger('mouseenter');
948 } else {
949 // If there are no selected options, highlight the first option
950 // in the dropdown
951 $options.first().trigger('mouseenter');
952 }
953
954 this.ensureHighlightVisible();
955 };
956
957 Results.prototype.setClasses = function () {
958 var self = this;
959
960 this.data.current(function (selected) {
961 var selectedIds = $.map(selected, function (s) {
962 return s.id.toString();
963 });
964
965 var $options = self.$results
966 .find('.select2-results__option[aria-selected]');
967
968 $options.each(function () {
969 var $option = $(this);
970
971 var item = Utils.GetData(this, 'data');
972
973 // id needs to be converted to a string when comparing
974 var id = '' + item.id;
975
976 if ((item.element != null && item.element.selected) ||
977 (item.element == null && $.inArray(id, selectedIds) > -1)) {
978 $option.attr('aria-selected', 'true');
979 } else {
980 $option.attr('aria-selected', 'false');
981 }
982 });
983
984 });
985 };
986
987 Results.prototype.showLoading = function (params) {
988 this.hideLoading();
989
990 var loadingMore = this.options.get('translations').get('searching');
991
992 var loading = {
993 disabled: true,
994 loading: true,
995 text: loadingMore(params)
996 };
997 var $loading = this.option(loading);
998 $loading.className += ' loading-results';
999
1000 this.$results.prepend($loading);
1001 };
1002
1003 Results.prototype.hideLoading = function () {
1004 this.$results.find('.loading-results').remove();
1005 };
1006
1007 Results.prototype.option = function (data) {
1008 var option = document.createElement('li');
1009 option.className = 'select2-results__option';
1010
1011 var attrs = {
1012 'role': 'treeitem',
1013 'aria-selected': 'false'
1014 };
1015
1016 if (data.disabled) {
1017 delete attrs['aria-selected'];
1018 attrs['aria-disabled'] = 'true';
1019 }
1020
1021 if (data.id == null) {
1022 delete attrs['aria-selected'];
1023 }
1024
1025 if (data._resultId != null) {
1026 option.id = data._resultId;
1027 }
1028
1029 if (data.title) {
1030 option.title = data.title;
1031 }
1032
1033 if (data.children) {
1034 attrs.role = 'group';
1035 attrs['aria-label'] = data.text;
1036 delete attrs['aria-selected'];
1037 }
1038
1039 for (var attr in attrs) {
1040 var val = attrs[attr];
1041
1042 option.setAttribute(attr, val);
1043 }
1044
1045 if (data.children) {
1046 var $option = $(option);
1047
1048 var label = document.createElement('strong');
1049 label.className = 'select2-results__group';
1050
1051 var $label = $(label);
1052 this.template(data, label);
1053
1054 var $children = [];
1055
1056 for (var c = 0; c < data.children.length; c++) {
1057 var child = data.children[c];
1058
1059 var $child = this.option(child);
1060
1061 $children.push($child);
1062 }
1063
1064 var $childrenContainer = $('<ul></ul>', {
1065 'class': 'select2-results__options select2-results__options--nested'
1066 });
1067
1068 $childrenContainer.append($children);
1069
1070 $option.append(label);
1071 $option.append($childrenContainer);
1072 } else {
1073 this.template(data, option);
1074 }
1075
1076 Utils.StoreData(option, 'data', data);
1077
1078 return option;
1079 };
1080
1081 Results.prototype.bind = function (container, $container) {
1082 var self = this;
1083
1084 var id = container.id + '-results';
1085
1086 this.$results.attr('id', id);
1087
1088 container.on('results:all', function (params) {
1089 self.clear();
1090 self.append(params.data);
1091
1092 if (container.isOpen()) {
1093 self.setClasses();
1094 self.highlightFirstItem();
1095 }
1096 });
1097
1098 container.on('results:append', function (params) {
1099 self.append(params.data);
1100
1101 if (container.isOpen()) {
1102 self.setClasses();
1103 }
1104 });
1105
1106 container.on('query', function (params) {
1107 self.hideMessages();
1108 self.showLoading(params);
1109 });
1110
1111 container.on('select', function () {
1112 if (!container.isOpen()) {
1113 return;
1114 }
1115
1116 self.setClasses();
1117 self.highlightFirstItem();
1118 });
1119
1120 container.on('unselect', function () {
1121 if (!container.isOpen()) {
1122 return;
1123 }
1124
1125 self.setClasses();
1126 self.highlightFirstItem();
1127 });
1128
1129 container.on('open', function () {
1130 // When the dropdown is open, aria-expended="true"
1131 self.$results.attr('aria-expanded', 'true');
1132 self.$results.attr('aria-hidden', 'false');
1133
1134 self.setClasses();
1135 self.ensureHighlightVisible();
1136 });
1137
1138 container.on('close', function () {
1139 // When the dropdown is closed, aria-expended="false"
1140 self.$results.attr('aria-expanded', 'false');
1141 self.$results.attr('aria-hidden', 'true');
1142 self.$results.removeAttr('aria-activedescendant');
1143 });
1144
1145 container.on('results:toggle', function () {
1146 var $highlighted = self.getHighlightedResults();
1147
1148 if ($highlighted.length === 0) {
1149 return;
1150 }
1151
1152 $highlighted.trigger('mouseup');
1153 });
1154
1155 container.on('results:select', function () {
1156 var $highlighted = self.getHighlightedResults();
1157
1158 if ($highlighted.length === 0) {
1159 return;
1160 }
1161
1162 var data = Utils.GetData($highlighted[0], 'data');
1163
1164 if ($highlighted.attr('aria-selected') == 'true') {
1165 self.trigger('close', {});
1166 } else {
1167 self.trigger('select', {
1168 data: data
1169 });
1170 }
1171 });
1172
1173 container.on('results:previous', function () {
1174 var $highlighted = self.getHighlightedResults();
1175
1176 var $options = self.$results.find('[aria-selected]');
1177
1178 var currentIndex = $options.index($highlighted);
1179
1180 // If we are already at te top, don't move further
1181 // If no options, currentIndex will be -1
1182 if (currentIndex <= 0) {
1183 return;
1184 }
1185
1186 var nextIndex = currentIndex - 1;
1187
1188 // If none are highlighted, highlight the first
1189 if ($highlighted.length === 0) {
1190 nextIndex = 0;
1191 }
1192
1193 var $next = $options.eq(nextIndex);
1194
1195 $next.trigger('mouseenter');
1196
1197 var currentOffset = self.$results.offset().top;
1198 var nextTop = $next.offset().top;
1199 var nextOffset = self.$results.scrollTop() + (nextTop - currentOffset);
1200
1201 if (nextIndex === 0) {
1202 self.$results.scrollTop(0);
1203 } else if (nextTop - currentOffset < 0) {
1204 self.$results.scrollTop(nextOffset);
1205 }
1206 });
1207
1208 container.on('results:next', function () {
1209 var $highlighted = self.getHighlightedResults();
1210
1211 var $options = self.$results.find('[aria-selected]');
1212
1213 var currentIndex = $options.index($highlighted);
1214
1215 var nextIndex = currentIndex + 1;
1216
1217 // If we are at the last option, stay there
1218 if (nextIndex >= $options.length) {
1219 return;
1220 }
1221
1222 var $next = $options.eq(nextIndex);
1223
1224 $next.trigger('mouseenter');
1225
1226 var currentOffset = self.$results.offset().top +
1227 self.$results.outerHeight(false);
1228 var nextBottom = $next.offset().top + $next.outerHeight(false);
1229 var nextOffset = self.$results.scrollTop() + nextBottom - currentOffset;
1230
1231 if (nextIndex === 0) {
1232 self.$results.scrollTop(0);
1233 } else if (nextBottom > currentOffset) {
1234 self.$results.scrollTop(nextOffset);
1235 }
1236 });
1237
1238 container.on('results:focus', function (params) {
1239 params.element.addClass('select2-results__option--highlighted');
1240 });
1241
1242 container.on('results:message', function (params) {
1243 self.displayMessage(params);
1244 });
1245
1246 if ($.fn.mousewheel) {
1247 this.$results.on('mousewheel', function (e) {
1248 var top = self.$results.scrollTop();
1249
1250 var bottom = self.$results.get(0).scrollHeight - top + e.deltaY;
1251
1252 var isAtTop = e.deltaY > 0 && top - e.deltaY <= 0;
1253 var isAtBottom = e.deltaY < 0 && bottom <= self.$results.height();
1254
1255 if (isAtTop) {
1256 self.$results.scrollTop(0);
1257
1258 e.preventDefault();
1259 e.stopPropagation();
1260 } else if (isAtBottom) {
1261 self.$results.scrollTop(
1262 self.$results.get(0).scrollHeight - self.$results.height()
1263 );
1264
1265 e.preventDefault();
1266 e.stopPropagation();
1267 }
1268 });
1269 }
1270
1271 this.$results.on('mouseup', '.select2-results__option[aria-selected]',
1272 function (evt) {
1273 var $this = $(this);
1274
1275 var data = Utils.GetData(this, 'data');
1276
1277 if ($this.attr('aria-selected') === 'true') {
1278 if (self.options.get('multiple')) {
1279 self.trigger('unselect', {
1280 originalEvent: evt,
1281 data: data
1282 });
1283 } else {
1284 self.trigger('close', {});
1285 }
1286
1287 return;
1288 }
1289
1290 self.trigger('select', {
1291 originalEvent: evt,
1292 data: data
1293 });
1294 });
1295
1296 this.$results.on('mouseenter', '.select2-results__option[aria-selected]',
1297 function (evt) {
1298 var data = Utils.GetData(this, 'data');
1299
1300 self.getHighlightedResults()
1301 .removeClass('select2-results__option--highlighted');
1302
1303 self.trigger('results:focus', {
1304 data: data,
1305 element: $(this)
1306 });
1307 });
1308 };
1309
1310 Results.prototype.getHighlightedResults = function () {
1311 var $highlighted = this.$results
1312 .find('.select2-results__option--highlighted');
1313
1314 return $highlighted;
1315 };
1316
1317 Results.prototype.destroy = function () {
1318 this.$results.remove();
1319 };
1320
1321 Results.prototype.ensureHighlightVisible = function () {
1322 var $highlighted = this.getHighlightedResults();
1323
1324 if ($highlighted.length === 0) {
1325 return;
1326 }
1327
1328 var $options = this.$results.find('[aria-selected]');
1329
1330 var currentIndex = $options.index($highlighted);
1331
1332 var currentOffset = this.$results.offset().top;
1333 var nextTop = $highlighted.offset().top;
1334 var nextOffset = this.$results.scrollTop() + (nextTop - currentOffset);
1335
1336 var offsetDelta = nextTop - currentOffset;
1337 nextOffset -= $highlighted.outerHeight(false) * 2;
1338
1339 if (currentIndex <= 2) {
1340 this.$results.scrollTop(0);
1341 } else if (offsetDelta > this.$results.outerHeight() || offsetDelta < 0) {
1342 this.$results.scrollTop(nextOffset);
1343 }
1344 };
1345
1346 Results.prototype.template = function (result, container) {
1347 var template = this.options.get('templateResult');
1348 var escapeMarkup = this.options.get('escapeMarkup');
1349
1350 var content = template(result, container);
1351
1352 if (content == null) {
1353 container.style.display = 'none';
1354 } else if (typeof content === 'string') {
1355 container.innerHTML = escapeMarkup(content);
1356 } else {
1357 $(container).append(content);
1358 }
1359 };
1360
1361 return Results;
1362});
1363
1364S2.define('select2/keys',[
1365
1366], function () {
1367 var KEYS = {
1368 BACKSPACE: 8,
1369 TAB: 9,
1370 ENTER: 13,
1371 SHIFT: 16,
1372 CTRL: 17,
1373 ALT: 18,
1374 ESC: 27,
1375 SPACE: 32,
1376 PAGE_UP: 33,
1377 PAGE_DOWN: 34,
1378 END: 35,
1379 HOME: 36,
1380 LEFT: 37,
1381 UP: 38,
1382 RIGHT: 39,
1383 DOWN: 40,
1384 DELETE: 46
1385 };
1386
1387 return KEYS;
1388});
1389
1390S2.define('select2/selection/base',[
1391 'jquery',
1392 '../utils',
1393 '../keys'
1394], function ($, Utils, KEYS) {
1395 function BaseSelection ($element, options) {
1396 this.$element = $element;
1397 this.options = options;
1398
1399 BaseSelection.__super__.constructor.call(this);
1400 }
1401
1402 Utils.Extend(BaseSelection, Utils.Observable);
1403
1404 BaseSelection.prototype.render = function () {
1405 var $selection = $(
1406 '<span class="select2-selection" role="combobox" ' +
1407 ' aria-haspopup="true" aria-expanded="false">' +
1408 '</span>'
1409 );
1410
1411 this._tabindex = 0;
1412
1413 if (Utils.GetData(this.$element[0], 'old-tabindex') != null) {
1414 this._tabindex = Utils.GetData(this.$element[0], 'old-tabindex');
1415 } else if (this.$element.attr('tabindex') != null) {
1416 this._tabindex = this.$element.attr('tabindex');
1417 }
1418
1419 $selection.attr('title', this.$element.attr('title'));
1420 $selection.attr('tabindex', this._tabindex);
1421
1422 this.$selection = $selection;
1423
1424 return $selection;
1425 };
1426
1427 BaseSelection.prototype.bind = function (container, $container) {
1428 var self = this;
1429
1430 var id = container.id + '-container';
1431 var resultsId = container.id + '-results';
1432
1433 this.container = container;
1434
1435 this.$selection.on('focus', function (evt) {
1436 self.trigger('focus', evt);
1437 });
1438
1439 this.$selection.on('blur', function (evt) {
1440 self._handleBlur(evt);
1441 });
1442
1443 this.$selection.on('keydown', function (evt) {
1444 self.trigger('keypress', evt);
1445
1446 if (evt.which === KEYS.SPACE) {
1447 evt.preventDefault();
1448 }
1449 });
1450
1451 container.on('results:focus', function (params) {
1452 self.$selection.attr('aria-activedescendant', params.data._resultId);
1453 });
1454
1455 container.on('selection:update', function (params) {
1456 self.update(params.data);
1457 });
1458
1459 container.on('open', function () {
1460 // When the dropdown is open, aria-expanded="true"
1461 self.$selection.attr('aria-expanded', 'true');
1462 self.$selection.attr('aria-owns', resultsId);
1463
1464 self._attachCloseHandler(container);
1465 });
1466
1467 container.on('close', function () {
1468 // When the dropdown is closed, aria-expanded="false"
1469 self.$selection.attr('aria-expanded', 'false');
1470 self.$selection.removeAttr('aria-activedescendant');
1471 self.$selection.removeAttr('aria-owns');
1472
1473 self.$selection.focus();
1474 window.setTimeout(function () {
1475 self.$selection.focus();
1476 }, 0);
1477
1478 self._detachCloseHandler(container);
1479 });
1480
1481 container.on('enable', function () {
1482 self.$selection.attr('tabindex', self._tabindex);
1483 });
1484
1485 container.on('disable', function () {
1486 self.$selection.attr('tabindex', '-1');
1487 });
1488 };
1489
1490 BaseSelection.prototype._handleBlur = function (evt) {
1491 var self = this;
1492
1493 // This needs to be delayed as the active element is the body when the tab
1494 // key is pressed, possibly along with others.
1495 window.setTimeout(function () {
1496 // Don't trigger `blur` if the focus is still in the selection
1497 if (
1498 (document.activeElement == self.$selection[0]) ||
1499 ($.contains(self.$selection[0], document.activeElement))
1500 ) {
1501 return;
1502 }
1503
1504 self.trigger('blur', evt);
1505 }, 1);
1506 };
1507
1508 BaseSelection.prototype._attachCloseHandler = function (container) {
1509 var self = this;
1510
1511 $(document.body).on('mousedown.select2.' + container.id, function (e) {
1512 var $target = $(e.target);
1513
1514 var $select = $target.closest('.select2');
1515
1516 var $all = $('.select2.select2-container--open');
1517
1518 $all.each(function () {
1519 var $this = $(this);
1520
1521 if (this == $select[0]) {
1522 return;
1523 }
1524
1525 var $element = Utils.GetData(this, 'element');
1526
1527 $element.select2('close');
1528 });
1529 });
1530 };
1531
1532 BaseSelection.prototype._detachCloseHandler = function (container) {
1533 $(document.body).off('mousedown.select2.' + container.id);
1534 };
1535
1536 BaseSelection.prototype.position = function ($selection, $container) {
1537 var $selectionContainer = $container.find('.selection');
1538 $selectionContainer.append($selection);
1539 };
1540
1541 BaseSelection.prototype.destroy = function () {
1542 this._detachCloseHandler(this.container);
1543 };
1544
1545 BaseSelection.prototype.update = function (data) {
1546 throw new Error('The `update` method must be defined in child classes.');
1547 };
1548
1549 return BaseSelection;
1550});
1551
1552S2.define('select2/selection/single',[
1553 'jquery',
1554 './base',
1555 '../utils',
1556 '../keys'
1557], function ($, BaseSelection, Utils, KEYS) {
1558 function SingleSelection () {
1559 SingleSelection.__super__.constructor.apply(this, arguments);
1560 }
1561
1562 Utils.Extend(SingleSelection, BaseSelection);
1563
1564 SingleSelection.prototype.render = function () {
1565 var $selection = SingleSelection.__super__.render.call(this);
1566
1567 $selection.addClass('select2-selection--single');
1568
1569 $selection.html(
1570 '<span class="select2-selection__rendered"></span>' +
1571 '<span class="select2-selection__arrow" role="presentation">' +
1572 '<b role="presentation"></b>' +
1573 '</span>'
1574 );
1575
1576 return $selection;
1577 };
1578
1579 SingleSelection.prototype.bind = function (container, $container) {
1580 var self = this;
1581
1582 SingleSelection.__super__.bind.apply(this, arguments);
1583
1584 var id = container.id + '-container';
1585
1586 this.$selection.find('.select2-selection__rendered')
1587 .attr('id', id)
1588 .attr('role', 'textbox')
1589 .attr('aria-readonly', 'true');
1590 this.$selection.attr('aria-labelledby', id);
1591
1592 this.$selection.on('mousedown', function (evt) {
1593 // Only respond to left clicks
1594 if (evt.which !== 1) {
1595 return;
1596 }
1597
1598 self.trigger('toggle', {
1599 originalEvent: evt
1600 });
1601 });
1602
1603 this.$selection.on('focus', function (evt) {
1604 // User focuses on the container
1605 });
1606
1607 this.$selection.on('blur', function (evt) {
1608 // User exits the container
1609 });
1610
1611 container.on('focus', function (evt) {
1612 if (!container.isOpen()) {
1613 self.$selection.focus();
1614 }
1615 });
1616 };
1617
1618 SingleSelection.prototype.clear = function () {
1619 var $rendered = this.$selection.find('.select2-selection__rendered');
1620 $rendered.empty();
1621 $rendered.removeAttr('title'); // clear tooltip on empty
1622 };
1623
1624 SingleSelection.prototype.display = function (data, container) {
1625 var template = this.options.get('templateSelection');
1626 var escapeMarkup = this.options.get('escapeMarkup');
1627
1628 return escapeMarkup(template(data, container));
1629 };
1630
1631 SingleSelection.prototype.selectionContainer = function () {
1632 return $('<span></span>');
1633 };
1634
1635 SingleSelection.prototype.update = function (data) {
1636 if (data.length === 0) {
1637 this.clear();
1638 return;
1639 }
1640
1641 var selection = data[0];
1642
1643 var $rendered = this.$selection.find('.select2-selection__rendered');
1644 var formatted = this.display(selection, $rendered);
1645
1646 $rendered.empty().append(formatted);
1647 $rendered.attr('title', selection.title || selection.text);
1648 };
1649
1650 return SingleSelection;
1651});
1652
1653S2.define('select2/selection/multiple',[
1654 'jquery',
1655 './base',
1656 '../utils'
1657], function ($, BaseSelection, Utils) {
1658 function MultipleSelection ($element, options) {
1659 MultipleSelection.__super__.constructor.apply(this, arguments);
1660 }
1661
1662 Utils.Extend(MultipleSelection, BaseSelection);
1663
1664 MultipleSelection.prototype.render = function () {
1665 var $selection = MultipleSelection.__super__.render.call(this);
1666
1667 $selection.addClass('select2-selection--multiple');
1668
1669 $selection.html(
1670 '<ul class="select2-selection__rendered"></ul>'
1671 );
1672
1673 return $selection;
1674 };
1675
1676 MultipleSelection.prototype.bind = function (container, $container) {
1677 var self = this;
1678
1679 MultipleSelection.__super__.bind.apply(this, arguments);
1680
1681 this.$selection.on('click', function (evt) {
1682 self.trigger('toggle', {
1683 originalEvent: evt
1684 });
1685 });
1686
1687 this.$selection.on(
1688 'click',
1689 '.select2-selection__choice__remove',
1690 function (evt) {
1691 // Ignore the event if it is disabled
1692 if (self.options.get('disabled')) {
1693 return;
1694 }
1695
1696 var $remove = $(this);
1697 var $selection = $remove.parent();
1698
1699 var data = Utils.GetData($selection[0], 'data');
1700
1701 self.trigger('unselect', {
1702 originalEvent: evt,
1703 data: data
1704 });
1705 }
1706 );
1707 };
1708
1709 MultipleSelection.prototype.clear = function () {
1710 var $rendered = this.$selection.find('.select2-selection__rendered');
1711 $rendered.empty();
1712 $rendered.removeAttr('title');
1713 };
1714
1715 MultipleSelection.prototype.display = function (data, container) {
1716 var template = this.options.get('templateSelection');
1717 var escapeMarkup = this.options.get('escapeMarkup');
1718
1719 return escapeMarkup(template(data, container));
1720 };
1721
1722 MultipleSelection.prototype.selectionContainer = function () {
1723 var $container = $(
1724 '<li class="select2-selection__choice">' +
1725 '<span class="select2-selection__choice__remove" role="presentation">' +
1726 '&times;' +
1727 '</span>' +
1728 '</li>'
1729 );
1730
1731 return $container;
1732 };
1733
1734 MultipleSelection.prototype.update = function (data) {
1735 this.clear();
1736
1737 if (data.length === 0) {
1738 return;
1739 }
1740
1741 var $selections = [];
1742
1743 for (var d = 0; d < data.length; d++) {
1744 var selection = data[d];
1745
1746 var $selection = this.selectionContainer();
1747 var formatted = this.display(selection, $selection);
1748
1749 $selection.append(formatted);
1750 $selection.attr('title', selection.title || selection.text);
1751
1752 Utils.StoreData($selection[0], 'data', selection);
1753
1754 $selections.push($selection);
1755 }
1756
1757 var $rendered = this.$selection.find('.select2-selection__rendered');
1758
1759 Utils.appendMany($rendered, $selections);
1760 };
1761
1762 return MultipleSelection;
1763});
1764
1765S2.define('select2/selection/placeholder',[
1766 '../utils'
1767], function (Utils) {
1768 function Placeholder (decorated, $element, options) {
1769 this.placeholder = this.normalizePlaceholder(options.get('placeholder'));
1770
1771 decorated.call(this, $element, options);
1772 }
1773
1774 Placeholder.prototype.normalizePlaceholder = function (_, placeholder) {
1775 if (typeof placeholder === 'string') {
1776 placeholder = {
1777 id: '',
1778 text: placeholder
1779 };
1780 }
1781
1782 return placeholder;
1783 };
1784
1785 Placeholder.prototype.createPlaceholder = function (decorated, placeholder) {
1786 var $placeholder = this.selectionContainer();
1787
1788 $placeholder.html(this.display(placeholder));
1789 $placeholder.addClass('select2-selection__placeholder')
1790 .removeClass('select2-selection__choice');
1791
1792 return $placeholder;
1793 };
1794
1795 Placeholder.prototype.update = function (decorated, data) {
1796 var singlePlaceholder = (
1797 data.length == 1 && data[0].id != this.placeholder.id
1798 );
1799 var multipleSelections = data.length > 1;
1800
1801 if (multipleSelections || singlePlaceholder) {
1802 return decorated.call(this, data);
1803 }
1804
1805 this.clear();
1806
1807 var $placeholder = this.createPlaceholder(this.placeholder);
1808
1809 this.$selection.find('.select2-selection__rendered').append($placeholder);
1810 };
1811
1812 return Placeholder;
1813});
1814
1815S2.define('select2/selection/allowClear',[
1816 'jquery',
1817 '../keys',
1818 '../utils'
1819], function ($, KEYS, Utils) {
1820 function AllowClear () { }
1821
1822 AllowClear.prototype.bind = function (decorated, container, $container) {
1823 var self = this;
1824
1825 decorated.call(this, container, $container);
1826
1827 if (this.placeholder == null) {
1828 if (this.options.get('debug') && window.console && console.error) {
1829 console.error(
1830 'Select2: The `allowClear` option should be used in combination ' +
1831 'with the `placeholder` option.'
1832 );
1833 }
1834 }
1835
1836 this.$selection.on('mousedown', '.select2-selection__clear',
1837 function (evt) {
1838 self._handleClear(evt);
1839 });
1840
1841 container.on('keypress', function (evt) {
1842 self._handleKeyboardClear(evt, container);
1843 });
1844 };
1845
1846 AllowClear.prototype._handleClear = function (_, evt) {
1847 // Ignore the event if it is disabled
1848 if (this.options.get('disabled')) {
1849 return;
1850 }
1851
1852 var $clear = this.$selection.find('.select2-selection__clear');
1853
1854 // Ignore the event if nothing has been selected
1855 if ($clear.length === 0) {
1856 return;
1857 }
1858
1859 evt.stopPropagation();
1860
1861 var data = Utils.GetData($clear[0], 'data');
1862
1863 var previousVal = this.$element.val();
1864 this.$element.val(this.placeholder.id);
1865
1866 var unselectData = {
1867 data: data
1868 };
1869 this.trigger('clear', unselectData);
1870 if (unselectData.prevented) {
1871 this.$element.val(previousVal);
1872 return;
1873 }
1874
1875 for (var d = 0; d < data.length; d++) {
1876 unselectData = {
1877 data: data[d]
1878 };
1879
1880 // Trigger the `unselect` event, so people can prevent it from being
1881 // cleared.
1882 this.trigger('unselect', unselectData);
1883
1884 // If the event was prevented, don't clear it out.
1885 if (unselectData.prevented) {
1886 this.$element.val(previousVal);
1887 return;
1888 }
1889 }
1890
1891 this.$element.trigger('change');
1892
1893 this.trigger('toggle', {});
1894 };
1895
1896 AllowClear.prototype._handleKeyboardClear = function (_, evt, container) {
1897 if (container.isOpen()) {
1898 return;
1899 }
1900
1901 if (evt.which == KEYS.DELETE || evt.which == KEYS.BACKSPACE) {
1902 this._handleClear(evt);
1903 }
1904 };
1905
1906 AllowClear.prototype.update = function (decorated, data) {
1907 decorated.call(this, data);
1908
1909 if (this.$selection.find('.select2-selection__placeholder').length > 0 ||
1910 data.length === 0) {
1911 return;
1912 }
1913
1914 var $remove = $(
1915 '<span class="select2-selection__clear">' +
1916 '&times;' +
1917 '</span>'
1918 );
1919 Utils.StoreData($remove[0], 'data', data);
1920
1921 this.$selection.find('.select2-selection__rendered').prepend($remove);
1922 };
1923
1924 return AllowClear;
1925});
1926
1927S2.define('select2/selection/search',[
1928 'jquery',
1929 '../utils',
1930 '../keys'
1931], function ($, Utils, KEYS) {
1932 function Search (decorated, $element, options) {
1933 decorated.call(this, $element, options);
1934 }
1935
1936 Search.prototype.render = function (decorated) {
1937 var $search = $(
1938 '<li class="select2-search select2-search--inline">' +
1939 '<input class="select2-search__field" type="search" tabindex="-1"' +
1940 ' autocomplete="off" autocorrect="off" autocapitalize="none"' +
1941 ' spellcheck="false" role="textbox" aria-autocomplete="list" />' +
1942 '</li>'
1943 );
1944
1945 this.$searchContainer = $search;
1946 this.$search = $search.find('input');
1947
1948 var $rendered = decorated.call(this);
1949
1950 this._transferTabIndex();
1951
1952 return $rendered;
1953 };
1954
1955 Search.prototype.bind = function (decorated, container, $container) {
1956 var self = this;
1957
1958 decorated.call(this, container, $container);
1959
1960 container.on('open', function () {
1961 self.$search.trigger('focus');
1962 });
1963
1964 container.on('close', function () {
1965 self.$search.val('');
1966 self.$search.removeAttr('aria-activedescendant');
1967 self.$search.trigger('focus');
1968 });
1969
1970 container.on('enable', function () {
1971 self.$search.prop('disabled', false);
1972
1973 self._transferTabIndex();
1974 });
1975
1976 container.on('disable', function () {
1977 self.$search.prop('disabled', true);
1978 });
1979
1980 container.on('focus', function (evt) {
1981 self.$search.trigger('focus');
1982 });
1983
1984 container.on('results:focus', function (params) {
1985 self.$search.attr('aria-activedescendant', params.id);
1986 });
1987
1988 this.$selection.on('focusin', '.select2-search--inline', function (evt) {
1989 self.trigger('focus', evt);
1990 });
1991
1992 this.$selection.on('focusout', '.select2-search--inline', function (evt) {
1993 self._handleBlur(evt);
1994 });
1995
1996 this.$selection.on('keydown', '.select2-search--inline', function (evt) {
1997 evt.stopPropagation();
1998
1999 self.trigger('keypress', evt);
2000
2001 self._keyUpPrevented = evt.isDefaultPrevented();
2002
2003 var key = evt.which;
2004
2005 if (key === KEYS.BACKSPACE && self.$search.val() === '') {
2006 var $previousChoice = self.$searchContainer
2007 .prev('.select2-selection__choice');
2008
2009 if ($previousChoice.length > 0) {
2010 var item = Utils.GetData($previousChoice[0], 'data');
2011
2012 self.searchRemoveChoice(item);
2013
2014 evt.preventDefault();
2015 }
2016 }
2017 });
2018
2019 // Try to detect the IE version should the `documentMode` property that
2020 // is stored on the document. This is only implemented in IE and is
2021 // slightly cleaner than doing a user agent check.
2022 // This property is not available in Edge, but Edge also doesn't have
2023 // this bug.
2024 var msie = document.documentMode;
2025 var disableInputEvents = msie && msie <= 11;
2026
2027 // Workaround for browsers which do not support the `input` event
2028 // This will prevent double-triggering of events for browsers which support
2029 // both the `keyup` and `input` events.
2030 this.$selection.on(
2031 'input.searchcheck',
2032 '.select2-search--inline',
2033 function (evt) {
2034 // IE will trigger the `input` event when a placeholder is used on a
2035 // search box. To get around this issue, we are forced to ignore all
2036 // `input` events in IE and keep using `keyup`.
2037 if (disableInputEvents) {
2038 self.$selection.off('input.search input.searchcheck');
2039 return;
2040 }
2041
2042 // Unbind the duplicated `keyup` event
2043 self.$selection.off('keyup.search');
2044 }
2045 );
2046
2047 this.$selection.on(
2048 'keyup.search input.search',
2049 '.select2-search--inline',
2050 function (evt) {
2051 // IE will trigger the `input` event when a placeholder is used on a
2052 // search box. To get around this issue, we are forced to ignore all
2053 // `input` events in IE and keep using `keyup`.
2054 if (disableInputEvents && evt.type === 'input') {
2055 self.$selection.off('input.search input.searchcheck');
2056 return;
2057 }
2058
2059 var key = evt.which;
2060
2061 // We can freely ignore events from modifier keys
2062 if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) {
2063 return;
2064 }
2065
2066 // Tabbing will be handled during the `keydown` phase
2067 if (key == KEYS.TAB) {
2068 return;
2069 }
2070
2071 self.handleSearch(evt);
2072 }
2073 );
2074 };
2075
2076 /**
2077 * This method will transfer the tabindex attribute from the rendered
2078 * selection to the search box. This allows for the search box to be used as
2079 * the primary focus instead of the selection container.
2080 *
2081 * @private
2082 */
2083 Search.prototype._transferTabIndex = function (decorated) {
2084 this.$search.attr('tabindex', this.$selection.attr('tabindex'));
2085 this.$selection.attr('tabindex', '-1');
2086 };
2087
2088 Search.prototype.createPlaceholder = function (decorated, placeholder) {
2089 this.$search.attr('placeholder', placeholder.text);
2090 };
2091
2092 Search.prototype.update = function (decorated, data) {
2093 var searchHadFocus = this.$search[0] == document.activeElement;
2094
2095 this.$search.attr('placeholder', '');
2096
2097 decorated.call(this, data);
2098
2099 this.$selection.find('.select2-selection__rendered')
2100 .append(this.$searchContainer);
2101
2102 this.resizeSearch();
2103 if (searchHadFocus) {
2104 var isTagInput = this.$element.find('[data-select2-tag]').length;
2105 if (isTagInput) {
2106 // fix IE11 bug where tag input lost focus
2107 this.$element.focus();
2108 } else {
2109 this.$search.focus();
2110 }
2111 }
2112 };
2113
2114 Search.prototype.handleSearch = function () {
2115 this.resizeSearch();
2116
2117 if (!this._keyUpPrevented) {
2118 var input = this.$search.val();
2119
2120 this.trigger('query', {
2121 term: input
2122 });
2123 }
2124
2125 this._keyUpPrevented = false;
2126 };
2127
2128 Search.prototype.searchRemoveChoice = function (decorated, item) {
2129 this.trigger('unselect', {
2130 data: item
2131 });
2132
2133 this.$search.val(item.text);
2134 this.handleSearch();
2135 };
2136
2137 Search.prototype.resizeSearch = function () {
2138 this.$search.css('width', '25px');
2139
2140 var width = '';
2141
2142 if (this.$search.attr('placeholder') !== '') {
2143 width = this.$selection.find('.select2-selection__rendered').innerWidth();
2144 } else {
2145 var minimumWidth = this.$search.val().length + 1;
2146
2147 width = (minimumWidth * 0.75) + 'em';
2148 }
2149
2150 this.$search.css('width', width);
2151 };
2152
2153 return Search;
2154});
2155
2156S2.define('select2/selection/eventRelay',[
2157 'jquery'
2158], function ($) {
2159 function EventRelay () { }
2160
2161 EventRelay.prototype.bind = function (decorated, container, $container) {
2162 var self = this;
2163 var relayEvents = [
2164 'open', 'opening',
2165 'close', 'closing',
2166 'select', 'selecting',
2167 'unselect', 'unselecting',
2168 'clear', 'clearing'
2169 ];
2170
2171 var preventableEvents = [
2172 'opening', 'closing', 'selecting', 'unselecting', 'clearing'
2173 ];
2174
2175 decorated.call(this, container, $container);
2176
2177 container.on('*', function (name, params) {
2178 // Ignore events that should not be relayed
2179 if ($.inArray(name, relayEvents) === -1) {
2180 return;
2181 }
2182
2183 // The parameters should always be an object
2184 params = params || {};
2185
2186 // Generate the jQuery event for the Select2 event
2187 var evt = $.Event('select2:' + name, {
2188 params: params
2189 });
2190
2191 self.$element.trigger(evt);
2192
2193 // Only handle preventable events if it was one
2194 if ($.inArray(name, preventableEvents) === -1) {
2195 return;
2196 }
2197
2198 params.prevented = evt.isDefaultPrevented();
2199 });
2200 };
2201
2202 return EventRelay;
2203});
2204
2205S2.define('select2/translation',[
2206 'jquery',
2207 'require'
2208], function ($, require) {
2209 function Translation (dict) {
2210 this.dict = dict || {};
2211 }
2212
2213 Translation.prototype.all = function () {
2214 return this.dict;
2215 };
2216
2217 Translation.prototype.get = function (key) {
2218 return this.dict[key];
2219 };
2220
2221 Translation.prototype.extend = function (translation) {
2222 this.dict = $.extend({}, translation.all(), this.dict);
2223 };
2224
2225 // Static functions
2226
2227 Translation._cache = {};
2228
2229 Translation.loadPath = function (path) {
2230 if (!(path in Translation._cache)) {
2231 var translations = require(path);
2232
2233 Translation._cache[path] = translations;
2234 }
2235
2236 return new Translation(Translation._cache[path]);
2237 };
2238
2239 return Translation;
2240});
2241
2242S2.define('select2/diacritics',[
2243
2244], function () {
2245 var diacritics = {
2246 '\u24B6': 'A',
2247 '\uFF21': 'A',
2248 '\u00C0': 'A',
2249 '\u00C1': 'A',
2250 '\u00C2': 'A',
2251 '\u1EA6': 'A',
2252 '\u1EA4': 'A',
2253 '\u1EAA': 'A',
2254 '\u1EA8': 'A',
2255 '\u00C3': 'A',
2256 '\u0100': 'A',
2257 '\u0102': 'A',
2258 '\u1EB0': 'A',
2259 '\u1EAE': 'A',
2260 '\u1EB4': 'A',
2261 '\u1EB2': 'A',
2262 '\u0226': 'A',
2263 '\u01E0': 'A',
2264 '\u00C4': 'A',
2265 '\u01DE': 'A',
2266 '\u1EA2': 'A',
2267 '\u00C5': 'A',
2268 '\u01FA': 'A',
2269 '\u01CD': 'A',
2270 '\u0200': 'A',
2271 '\u0202': 'A',
2272 '\u1EA0': 'A',
2273 '\u1EAC': 'A',
2274 '\u1EB6': 'A',
2275 '\u1E00': 'A',
2276 '\u0104': 'A',
2277 '\u023A': 'A',
2278 '\u2C6F': 'A',
2279 '\uA732': 'AA',
2280 '\u00C6': 'AE',
2281 '\u01FC': 'AE',
2282 '\u01E2': 'AE',
2283 '\uA734': 'AO',
2284 '\uA736': 'AU',
2285 '\uA738': 'AV',
2286 '\uA73A': 'AV',
2287 '\uA73C': 'AY',
2288 '\u24B7': 'B',
2289 '\uFF22': 'B',
2290 '\u1E02': 'B',
2291 '\u1E04': 'B',
2292 '\u1E06': 'B',
2293 '\u0243': 'B',
2294 '\u0182': 'B',
2295 '\u0181': 'B',
2296 '\u24B8': 'C',
2297 '\uFF23': 'C',
2298 '\u0106': 'C',
2299 '\u0108': 'C',
2300 '\u010A': 'C',
2301 '\u010C': 'C',
2302 '\u00C7': 'C',
2303 '\u1E08': 'C',
2304 '\u0187': 'C',
2305 '\u023B': 'C',
2306 '\uA73E': 'C',
2307 '\u24B9': 'D',
2308 '\uFF24': 'D',
2309 '\u1E0A': 'D',
2310 '\u010E': 'D',
2311 '\u1E0C': 'D',
2312 '\u1E10': 'D',
2313 '\u1E12': 'D',
2314 '\u1E0E': 'D',
2315 '\u0110': 'D',
2316 '\u018B': 'D',
2317 '\u018A': 'D',
2318 '\u0189': 'D',
2319 '\uA779': 'D',
2320 '\u01F1': 'DZ',
2321 '\u01C4': 'DZ',
2322 '\u01F2': 'Dz',
2323 '\u01C5': 'Dz',
2324 '\u24BA': 'E',
2325 '\uFF25': 'E',
2326 '\u00C8': 'E',
2327 '\u00C9': 'E',
2328 '\u00CA': 'E',
2329 '\u1EC0': 'E',
2330 '\u1EBE': 'E',
2331 '\u1EC4': 'E',
2332 '\u1EC2': 'E',
2333 '\u1EBC': 'E',
2334 '\u0112': 'E',
2335 '\u1E14': 'E',
2336 '\u1E16': 'E',
2337 '\u0114': 'E',
2338 '\u0116': 'E',
2339 '\u00CB': 'E',
2340 '\u1EBA': 'E',
2341 '\u011A': 'E',
2342 '\u0204': 'E',
2343 '\u0206': 'E',
2344 '\u1EB8': 'E',
2345 '\u1EC6': 'E',
2346 '\u0228': 'E',
2347 '\u1E1C': 'E',
2348 '\u0118': 'E',
2349 '\u1E18': 'E',
2350 '\u1E1A': 'E',
2351 '\u0190': 'E',
2352 '\u018E': 'E',
2353 '\u24BB': 'F',
2354 '\uFF26': 'F',
2355 '\u1E1E': 'F',
2356 '\u0191': 'F',
2357 '\uA77B': 'F',
2358 '\u24BC': 'G',
2359 '\uFF27': 'G',
2360 '\u01F4': 'G',
2361 '\u011C': 'G',
2362 '\u1E20': 'G',
2363 '\u011E': 'G',
2364 '\u0120': 'G',
2365 '\u01E6': 'G',
2366 '\u0122': 'G',
2367 '\u01E4': 'G',
2368 '\u0193': 'G',
2369 '\uA7A0': 'G',
2370 '\uA77D': 'G',
2371 '\uA77E': 'G',
2372 '\u24BD': 'H',
2373 '\uFF28': 'H',
2374 '\u0124': 'H',
2375 '\u1E22': 'H',
2376 '\u1E26': 'H',
2377 '\u021E': 'H',
2378 '\u1E24': 'H',
2379 '\u1E28': 'H',
2380 '\u1E2A': 'H',
2381 '\u0126': 'H',
2382 '\u2C67': 'H',
2383 '\u2C75': 'H',
2384 '\uA78D': 'H',
2385 '\u24BE': 'I',
2386 '\uFF29': 'I',
2387 '\u00CC': 'I',
2388 '\u00CD': 'I',
2389 '\u00CE': 'I',
2390 '\u0128': 'I',
2391 '\u012A': 'I',
2392 '\u012C': 'I',
2393 '\u0130': 'I',
2394 '\u00CF': 'I',
2395 '\u1E2E': 'I',
2396 '\u1EC8': 'I',
2397 '\u01CF': 'I',
2398 '\u0208': 'I',
2399 '\u020A': 'I',
2400 '\u1ECA': 'I',
2401 '\u012E': 'I',
2402 '\u1E2C': 'I',
2403 '\u0197': 'I',
2404 '\u24BF': 'J',
2405 '\uFF2A': 'J',
2406 '\u0134': 'J',
2407 '\u0248': 'J',
2408 '\u24C0': 'K',
2409 '\uFF2B': 'K',
2410 '\u1E30': 'K',
2411 '\u01E8': 'K',
2412 '\u1E32': 'K',
2413 '\u0136': 'K',
2414 '\u1E34': 'K',
2415 '\u0198': 'K',
2416 '\u2C69': 'K',
2417 '\uA740': 'K',
2418 '\uA742': 'K',
2419 '\uA744': 'K',
2420 '\uA7A2': 'K',
2421 '\u24C1': 'L',
2422 '\uFF2C': 'L',
2423 '\u013F': 'L',
2424 '\u0139': 'L',
2425 '\u013D': 'L',
2426 '\u1E36': 'L',
2427 '\u1E38': 'L',
2428 '\u013B': 'L',
2429 '\u1E3C': 'L',
2430 '\u1E3A': 'L',
2431 '\u0141': 'L',
2432 '\u023D': 'L',
2433 '\u2C62': 'L',
2434 '\u2C60': 'L',
2435 '\uA748': 'L',
2436 '\uA746': 'L',
2437 '\uA780': 'L',
2438 '\u01C7': 'LJ',
2439 '\u01C8': 'Lj',
2440 '\u24C2': 'M',
2441 '\uFF2D': 'M',
2442 '\u1E3E': 'M',
2443 '\u1E40': 'M',
2444 '\u1E42': 'M',
2445 '\u2C6E': 'M',
2446 '\u019C': 'M',
2447 '\u24C3': 'N',
2448 '\uFF2E': 'N',
2449 '\u01F8': 'N',
2450 '\u0143': 'N',
2451 '\u00D1': 'N',
2452 '\u1E44': 'N',
2453 '\u0147': 'N',
2454 '\u1E46': 'N',
2455 '\u0145': 'N',
2456 '\u1E4A': 'N',
2457 '\u1E48': 'N',
2458 '\u0220': 'N',
2459 '\u019D': 'N',
2460 '\uA790': 'N',
2461 '\uA7A4': 'N',
2462 '\u01CA': 'NJ',
2463 '\u01CB': 'Nj',
2464 '\u24C4': 'O',
2465 '\uFF2F': 'O',
2466 '\u00D2': 'O',
2467 '\u00D3': 'O',
2468 '\u00D4': 'O',
2469 '\u1ED2': 'O',
2470 '\u1ED0': 'O',
2471 '\u1ED6': 'O',
2472 '\u1ED4': 'O',
2473 '\u00D5': 'O',
2474 '\u1E4C': 'O',
2475 '\u022C': 'O',
2476 '\u1E4E': 'O',
2477 '\u014C': 'O',
2478 '\u1E50': 'O',
2479 '\u1E52': 'O',
2480 '\u014E': 'O',
2481 '\u022E': 'O',
2482 '\u0230': 'O',
2483 '\u00D6': 'O',
2484 '\u022A': 'O',
2485 '\u1ECE': 'O',
2486 '\u0150': 'O',
2487 '\u01D1': 'O',
2488 '\u020C': 'O',
2489 '\u020E': 'O',
2490 '\u01A0': 'O',
2491 '\u1EDC': 'O',
2492 '\u1EDA': 'O',
2493 '\u1EE0': 'O',
2494 '\u1EDE': 'O',
2495 '\u1EE2': 'O',
2496 '\u1ECC': 'O',
2497 '\u1ED8': 'O',
2498 '\u01EA': 'O',
2499 '\u01EC': 'O',
2500 '\u00D8': 'O',
2501 '\u01FE': 'O',
2502 '\u0186': 'O',
2503 '\u019F': 'O',
2504 '\uA74A': 'O',
2505 '\uA74C': 'O',
2506 '\u01A2': 'OI',
2507 '\uA74E': 'OO',
2508 '\u0222': 'OU',
2509 '\u24C5': 'P',
2510 '\uFF30': 'P',
2511 '\u1E54': 'P',
2512 '\u1E56': 'P',
2513 '\u01A4': 'P',
2514 '\u2C63': 'P',
2515 '\uA750': 'P',
2516 '\uA752': 'P',
2517 '\uA754': 'P',
2518 '\u24C6': 'Q',
2519 '\uFF31': 'Q',
2520 '\uA756': 'Q',
2521 '\uA758': 'Q',
2522 '\u024A': 'Q',
2523 '\u24C7': 'R',
2524 '\uFF32': 'R',
2525 '\u0154': 'R',
2526 '\u1E58': 'R',
2527 '\u0158': 'R',
2528 '\u0210': 'R',
2529 '\u0212': 'R',
2530 '\u1E5A': 'R',
2531 '\u1E5C': 'R',
2532 '\u0156': 'R',
2533 '\u1E5E': 'R',
2534 '\u024C': 'R',
2535 '\u2C64': 'R',
2536 '\uA75A': 'R',
2537 '\uA7A6': 'R',
2538 '\uA782': 'R',
2539 '\u24C8': 'S',
2540 '\uFF33': 'S',
2541 '\u1E9E': 'S',
2542 '\u015A': 'S',
2543 '\u1E64': 'S',
2544 '\u015C': 'S',
2545 '\u1E60': 'S',
2546 '\u0160': 'S',
2547 '\u1E66': 'S',
2548 '\u1E62': 'S',
2549 '\u1E68': 'S',
2550 '\u0218': 'S',
2551 '\u015E': 'S',
2552 '\u2C7E': 'S',
2553 '\uA7A8': 'S',
2554 '\uA784': 'S',
2555 '\u24C9': 'T',
2556 '\uFF34': 'T',
2557 '\u1E6A': 'T',
2558 '\u0164': 'T',
2559 '\u1E6C': 'T',
2560 '\u021A': 'T',
2561 '\u0162': 'T',
2562 '\u1E70': 'T',
2563 '\u1E6E': 'T',
2564 '\u0166': 'T',
2565 '\u01AC': 'T',
2566 '\u01AE': 'T',
2567 '\u023E': 'T',
2568 '\uA786': 'T',
2569 '\uA728': 'TZ',
2570 '\u24CA': 'U',
2571 '\uFF35': 'U',
2572 '\u00D9': 'U',
2573 '\u00DA': 'U',
2574 '\u00DB': 'U',
2575 '\u0168': 'U',
2576 '\u1E78': 'U',
2577 '\u016A': 'U',
2578 '\u1E7A': 'U',
2579 '\u016C': 'U',
2580 '\u00DC': 'U',
2581 '\u01DB': 'U',
2582 '\u01D7': 'U',
2583 '\u01D5': 'U',
2584 '\u01D9': 'U',
2585 '\u1EE6': 'U',
2586 '\u016E': 'U',
2587 '\u0170': 'U',
2588 '\u01D3': 'U',
2589 '\u0214': 'U',
2590 '\u0216': 'U',
2591 '\u01AF': 'U',
2592 '\u1EEA': 'U',
2593 '\u1EE8': 'U',
2594 '\u1EEE': 'U',
2595 '\u1EEC': 'U',
2596 '\u1EF0': 'U',
2597 '\u1EE4': 'U',
2598 '\u1E72': 'U',
2599 '\u0172': 'U',
2600 '\u1E76': 'U',
2601 '\u1E74': 'U',
2602 '\u0244': 'U',
2603 '\u24CB': 'V',
2604 '\uFF36': 'V',
2605 '\u1E7C': 'V',
2606 '\u1E7E': 'V',
2607 '\u01B2': 'V',
2608 '\uA75E': 'V',
2609 '\u0245': 'V',
2610 '\uA760': 'VY',
2611 '\u24CC': 'W',
2612 '\uFF37': 'W',
2613 '\u1E80': 'W',
2614 '\u1E82': 'W',
2615 '\u0174': 'W',
2616 '\u1E86': 'W',
2617 '\u1E84': 'W',
2618 '\u1E88': 'W',
2619 '\u2C72': 'W',
2620 '\u24CD': 'X',
2621 '\uFF38': 'X',
2622 '\u1E8A': 'X',
2623 '\u1E8C': 'X',
2624 '\u24CE': 'Y',
2625 '\uFF39': 'Y',
2626 '\u1EF2': 'Y',
2627 '\u00DD': 'Y',
2628 '\u0176': 'Y',
2629 '\u1EF8': 'Y',
2630 '\u0232': 'Y',
2631 '\u1E8E': 'Y',
2632 '\u0178': 'Y',
2633 '\u1EF6': 'Y',
2634 '\u1EF4': 'Y',
2635 '\u01B3': 'Y',
2636 '\u024E': 'Y',
2637 '\u1EFE': 'Y',
2638 '\u24CF': 'Z',
2639 '\uFF3A': 'Z',
2640 '\u0179': 'Z',
2641 '\u1E90': 'Z',
2642 '\u017B': 'Z',
2643 '\u017D': 'Z',
2644 '\u1E92': 'Z',
2645 '\u1E94': 'Z',
2646 '\u01B5': 'Z',
2647 '\u0224': 'Z',
2648 '\u2C7F': 'Z',
2649 '\u2C6B': 'Z',
2650 '\uA762': 'Z',
2651 '\u24D0': 'a',
2652 '\uFF41': 'a',
2653 '\u1E9A': 'a',
2654 '\u00E0': 'a',
2655 '\u00E1': 'a',
2656 '\u00E2': 'a',
2657 '\u1EA7': 'a',
2658 '\u1EA5': 'a',
2659 '\u1EAB': 'a',
2660 '\u1EA9': 'a',
2661 '\u00E3': 'a',
2662 '\u0101': 'a',
2663 '\u0103': 'a',
2664 '\u1EB1': 'a',
2665 '\u1EAF': 'a',
2666 '\u1EB5': 'a',
2667 '\u1EB3': 'a',
2668 '\u0227': 'a',
2669 '\u01E1': 'a',
2670 '\u00E4': 'a',
2671 '\u01DF': 'a',
2672 '\u1EA3': 'a',
2673 '\u00E5': 'a',
2674 '\u01FB': 'a',
2675 '\u01CE': 'a',
2676 '\u0201': 'a',
2677 '\u0203': 'a',
2678 '\u1EA1': 'a',
2679 '\u1EAD': 'a',
2680 '\u1EB7': 'a',
2681 '\u1E01': 'a',
2682 '\u0105': 'a',
2683 '\u2C65': 'a',
2684 '\u0250': 'a',
2685 '\uA733': 'aa',
2686 '\u00E6': 'ae',
2687 '\u01FD': 'ae',
2688 '\u01E3': 'ae',
2689 '\uA735': 'ao',
2690 '\uA737': 'au',
2691 '\uA739': 'av',
2692 '\uA73B': 'av',
2693 '\uA73D': 'ay',
2694 '\u24D1': 'b',
2695 '\uFF42': 'b',
2696 '\u1E03': 'b',
2697 '\u1E05': 'b',
2698 '\u1E07': 'b',
2699 '\u0180': 'b',
2700 '\u0183': 'b',
2701 '\u0253': 'b',
2702 '\u24D2': 'c',
2703 '\uFF43': 'c',
2704 '\u0107': 'c',
2705 '\u0109': 'c',
2706 '\u010B': 'c',
2707 '\u010D': 'c',
2708 '\u00E7': 'c',
2709 '\u1E09': 'c',
2710 '\u0188': 'c',
2711 '\u023C': 'c',
2712 '\uA73F': 'c',
2713 '\u2184': 'c',
2714 '\u24D3': 'd',
2715 '\uFF44': 'd',
2716 '\u1E0B': 'd',
2717 '\u010F': 'd',
2718 '\u1E0D': 'd',
2719 '\u1E11': 'd',
2720 '\u1E13': 'd',
2721 '\u1E0F': 'd',
2722 '\u0111': 'd',
2723 '\u018C': 'd',
2724 '\u0256': 'd',
2725 '\u0257': 'd',
2726 '\uA77A': 'd',
2727 '\u01F3': 'dz',
2728 '\u01C6': 'dz',
2729 '\u24D4': 'e',
2730 '\uFF45': 'e',
2731 '\u00E8': 'e',
2732 '\u00E9': 'e',
2733 '\u00EA': 'e',
2734 '\u1EC1': 'e',
2735 '\u1EBF': 'e',
2736 '\u1EC5': 'e',
2737 '\u1EC3': 'e',
2738 '\u1EBD': 'e',
2739 '\u0113': 'e',
2740 '\u1E15': 'e',
2741 '\u1E17': 'e',
2742 '\u0115': 'e',
2743 '\u0117': 'e',
2744 '\u00EB': 'e',
2745 '\u1EBB': 'e',
2746 '\u011B': 'e',
2747 '\u0205': 'e',
2748 '\u0207': 'e',
2749 '\u1EB9': 'e',
2750 '\u1EC7': 'e',
2751 '\u0229': 'e',
2752 '\u1E1D': 'e',
2753 '\u0119': 'e',
2754 '\u1E19': 'e',
2755 '\u1E1B': 'e',
2756 '\u0247': 'e',
2757 '\u025B': 'e',
2758 '\u01DD': 'e',
2759 '\u24D5': 'f',
2760 '\uFF46': 'f',
2761 '\u1E1F': 'f',
2762 '\u0192': 'f',
2763 '\uA77C': 'f',
2764 '\u24D6': 'g',
2765 '\uFF47': 'g',
2766 '\u01F5': 'g',
2767 '\u011D': 'g',
2768 '\u1E21': 'g',
2769 '\u011F': 'g',
2770 '\u0121': 'g',
2771 '\u01E7': 'g',
2772 '\u0123': 'g',
2773 '\u01E5': 'g',
2774 '\u0260': 'g',
2775 '\uA7A1': 'g',
2776 '\u1D79': 'g',
2777 '\uA77F': 'g',
2778 '\u24D7': 'h',
2779 '\uFF48': 'h',
2780 '\u0125': 'h',
2781 '\u1E23': 'h',
2782 '\u1E27': 'h',
2783 '\u021F': 'h',
2784 '\u1E25': 'h',
2785 '\u1E29': 'h',
2786 '\u1E2B': 'h',
2787 '\u1E96': 'h',
2788 '\u0127': 'h',
2789 '\u2C68': 'h',
2790 '\u2C76': 'h',
2791 '\u0265': 'h',
2792 '\u0195': 'hv',
2793 '\u24D8': 'i',
2794 '\uFF49': 'i',
2795 '\u00EC': 'i',
2796 '\u00ED': 'i',
2797 '\u00EE': 'i',
2798 '\u0129': 'i',
2799 '\u012B': 'i',
2800 '\u012D': 'i',
2801 '\u00EF': 'i',
2802 '\u1E2F': 'i',
2803 '\u1EC9': 'i',
2804 '\u01D0': 'i',
2805 '\u0209': 'i',
2806 '\u020B': 'i',
2807 '\u1ECB': 'i',
2808 '\u012F': 'i',
2809 '\u1E2D': 'i',
2810 '\u0268': 'i',
2811 '\u0131': 'i',
2812 '\u24D9': 'j',
2813 '\uFF4A': 'j',
2814 '\u0135': 'j',
2815 '\u01F0': 'j',
2816 '\u0249': 'j',
2817 '\u24DA': 'k',
2818 '\uFF4B': 'k',
2819 '\u1E31': 'k',
2820 '\u01E9': 'k',
2821 '\u1E33': 'k',
2822 '\u0137': 'k',
2823 '\u1E35': 'k',
2824 '\u0199': 'k',
2825 '\u2C6A': 'k',
2826 '\uA741': 'k',
2827 '\uA743': 'k',
2828 '\uA745': 'k',
2829 '\uA7A3': 'k',
2830 '\u24DB': 'l',
2831 '\uFF4C': 'l',
2832 '\u0140': 'l',
2833 '\u013A': 'l',
2834 '\u013E': 'l',
2835 '\u1E37': 'l',
2836 '\u1E39': 'l',
2837 '\u013C': 'l',
2838 '\u1E3D': 'l',
2839 '\u1E3B': 'l',
2840 '\u017F': 'l',
2841 '\u0142': 'l',
2842 '\u019A': 'l',
2843 '\u026B': 'l',
2844 '\u2C61': 'l',
2845 '\uA749': 'l',
2846 '\uA781': 'l',
2847 '\uA747': 'l',
2848 '\u01C9': 'lj',
2849 '\u24DC': 'm',
2850 '\uFF4D': 'm',
2851 '\u1E3F': 'm',
2852 '\u1E41': 'm',
2853 '\u1E43': 'm',
2854 '\u0271': 'm',
2855 '\u026F': 'm',
2856 '\u24DD': 'n',
2857 '\uFF4E': 'n',
2858 '\u01F9': 'n',
2859 '\u0144': 'n',
2860 '\u00F1': 'n',
2861 '\u1E45': 'n',
2862 '\u0148': 'n',
2863 '\u1E47': 'n',
2864 '\u0146': 'n',
2865 '\u1E4B': 'n',
2866 '\u1E49': 'n',
2867 '\u019E': 'n',
2868 '\u0272': 'n',
2869 '\u0149': 'n',
2870 '\uA791': 'n',
2871 '\uA7A5': 'n',
2872 '\u01CC': 'nj',
2873 '\u24DE': 'o',
2874 '\uFF4F': 'o',
2875 '\u00F2': 'o',
2876 '\u00F3': 'o',
2877 '\u00F4': 'o',
2878 '\u1ED3': 'o',
2879 '\u1ED1': 'o',
2880 '\u1ED7': 'o',
2881 '\u1ED5': 'o',
2882 '\u00F5': 'o',
2883 '\u1E4D': 'o',
2884 '\u022D': 'o',
2885 '\u1E4F': 'o',
2886 '\u014D': 'o',
2887 '\u1E51': 'o',
2888 '\u1E53': 'o',
2889 '\u014F': 'o',
2890 '\u022F': 'o',
2891 '\u0231': 'o',
2892 '\u00F6': 'o',
2893 '\u022B': 'o',
2894 '\u1ECF': 'o',
2895 '\u0151': 'o',
2896 '\u01D2': 'o',
2897 '\u020D': 'o',
2898 '\u020F': 'o',
2899 '\u01A1': 'o',
2900 '\u1EDD': 'o',
2901 '\u1EDB': 'o',
2902 '\u1EE1': 'o',
2903 '\u1EDF': 'o',
2904 '\u1EE3': 'o',
2905 '\u1ECD': 'o',
2906 '\u1ED9': 'o',
2907 '\u01EB': 'o',
2908 '\u01ED': 'o',
2909 '\u00F8': 'o',
2910 '\u01FF': 'o',
2911 '\u0254': 'o',
2912 '\uA74B': 'o',
2913 '\uA74D': 'o',
2914 '\u0275': 'o',
2915 '\u01A3': 'oi',
2916 '\u0223': 'ou',
2917 '\uA74F': 'oo',
2918 '\u24DF': 'p',
2919 '\uFF50': 'p',
2920 '\u1E55': 'p',
2921 '\u1E57': 'p',
2922 '\u01A5': 'p',
2923 '\u1D7D': 'p',
2924 '\uA751': 'p',
2925 '\uA753': 'p',
2926 '\uA755': 'p',
2927 '\u24E0': 'q',
2928 '\uFF51': 'q',
2929 '\u024B': 'q',
2930 '\uA757': 'q',
2931 '\uA759': 'q',
2932 '\u24E1': 'r',
2933 '\uFF52': 'r',
2934 '\u0155': 'r',
2935 '\u1E59': 'r',
2936 '\u0159': 'r',
2937 '\u0211': 'r',
2938 '\u0213': 'r',
2939 '\u1E5B': 'r',
2940 '\u1E5D': 'r',
2941 '\u0157': 'r',
2942 '\u1E5F': 'r',
2943 '\u024D': 'r',
2944 '\u027D': 'r',
2945 '\uA75B': 'r',
2946 '\uA7A7': 'r',
2947 '\uA783': 'r',
2948 '\u24E2': 's',
2949 '\uFF53': 's',
2950 '\u00DF': 's',
2951 '\u015B': 's',
2952 '\u1E65': 's',
2953 '\u015D': 's',
2954 '\u1E61': 's',
2955 '\u0161': 's',
2956 '\u1E67': 's',
2957 '\u1E63': 's',
2958 '\u1E69': 's',
2959 '\u0219': 's',
2960 '\u015F': 's',
2961 '\u023F': 's',
2962 '\uA7A9': 's',
2963 '\uA785': 's',
2964 '\u1E9B': 's',
2965 '\u24E3': 't',
2966 '\uFF54': 't',
2967 '\u1E6B': 't',
2968 '\u1E97': 't',
2969 '\u0165': 't',
2970 '\u1E6D': 't',
2971 '\u021B': 't',
2972 '\u0163': 't',
2973 '\u1E71': 't',
2974 '\u1E6F': 't',
2975 '\u0167': 't',
2976 '\u01AD': 't',
2977 '\u0288': 't',
2978 '\u2C66': 't',
2979 '\uA787': 't',
2980 '\uA729': 'tz',
2981 '\u24E4': 'u',
2982 '\uFF55': 'u',
2983 '\u00F9': 'u',
2984 '\u00FA': 'u',
2985 '\u00FB': 'u',
2986 '\u0169': 'u',
2987 '\u1E79': 'u',
2988 '\u016B': 'u',
2989 '\u1E7B': 'u',
2990 '\u016D': 'u',
2991 '\u00FC': 'u',
2992 '\u01DC': 'u',
2993 '\u01D8': 'u',
2994 '\u01D6': 'u',
2995 '\u01DA': 'u',
2996 '\u1EE7': 'u',
2997 '\u016F': 'u',
2998 '\u0171': 'u',
2999 '\u01D4': 'u',
3000 '\u0215': 'u',
3001 '\u0217': 'u',
3002 '\u01B0': 'u',
3003 '\u1EEB': 'u',
3004 '\u1EE9': 'u',
3005 '\u1EEF': 'u',
3006 '\u1EED': 'u',
3007 '\u1EF1': 'u',
3008 '\u1EE5': 'u',
3009 '\u1E73': 'u',
3010 '\u0173': 'u',
3011 '\u1E77': 'u',
3012 '\u1E75': 'u',
3013 '\u0289': 'u',
3014 '\u24E5': 'v',
3015 '\uFF56': 'v',
3016 '\u1E7D': 'v',
3017 '\u1E7F': 'v',
3018 '\u028B': 'v',
3019 '\uA75F': 'v',
3020 '\u028C': 'v',
3021 '\uA761': 'vy',
3022 '\u24E6': 'w',
3023 '\uFF57': 'w',
3024 '\u1E81': 'w',
3025 '\u1E83': 'w',
3026 '\u0175': 'w',
3027 '\u1E87': 'w',
3028 '\u1E85': 'w',
3029 '\u1E98': 'w',
3030 '\u1E89': 'w',
3031 '\u2C73': 'w',
3032 '\u24E7': 'x',
3033 '\uFF58': 'x',
3034 '\u1E8B': 'x',
3035 '\u1E8D': 'x',
3036 '\u24E8': 'y',
3037 '\uFF59': 'y',
3038 '\u1EF3': 'y',
3039 '\u00FD': 'y',
3040 '\u0177': 'y',
3041 '\u1EF9': 'y',
3042 '\u0233': 'y',
3043 '\u1E8F': 'y',
3044 '\u00FF': 'y',
3045 '\u1EF7': 'y',
3046 '\u1E99': 'y',
3047 '\u1EF5': 'y',
3048 '\u01B4': 'y',
3049 '\u024F': 'y',
3050 '\u1EFF': 'y',
3051 '\u24E9': 'z',
3052 '\uFF5A': 'z',
3053 '\u017A': 'z',
3054 '\u1E91': 'z',
3055 '\u017C': 'z',
3056 '\u017E': 'z',
3057 '\u1E93': 'z',
3058 '\u1E95': 'z',
3059 '\u01B6': 'z',
3060 '\u0225': 'z',
3061 '\u0240': 'z',
3062 '\u2C6C': 'z',
3063 '\uA763': 'z',
3064 '\u0386': '\u0391',
3065 '\u0388': '\u0395',
3066 '\u0389': '\u0397',
3067 '\u038A': '\u0399',
3068 '\u03AA': '\u0399',
3069 '\u038C': '\u039F',
3070 '\u038E': '\u03A5',
3071 '\u03AB': '\u03A5',
3072 '\u038F': '\u03A9',
3073 '\u03AC': '\u03B1',
3074 '\u03AD': '\u03B5',
3075 '\u03AE': '\u03B7',
3076 '\u03AF': '\u03B9',
3077 '\u03CA': '\u03B9',
3078 '\u0390': '\u03B9',
3079 '\u03CC': '\u03BF',
3080 '\u03CD': '\u03C5',
3081 '\u03CB': '\u03C5',
3082 '\u03B0': '\u03C5',
3083 '\u03C9': '\u03C9',
3084 '\u03C2': '\u03C3'
3085 };
3086
3087 return diacritics;
3088});
3089
3090S2.define('select2/data/base',[
3091 '../utils'
3092], function (Utils) {
3093 function BaseAdapter ($element, options) {
3094 BaseAdapter.__super__.constructor.call(this);
3095 }
3096
3097 Utils.Extend(BaseAdapter, Utils.Observable);
3098
3099 BaseAdapter.prototype.current = function (callback) {
3100 throw new Error('The `current` method must be defined in child classes.');
3101 };
3102
3103 BaseAdapter.prototype.query = function (params, callback) {
3104 throw new Error('The `query` method must be defined in child classes.');
3105 };
3106
3107 BaseAdapter.prototype.bind = function (container, $container) {
3108 // Can be implemented in subclasses
3109 };
3110
3111 BaseAdapter.prototype.destroy = function () {
3112 // Can be implemented in subclasses
3113 };
3114
3115 BaseAdapter.prototype.generateResultId = function (container, data) {
3116 var id = container.id + '-result-';
3117
3118 id += Utils.generateChars(4);
3119
3120 if (data.id != null) {
3121 id += '-' + data.id.toString();
3122 } else {
3123 id += '-' + Utils.generateChars(4);
3124 }
3125 return id;
3126 };
3127
3128 return BaseAdapter;
3129});
3130
3131S2.define('select2/data/select',[
3132 './base',
3133 '../utils',
3134 'jquery'
3135], function (BaseAdapter, Utils, $) {
3136 function SelectAdapter ($element, options) {
3137 this.$element = $element;
3138 this.options = options;
3139
3140 SelectAdapter.__super__.constructor.call(this);
3141 }
3142
3143 Utils.Extend(SelectAdapter, BaseAdapter);
3144
3145 SelectAdapter.prototype.current = function (callback) {
3146 var data = [];
3147 var self = this;
3148
3149 this.$element.find(':selected').each(function () {
3150 var $option = $(this);
3151
3152 var option = self.item($option);
3153
3154 data.push(option);
3155 });
3156
3157 callback(data);
3158 };
3159
3160 SelectAdapter.prototype.select = function (data) {
3161 var self = this;
3162
3163 data.selected = true;
3164
3165 // If data.element is a DOM node, use it instead
3166 if ($(data.element).is('option')) {
3167 data.element.selected = true;
3168
3169 this.$element.trigger('change');
3170
3171 return;
3172 }
3173
3174 if (this.$element.prop('multiple')) {
3175 this.current(function (currentData) {
3176 var val = [];
3177
3178 data = [data];
3179 data.push.apply(data, currentData);
3180
3181 for (var d = 0; d < data.length; d++) {
3182 var id = data[d].id;
3183
3184 if ($.inArray(id, val) === -1) {
3185 val.push(id);
3186 }
3187 }
3188
3189 self.$element.val(val);
3190 self.$element.trigger('change');
3191 });
3192 } else {
3193 var val = data.id;
3194
3195 this.$element.val(val);
3196 this.$element.trigger('change');
3197 }
3198 };
3199
3200 SelectAdapter.prototype.unselect = function (data) {
3201 var self = this;
3202
3203 if (!this.$element.prop('multiple')) {
3204 return;
3205 }
3206
3207 data.selected = false;
3208
3209 if ($(data.element).is('option')) {
3210 data.element.selected = false;
3211
3212 this.$element.trigger('change');
3213
3214 return;
3215 }
3216
3217 this.current(function (currentData) {
3218 var val = [];
3219
3220 for (var d = 0; d < currentData.length; d++) {
3221 var id = currentData[d].id;
3222
3223 if (id !== data.id && $.inArray(id, val) === -1) {
3224 val.push(id);
3225 }
3226 }
3227
3228 self.$element.val(val);
3229
3230 self.$element.trigger('change');
3231 });
3232 };
3233
3234 SelectAdapter.prototype.bind = function (container, $container) {
3235 var self = this;
3236
3237 this.container = container;
3238
3239 container.on('select', function (params) {
3240 self.select(params.data);
3241 });
3242
3243 container.on('unselect', function (params) {
3244 self.unselect(params.data);
3245 });
3246 };
3247
3248 SelectAdapter.prototype.destroy = function () {
3249 // Remove anything added to child elements
3250 this.$element.find('*').each(function () {
3251 // Remove any custom data set by Select2
3252 Utils.RemoveData(this);
3253 });
3254 };
3255
3256 SelectAdapter.prototype.query = function (params, callback) {
3257 var data = [];
3258 var self = this;
3259
3260 var $options = this.$element.children();
3261
3262 $options.each(function () {
3263 var $option = $(this);
3264
3265 if (!$option.is('option') && !$option.is('optgroup')) {
3266 return;
3267 }
3268
3269 var option = self.item($option);
3270
3271 var matches = self.matches(params, option);
3272
3273 if (matches !== null) {
3274 data.push(matches);
3275 }
3276 });
3277
3278 callback({
3279 results: data
3280 });
3281 };
3282
3283 SelectAdapter.prototype.addOptions = function ($options) {
3284 Utils.appendMany(this.$element, $options);
3285 };
3286
3287 SelectAdapter.prototype.option = function (data) {
3288 var option;
3289
3290 if (data.children) {
3291 option = document.createElement('optgroup');
3292 option.label = data.text;
3293 } else {
3294 option = document.createElement('option');
3295
3296 if (option.textContent !== undefined) {
3297 option.textContent = data.text;
3298 } else {
3299 option.innerText = data.text;
3300 }
3301 }
3302
3303 if (data.id !== undefined) {
3304 option.value = data.id;
3305 }
3306
3307 if (data.disabled) {
3308 option.disabled = true;
3309 }
3310
3311 if (data.selected) {
3312 option.selected = true;
3313 }
3314
3315 if (data.title) {
3316 option.title = data.title;
3317 }
3318
3319 var $option = $(option);
3320
3321 var normalizedData = this._normalizeItem(data);
3322 normalizedData.element = option;
3323
3324 // Override the option's data with the combined data
3325 Utils.StoreData(option, 'data', normalizedData);
3326
3327 return $option;
3328 };
3329
3330 SelectAdapter.prototype.item = function ($option) {
3331 var data = {};
3332
3333 data = Utils.GetData($option[0], 'data');
3334
3335 if (data != null) {
3336 return data;
3337 }
3338
3339 if ($option.is('option')) {
3340 data = {
3341 id: $option.val(),
3342 text: $option.text(),
3343 disabled: $option.prop('disabled'),
3344 selected: $option.prop('selected'),
3345 title: $option.prop('title')
3346 };
3347 } else if ($option.is('optgroup')) {
3348 data = {
3349 text: $option.prop('label'),
3350 children: [],
3351 title: $option.prop('title')
3352 };
3353
3354 var $children = $option.children('option');
3355 var children = [];
3356
3357 for (var c = 0; c < $children.length; c++) {
3358 var $child = $($children[c]);
3359
3360 var child = this.item($child);
3361
3362 children.push(child);
3363 }
3364
3365 data.children = children;
3366 }
3367
3368 data = this._normalizeItem(data);
3369 data.element = $option[0];
3370
3371 Utils.StoreData($option[0], 'data', data);
3372
3373 return data;
3374 };
3375
3376 SelectAdapter.prototype._normalizeItem = function (item) {
3377 if (item !== Object(item)) {
3378 item = {
3379 id: item,
3380 text: item
3381 };
3382 }
3383
3384 item = $.extend({}, {
3385 text: ''
3386 }, item);
3387
3388 var defaults = {
3389 selected: false,
3390 disabled: false
3391 };
3392
3393 if (item.id != null) {
3394 item.id = item.id.toString();
3395 }
3396
3397 if (item.text != null) {
3398 item.text = item.text.toString();
3399 }
3400
3401 if (item._resultId == null && item.id && this.container != null) {
3402 item._resultId = this.generateResultId(this.container, item);
3403 }
3404
3405 return $.extend({}, defaults, item);
3406 };
3407
3408 SelectAdapter.prototype.matches = function (params, data) {
3409 var matcher = this.options.get('matcher');
3410
3411 return matcher(params, data);
3412 };
3413
3414 return SelectAdapter;
3415});
3416
3417S2.define('select2/data/array',[
3418 './select',
3419 '../utils',
3420 'jquery'
3421], function (SelectAdapter, Utils, $) {
3422 function ArrayAdapter ($element, options) {
3423 var data = options.get('data') || [];
3424
3425 ArrayAdapter.__super__.constructor.call(this, $element, options);
3426
3427 this.addOptions(this.convertToOptions(data));
3428 }
3429
3430 Utils.Extend(ArrayAdapter, SelectAdapter);
3431
3432 ArrayAdapter.prototype.select = function (data) {
3433 var $option = this.$element.find('option').filter(function (i, elm) {
3434 return elm.value == data.id.toString();
3435 });
3436
3437 if ($option.length === 0) {
3438 $option = this.option(data);
3439
3440 this.addOptions($option);
3441 }
3442
3443 ArrayAdapter.__super__.select.call(this, data);
3444 };
3445
3446 ArrayAdapter.prototype.convertToOptions = function (data) {
3447 var self = this;
3448
3449 var $existing = this.$element.find('option');
3450 var existingIds = $existing.map(function () {
3451 return self.item($(this)).id;
3452 }).get();
3453
3454 var $options = [];
3455
3456 // Filter out all items except for the one passed in the argument
3457 function onlyItem (item) {
3458 return function () {
3459 return $(this).val() == item.id;
3460 };
3461 }
3462
3463 for (var d = 0; d < data.length; d++) {
3464 var item = this._normalizeItem(data[d]);
3465
3466 // Skip items which were pre-loaded, only merge the data
3467 if ($.inArray(item.id, existingIds) >= 0) {
3468 var $existingOption = $existing.filter(onlyItem(item));
3469
3470 var existingData = this.item($existingOption);
3471 var newData = $.extend(true, {}, item, existingData);
3472
3473 var $newOption = this.option(newData);
3474
3475 $existingOption.replaceWith($newOption);
3476
3477 continue;
3478 }
3479
3480 var $option = this.option(item);
3481
3482 if (item.children) {
3483 var $children = this.convertToOptions(item.children);
3484
3485 Utils.appendMany($option, $children);
3486 }
3487
3488 $options.push($option);
3489 }
3490
3491 return $options;
3492 };
3493
3494 return ArrayAdapter;
3495});
3496
3497S2.define('select2/data/ajax',[
3498 './array',
3499 '../utils',
3500 'jquery'
3501], function (ArrayAdapter, Utils, $) {
3502 function AjaxAdapter ($element, options) {
3503 this.ajaxOptions = this._applyDefaults(options.get('ajax'));
3504
3505 if (this.ajaxOptions.processResults != null) {
3506 this.processResults = this.ajaxOptions.processResults;
3507 }
3508
3509 AjaxAdapter.__super__.constructor.call(this, $element, options);
3510 }
3511
3512 Utils.Extend(AjaxAdapter, ArrayAdapter);
3513
3514 AjaxAdapter.prototype._applyDefaults = function (options) {
3515 var defaults = {
3516 data: function (params) {
3517 return $.extend({}, params, {
3518 q: params.term
3519 });
3520 },
3521 transport: function (params, success, failure) {
3522 var $request = $.ajax(params);
3523
3524 $request.then(success);
3525 $request.fail(failure);
3526
3527 return $request;
3528 }
3529 };
3530
3531 return $.extend({}, defaults, options, true);
3532 };
3533
3534 AjaxAdapter.prototype.processResults = function (results) {
3535 return results;
3536 };
3537
3538 AjaxAdapter.prototype.query = function (params, callback) {
3539 var matches = [];
3540 var self = this;
3541
3542 if (this._request != null) {
3543 // JSONP requests cannot always be aborted
3544 if ($.isFunction(this._request.abort)) {
3545 this._request.abort();
3546 }
3547
3548 this._request = null;
3549 }
3550
3551 var options = $.extend({
3552 type: 'GET'
3553 }, this.ajaxOptions);
3554
3555 if (typeof options.url === 'function') {
3556 options.url = options.url.call(this.$element, params);
3557 }
3558
3559 if (typeof options.data === 'function') {
3560 options.data = options.data.call(this.$element, params);
3561 }
3562
3563 function request () {
3564 var $request = options.transport(options, function (data) {
3565 var results = self.processResults(data, params);
3566
3567 if (self.options.get('debug') && window.console && console.error) {
3568 // Check to make sure that the response included a `results` key.
3569 if (!results || !results.results || !$.isArray(results.results)) {
3570 console.error(
3571 'Select2: The AJAX results did not return an array in the ' +
3572 '`results` key of the response.'
3573 );
3574 }
3575 }
3576
3577 callback(results);
3578 }, function () {
3579 // Attempt to detect if a request was aborted
3580 // Only works if the transport exposes a status property
3581 if ('status' in $request &&
3582 ($request.status === 0 || $request.status === '0')) {
3583 return;
3584 }
3585
3586 self.trigger('results:message', {
3587 message: 'errorLoading'
3588 });
3589 });
3590
3591 self._request = $request;
3592 }
3593
3594 if (this.ajaxOptions.delay && params.term != null) {
3595 if (this._queryTimeout) {
3596 window.clearTimeout(this._queryTimeout);
3597 }
3598
3599 this._queryTimeout = window.setTimeout(request, this.ajaxOptions.delay);
3600 } else {
3601 request();
3602 }
3603 };
3604
3605 return AjaxAdapter;
3606});
3607
3608S2.define('select2/data/tags',[
3609 'jquery'
3610], function ($) {
3611 function Tags (decorated, $element, options) {
3612 var tags = options.get('tags');
3613
3614 var createTag = options.get('createTag');
3615
3616 if (createTag !== undefined) {
3617 this.createTag = createTag;
3618 }
3619
3620 var insertTag = options.get('insertTag');
3621
3622 if (insertTag !== undefined) {
3623 this.insertTag = insertTag;
3624 }
3625
3626 decorated.call(this, $element, options);
3627
3628 if ($.isArray(tags)) {
3629 for (var t = 0; t < tags.length; t++) {
3630 var tag = tags[t];
3631 var item = this._normalizeItem(tag);
3632
3633 var $option = this.option(item);
3634
3635 this.$element.append($option);
3636 }
3637 }
3638 }
3639
3640 Tags.prototype.query = function (decorated, params, callback) {
3641 var self = this;
3642
3643 this._removeOldTags();
3644
3645 if (params.term == null || params.page != null) {
3646 decorated.call(this, params, callback);
3647 return;
3648 }
3649
3650 function wrapper (obj, child) {
3651 var data = obj.results;
3652
3653 for (var i = 0; i < data.length; i++) {
3654 var option = data[i];
3655
3656 var checkChildren = (
3657 option.children != null &&
3658 !wrapper({
3659 results: option.children
3660 }, true)
3661 );
3662
3663 var optionText = (option.text || '').toUpperCase();
3664 var paramsTerm = (params.term || '').toUpperCase();
3665
3666 var checkText = optionText === paramsTerm;
3667
3668 if (checkText || checkChildren) {
3669 if (child) {
3670 return false;
3671 }
3672
3673 obj.data = data;
3674 callback(obj);
3675
3676 return;
3677 }
3678 }
3679
3680 if (child) {
3681 return true;
3682 }
3683
3684 var tag = self.createTag(params);
3685
3686 if (tag != null) {
3687 var $option = self.option(tag);
3688 $option.attr('data-select2-tag', true);
3689
3690 self.addOptions([$option]);
3691
3692 self.insertTag(data, tag);
3693 }
3694
3695 obj.results = data;
3696
3697 callback(obj);
3698 }
3699
3700 decorated.call(this, params, wrapper);
3701 };
3702
3703 Tags.prototype.createTag = function (decorated, params) {
3704 var term = $.trim(params.term);
3705
3706 if (term === '') {
3707 return null;
3708 }
3709
3710 return {
3711 id: term,
3712 text: term
3713 };
3714 };
3715
3716 Tags.prototype.insertTag = function (_, data, tag) {
3717 data.unshift(tag);
3718 };
3719
3720 Tags.prototype._removeOldTags = function (_) {
3721 var tag = this._lastTag;
3722
3723 var $options = this.$element.find('option[data-select2-tag]');
3724
3725 $options.each(function () {
3726 if (this.selected) {
3727 return;
3728 }
3729
3730 $(this).remove();
3731 });
3732 };
3733
3734 return Tags;
3735});
3736
3737S2.define('select2/data/tokenizer',[
3738 'jquery'
3739], function ($) {
3740 function Tokenizer (decorated, $element, options) {
3741 var tokenizer = options.get('tokenizer');
3742
3743 if (tokenizer !== undefined) {
3744 this.tokenizer = tokenizer;
3745 }
3746
3747 decorated.call(this, $element, options);
3748 }
3749
3750 Tokenizer.prototype.bind = function (decorated, container, $container) {
3751 decorated.call(this, container, $container);
3752
3753 this.$search = container.dropdown.$search || container.selection.$search ||
3754 $container.find('.select2-search__field');
3755 };
3756
3757 Tokenizer.prototype.query = function (decorated, params, callback) {
3758 var self = this;
3759
3760 function createAndSelect (data) {
3761 // Normalize the data object so we can use it for checks
3762 var item = self._normalizeItem(data);
3763
3764 // Check if the data object already exists as a tag
3765 // Select it if it doesn't
3766 var $existingOptions = self.$element.find('option').filter(function () {
3767 return $(this).val() === item.id;
3768 });
3769
3770 // If an existing option wasn't found for it, create the option
3771 if (!$existingOptions.length) {
3772 var $option = self.option(item);
3773 $option.attr('data-select2-tag', true);
3774
3775 self._removeOldTags();
3776 self.addOptions([$option]);
3777 }
3778
3779 // Select the item, now that we know there is an option for it
3780 select(item);
3781 }
3782
3783 function select (data) {
3784 self.trigger('select', {
3785 data: data
3786 });
3787 }
3788
3789 params.term = params.term || '';
3790
3791 var tokenData = this.tokenizer(params, this.options, createAndSelect);
3792
3793 if (tokenData.term !== params.term) {
3794 // Replace the search term if we have the search box
3795 if (this.$search.length) {
3796 this.$search.val(tokenData.term);
3797 this.$search.focus();
3798 }
3799
3800 params.term = tokenData.term;
3801 }
3802
3803 decorated.call(this, params, callback);
3804 };
3805
3806 Tokenizer.prototype.tokenizer = function (_, params, options, callback) {
3807 var separators = options.get('tokenSeparators') || [];
3808 var term = params.term;
3809 var i = 0;
3810
3811 var createTag = this.createTag || function (params) {
3812 return {
3813 id: params.term,
3814 text: params.term
3815 };
3816 };
3817
3818 while (i < term.length) {
3819 var termChar = term[i];
3820
3821 if ($.inArray(termChar, separators) === -1) {
3822 i++;
3823
3824 continue;
3825 }
3826
3827 var part = term.substr(0, i);
3828 var partParams = $.extend({}, params, {
3829 term: part
3830 });
3831
3832 var data = createTag(partParams);
3833
3834 if (data == null) {
3835 i++;
3836 continue;
3837 }
3838
3839 callback(data);
3840
3841 // Reset the term to not include the tokenized portion
3842 term = term.substr(i + 1) || '';
3843 i = 0;
3844 }
3845
3846 return {
3847 term: term
3848 };
3849 };
3850
3851 return Tokenizer;
3852});
3853
3854S2.define('select2/data/minimumInputLength',[
3855
3856], function () {
3857 function MinimumInputLength (decorated, $e, options) {
3858 this.minimumInputLength = options.get('minimumInputLength');
3859
3860 decorated.call(this, $e, options);
3861 }
3862
3863 MinimumInputLength.prototype.query = function (decorated, params, callback) {
3864 params.term = params.term || '';
3865
3866 if (params.term.length < this.minimumInputLength) {
3867 this.trigger('results:message', {
3868 message: 'inputTooShort',
3869 args: {
3870 minimum: this.minimumInputLength,
3871 input: params.term,
3872 params: params
3873 }
3874 });
3875
3876 return;
3877 }
3878
3879 decorated.call(this, params, callback);
3880 };
3881
3882 return MinimumInputLength;
3883});
3884
3885S2.define('select2/data/maximumInputLength',[
3886
3887], function () {
3888 function MaximumInputLength (decorated, $e, options) {
3889 this.maximumInputLength = options.get('maximumInputLength');
3890
3891 decorated.call(this, $e, options);
3892 }
3893
3894 MaximumInputLength.prototype.query = function (decorated, params, callback) {
3895 params.term = params.term || '';
3896
3897 if (this.maximumInputLength > 0 &&
3898 params.term.length > this.maximumInputLength) {
3899 this.trigger('results:message', {
3900 message: 'inputTooLong',
3901 args: {
3902 maximum: this.maximumInputLength,
3903 input: params.term,
3904 params: params
3905 }
3906 });
3907
3908 return;
3909 }
3910
3911 decorated.call(this, params, callback);
3912 };
3913
3914 return MaximumInputLength;
3915});
3916
3917S2.define('select2/data/maximumSelectionLength',[
3918
3919], function (){
3920 function MaximumSelectionLength (decorated, $e, options) {
3921 this.maximumSelectionLength = options.get('maximumSelectionLength');
3922
3923 decorated.call(this, $e, options);
3924 }
3925
3926 MaximumSelectionLength.prototype.query =
3927 function (decorated, params, callback) {
3928 var self = this;
3929
3930 this.current(function (currentData) {
3931 var count = currentData != null ? currentData.length : 0;
3932 if (self.maximumSelectionLength > 0 &&
3933 count >= self.maximumSelectionLength) {
3934 self.trigger('results:message', {
3935 message: 'maximumSelected',
3936 args: {
3937 maximum: self.maximumSelectionLength
3938 }
3939 });
3940 return;
3941 }
3942 decorated.call(self, params, callback);
3943 });
3944 };
3945
3946 return MaximumSelectionLength;
3947});
3948
3949S2.define('select2/dropdown',[
3950 'jquery',
3951 './utils'
3952], function ($, Utils) {
3953 function Dropdown ($element, options) {
3954 this.$element = $element;
3955 this.options = options;
3956
3957 Dropdown.__super__.constructor.call(this);
3958 }
3959
3960 Utils.Extend(Dropdown, Utils.Observable);
3961
3962 Dropdown.prototype.render = function () {
3963 var $dropdown = $(
3964 '<span class="select2-dropdown">' +
3965 '<span class="select2-results"></span>' +
3966 '</span>'
3967 );
3968
3969 $dropdown.attr('dir', this.options.get('dir'));
3970
3971 this.$dropdown = $dropdown;
3972
3973 return $dropdown;
3974 };
3975
3976 Dropdown.prototype.bind = function () {
3977 // Should be implemented in subclasses
3978 };
3979
3980 Dropdown.prototype.position = function ($dropdown, $container) {
3981 // Should be implmented in subclasses
3982 };
3983
3984 Dropdown.prototype.destroy = function () {
3985 // Remove the dropdown from the DOM
3986 this.$dropdown.remove();
3987 };
3988
3989 return Dropdown;
3990});
3991
3992S2.define('select2/dropdown/search',[
3993 'jquery',
3994 '../utils'
3995], function ($, Utils) {
3996 function Search () { }
3997
3998 Search.prototype.render = function (decorated) {
3999 var $rendered = decorated.call(this);
4000
4001 var $search = $(
4002 '<span class="select2-search select2-search--dropdown">' +
4003 '<input class="select2-search__field" type="search" tabindex="-1"' +
4004 ' autocomplete="off" autocorrect="off" autocapitalize="none"' +
4005 ' spellcheck="false" role="textbox" />' +
4006 '</span>'
4007 );
4008
4009 this.$searchContainer = $search;
4010 this.$search = $search.find('input');
4011
4012 $rendered.prepend($search);
4013
4014 return $rendered;
4015 };
4016
4017 Search.prototype.bind = function (decorated, container, $container) {
4018 var self = this;
4019
4020 decorated.call(this, container, $container);
4021
4022 this.$search.on('keydown', function (evt) {
4023 self.trigger('keypress', evt);
4024
4025 self._keyUpPrevented = evt.isDefaultPrevented();
4026 });
4027
4028 // Workaround for browsers which do not support the `input` event
4029 // This will prevent double-triggering of events for browsers which support
4030 // both the `keyup` and `input` events.
4031 this.$search.on('input', function (evt) {
4032 // Unbind the duplicated `keyup` event
4033 $(this).off('keyup');
4034 });
4035
4036 this.$search.on('keyup input', function (evt) {
4037 self.handleSearch(evt);
4038 });
4039
4040 container.on('open', function () {
4041 self.$search.attr('tabindex', 0);
4042
4043 self.$search.focus();
4044
4045 window.setTimeout(function () {
4046 self.$search.focus();
4047 }, 0);
4048 });
4049
4050 container.on('close', function () {
4051 self.$search.attr('tabindex', -1);
4052
4053 self.$search.val('');
4054 self.$search.blur();
4055 });
4056
4057 container.on('focus', function () {
4058 if (!container.isOpen()) {
4059 self.$search.focus();
4060 }
4061 });
4062
4063 container.on('results:all', function (params) {
4064 if (params.query.term == null || params.query.term === '') {
4065 var showSearch = self.showSearch(params);
4066
4067 if (showSearch) {
4068 self.$searchContainer.removeClass('select2-search--hide');
4069 } else {
4070 self.$searchContainer.addClass('select2-search--hide');
4071 }
4072 }
4073 });
4074 };
4075
4076 Search.prototype.handleSearch = function (evt) {
4077 if (!this._keyUpPrevented) {
4078 var input = this.$search.val();
4079
4080 this.trigger('query', {
4081 term: input
4082 });
4083 }
4084
4085 this._keyUpPrevented = false;
4086 };
4087
4088 Search.prototype.showSearch = function (_, params) {
4089 return true;
4090 };
4091
4092 return Search;
4093});
4094
4095S2.define('select2/dropdown/hidePlaceholder',[
4096
4097], function () {
4098 function HidePlaceholder (decorated, $element, options, dataAdapter) {
4099 this.placeholder = this.normalizePlaceholder(options.get('placeholder'));
4100
4101 decorated.call(this, $element, options, dataAdapter);
4102 }
4103
4104 HidePlaceholder.prototype.append = function (decorated, data) {
4105 data.results = this.removePlaceholder(data.results);
4106
4107 decorated.call(this, data);
4108 };
4109
4110 HidePlaceholder.prototype.normalizePlaceholder = function (_, placeholder) {
4111 if (typeof placeholder === 'string') {
4112 placeholder = {
4113 id: '',
4114 text: placeholder
4115 };
4116 }
4117
4118 return placeholder;
4119 };
4120
4121 HidePlaceholder.prototype.removePlaceholder = function (_, data) {
4122 var modifiedData = data.slice(0);
4123
4124 for (var d = data.length - 1; d >= 0; d--) {
4125 var item = data[d];
4126
4127 if (this.placeholder.id === item.id) {
4128 modifiedData.splice(d, 1);
4129 }
4130 }
4131
4132 return modifiedData;
4133 };
4134
4135 return HidePlaceholder;
4136});
4137
4138S2.define('select2/dropdown/infiniteScroll',[
4139 'jquery'
4140], function ($) {
4141 function InfiniteScroll (decorated, $element, options, dataAdapter) {
4142 this.lastParams = {};
4143
4144 decorated.call(this, $element, options, dataAdapter);
4145
4146 this.$loadingMore = this.createLoadingMore();
4147 this.loading = false;
4148 }
4149
4150 InfiniteScroll.prototype.append = function (decorated, data) {
4151 this.$loadingMore.remove();
4152 this.loading = false;
4153
4154 decorated.call(this, data);
4155
4156 if (this.showLoadingMore(data)) {
4157 this.$results.append(this.$loadingMore);
4158 }
4159 };
4160
4161 InfiniteScroll.prototype.bind = function (decorated, container, $container) {
4162 var self = this;
4163
4164 decorated.call(this, container, $container);
4165
4166 container.on('query', function (params) {
4167 self.lastParams = params;
4168 self.loading = true;
4169 });
4170
4171 container.on('query:append', function (params) {
4172 self.lastParams = params;
4173 self.loading = true;
4174 });
4175
4176 this.$results.on('scroll', function () {
4177 var isLoadMoreVisible = $.contains(
4178 document.documentElement,
4179 self.$loadingMore[0]
4180 );
4181
4182 if (self.loading || !isLoadMoreVisible) {
4183 return;
4184 }
4185
4186 var currentOffset = self.$results.offset().top +
4187 self.$results.outerHeight(false);
4188 var loadingMoreOffset = self.$loadingMore.offset().top +
4189 self.$loadingMore.outerHeight(false);
4190
4191 if (currentOffset + 50 >= loadingMoreOffset) {
4192 self.loadMore();
4193 }
4194 });
4195 };
4196
4197 InfiniteScroll.prototype.loadMore = function () {
4198 this.loading = true;
4199
4200 var params = $.extend({}, {page: 1}, this.lastParams);
4201
4202 params.page++;
4203
4204 this.trigger('query:append', params);
4205 };
4206
4207 InfiniteScroll.prototype.showLoadingMore = function (_, data) {
4208 return data.pagination && data.pagination.more;
4209 };
4210
4211 InfiniteScroll.prototype.createLoadingMore = function () {
4212 var $option = $(
4213 '<li ' +
4214 'class="select2-results__option select2-results__option--load-more"' +
4215 'role="treeitem" aria-disabled="true"></li>'
4216 );
4217
4218 var message = this.options.get('translations').get('loadingMore');
4219
4220 $option.html(message(this.lastParams));
4221
4222 return $option;
4223 };
4224
4225 return InfiniteScroll;
4226});
4227
4228S2.define('select2/dropdown/attachBody',[
4229 'jquery',
4230 '../utils'
4231], function ($, Utils) {
4232 function AttachBody (decorated, $element, options) {
4233 this.$dropdownParent = options.get('dropdownParent') || $(document.body);
4234
4235 decorated.call(this, $element, options);
4236 }
4237
4238 AttachBody.prototype.bind = function (decorated, container, $container) {
4239 var self = this;
4240
4241 var setupResultsEvents = false;
4242
4243 decorated.call(this, container, $container);
4244
4245 container.on('open', function () {
4246 self._showDropdown();
4247 self._attachPositioningHandler(container);
4248
4249 if (!setupResultsEvents) {
4250 setupResultsEvents = true;
4251
4252 container.on('results:all', function () {
4253 self._positionDropdown();
4254 self._resizeDropdown();
4255 });
4256
4257 container.on('results:append', function () {
4258 self._positionDropdown();
4259 self._resizeDropdown();
4260 });
4261 }
4262 });
4263
4264 container.on('close', function () {
4265 self._hideDropdown();
4266 self._detachPositioningHandler(container);
4267 });
4268
4269 this.$dropdownContainer.on('mousedown', function (evt) {
4270 evt.stopPropagation();
4271 });
4272 };
4273
4274 AttachBody.prototype.destroy = function (decorated) {
4275 decorated.call(this);
4276
4277 this.$dropdownContainer.remove();
4278 };
4279
4280 AttachBody.prototype.position = function (decorated, $dropdown, $container) {
4281 // Clone all of the container classes
4282 $dropdown.attr('class', $container.attr('class'));
4283
4284 $dropdown.removeClass('select2');
4285 $dropdown.addClass('select2-container--open');
4286
4287 $dropdown.css({
4288 position: 'absolute',
4289 top: -999999
4290 });
4291
4292 this.$container = $container;
4293 };
4294
4295 AttachBody.prototype.render = function (decorated) {
4296 var $container = $('<span></span>');
4297
4298 var $dropdown = decorated.call(this);
4299 $container.append($dropdown);
4300
4301 this.$dropdownContainer = $container;
4302
4303 return $container;
4304 };
4305
4306 AttachBody.prototype._hideDropdown = function (decorated) {
4307 this.$dropdownContainer.detach();
4308 };
4309
4310 AttachBody.prototype._attachPositioningHandler =
4311 function (decorated, container) {
4312 var self = this;
4313
4314 var scrollEvent = 'scroll.select2.' + container.id;
4315 var resizeEvent = 'resize.select2.' + container.id;
4316 var orientationEvent = 'orientationchange.select2.' + container.id;
4317
4318 var $watchers = this.$container.parents().filter(Utils.hasScroll);
4319 $watchers.each(function () {
4320 Utils.StoreData(this, 'select2-scroll-position', {
4321 x: $(this).scrollLeft(),
4322 y: $(this).scrollTop()
4323 });
4324 });
4325
4326 $watchers.on(scrollEvent, function (ev) {
4327 var position = Utils.GetData(this, 'select2-scroll-position');
4328 $(this).scrollTop(position.y);
4329 });
4330
4331 $(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent,
4332 function (e) {
4333 self._positionDropdown();
4334 self._resizeDropdown();
4335 });
4336 };
4337
4338 AttachBody.prototype._detachPositioningHandler =
4339 function (decorated, container) {
4340 var scrollEvent = 'scroll.select2.' + container.id;
4341 var resizeEvent = 'resize.select2.' + container.id;
4342 var orientationEvent = 'orientationchange.select2.' + container.id;
4343
4344 var $watchers = this.$container.parents().filter(Utils.hasScroll);
4345 $watchers.off(scrollEvent);
4346
4347 $(window).off(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent);
4348 };
4349
4350 AttachBody.prototype._positionDropdown = function () {
4351 var $window = $(window);
4352
4353 var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above');
4354 var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below');
4355
4356 var newDirection = null;
4357
4358 var offset = this.$container.offset();
4359
4360 offset.bottom = offset.top + this.$container.outerHeight(false);
4361
4362 var container = {
4363 height: this.$container.outerHeight(false)
4364 };
4365
4366 container.top = offset.top;
4367 container.bottom = offset.top + container.height;
4368
4369 var dropdown = {
4370 height: this.$dropdown.outerHeight(false)
4371 };
4372
4373 var viewport = {
4374 top: $window.scrollTop(),
4375 bottom: $window.scrollTop() + $window.height()
4376 };
4377
4378 var enoughRoomAbove = viewport.top < (offset.top - dropdown.height);
4379 var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height);
4380
4381 var css = {
4382 left: offset.left,
4383 top: container.bottom
4384 };
4385
4386 // Determine what the parent element is to use for calciulating the offset
4387 var $offsetParent = this.$dropdownParent;
4388
4389 // For statically positoned elements, we need to get the element
4390 // that is determining the offset
4391 if ($offsetParent.css('position') === 'static') {
4392 $offsetParent = $offsetParent.offsetParent();
4393 }
4394
4395 var parentOffset = $offsetParent.offset();
4396
4397 css.top -= parentOffset.top;
4398 css.left -= parentOffset.left;
4399
4400 if (!isCurrentlyAbove && !isCurrentlyBelow) {
4401 newDirection = 'below';
4402 }
4403
4404 if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) {
4405 newDirection = 'above';
4406 } else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) {
4407 newDirection = 'below';
4408 }
4409
4410 if (newDirection == 'above' ||
4411 (isCurrentlyAbove && newDirection !== 'below')) {
4412 css.top = container.top - parentOffset.top - dropdown.height;
4413 }
4414
4415 if (newDirection != null) {
4416 this.$dropdown
4417 .removeClass('select2-dropdown--below select2-dropdown--above')
4418 .addClass('select2-dropdown--' + newDirection);
4419 this.$container
4420 .removeClass('select2-container--below select2-container--above')
4421 .addClass('select2-container--' + newDirection);
4422 }
4423
4424 this.$dropdownContainer.css(css);
4425 };
4426
4427 AttachBody.prototype._resizeDropdown = function () {
4428 var css = {
4429 width: this.$container.outerWidth(false) + 'px'
4430 };
4431
4432 if (this.options.get('dropdownAutoWidth')) {
4433 css.minWidth = css.width;
4434 css.position = 'relative';
4435 css.width = 'auto';
4436 }
4437
4438 this.$dropdown.css(css);
4439 };
4440
4441 AttachBody.prototype._showDropdown = function (decorated) {
4442 this.$dropdownContainer.appendTo(this.$dropdownParent);
4443
4444 this._positionDropdown();
4445 this._resizeDropdown();
4446 };
4447
4448 return AttachBody;
4449});
4450
4451S2.define('select2/dropdown/minimumResultsForSearch',[
4452
4453], function () {
4454 function countResults (data) {
4455 var count = 0;
4456
4457 for (var d = 0; d < data.length; d++) {
4458 var item = data[d];
4459
4460 if (item.children) {
4461 count += countResults(item.children);
4462 } else {
4463 count++;
4464 }
4465 }
4466
4467 return count;
4468 }
4469
4470 function MinimumResultsForSearch (decorated, $element, options, dataAdapter) {
4471 this.minimumResultsForSearch = options.get('minimumResultsForSearch');
4472
4473 if (this.minimumResultsForSearch < 0) {
4474 this.minimumResultsForSearch = Infinity;
4475 }
4476
4477 decorated.call(this, $element, options, dataAdapter);
4478 }
4479
4480 MinimumResultsForSearch.prototype.showSearch = function (decorated, params) {
4481 if (countResults(params.data.results) < this.minimumResultsForSearch) {
4482 return false;
4483 }
4484
4485 return decorated.call(this, params);
4486 };
4487
4488 return MinimumResultsForSearch;
4489});
4490
4491S2.define('select2/dropdown/selectOnClose',[
4492 '../utils'
4493], function (Utils) {
4494 function SelectOnClose () { }
4495
4496 SelectOnClose.prototype.bind = function (decorated, container, $container) {
4497 var self = this;
4498
4499 decorated.call(this, container, $container);
4500
4501 container.on('close', function (params) {
4502 self._handleSelectOnClose(params);
4503 });
4504 };
4505
4506 SelectOnClose.prototype._handleSelectOnClose = function (_, params) {
4507 if (params && params.originalSelect2Event != null) {
4508 var event = params.originalSelect2Event;
4509
4510 // Don't select an item if the close event was triggered from a select or
4511 // unselect event
4512 if (event._type === 'select' || event._type === 'unselect') {
4513 return;
4514 }
4515 }
4516
4517 var $highlightedResults = this.getHighlightedResults();
4518
4519 // Only select highlighted results
4520 if ($highlightedResults.length < 1) {
4521 return;
4522 }
4523
4524 var data = Utils.GetData($highlightedResults[0], 'data');
4525
4526 // Don't re-select already selected resulte
4527 if (
4528 (data.element != null && data.element.selected) ||
4529 (data.element == null && data.selected)
4530 ) {
4531 return;
4532 }
4533
4534 this.trigger('select', {
4535 data: data
4536 });
4537 };
4538
4539 return SelectOnClose;
4540});
4541
4542S2.define('select2/dropdown/closeOnSelect',[
4543
4544], function () {
4545 function CloseOnSelect () { }
4546
4547 CloseOnSelect.prototype.bind = function (decorated, container, $container) {
4548 var self = this;
4549
4550 decorated.call(this, container, $container);
4551
4552 container.on('select', function (evt) {
4553 self._selectTriggered(evt);
4554 });
4555
4556 container.on('unselect', function (evt) {
4557 self._selectTriggered(evt);
4558 });
4559 };
4560
4561 CloseOnSelect.prototype._selectTriggered = function (_, evt) {
4562 var originalEvent = evt.originalEvent;
4563
4564 // Don't close if the control key is being held
4565 if (originalEvent && originalEvent.ctrlKey) {
4566 return;
4567 }
4568
4569 this.trigger('close', {
4570 originalEvent: originalEvent,
4571 originalSelect2Event: evt
4572 });
4573 };
4574
4575 return CloseOnSelect;
4576});
4577
4578S2.define('select2/i18n/en',[],function () {
4579 // English
4580 return {
4581 errorLoading: function () {
4582 return 'The results could not be loaded.';
4583 },
4584 inputTooLong: function (args) {
4585 var overChars = args.input.length - args.maximum;
4586
4587 var message = 'Please delete ' + overChars + ' character';
4588
4589 if (overChars != 1) {
4590 message += 's';
4591 }
4592
4593 return message;
4594 },
4595 inputTooShort: function (args) {
4596 var remainingChars = args.minimum - args.input.length;
4597
4598 var message = 'Please enter ' + remainingChars + ' or more characters';
4599
4600 return message;
4601 },
4602 loadingMore: function () {
4603 return 'Loading more results…';
4604 },
4605 maximumSelected: function (args) {
4606 var message = 'You can only select ' + args.maximum + ' item';
4607
4608 if (args.maximum != 1) {
4609 message += 's';
4610 }
4611
4612 return message;
4613 },
4614 noResults: function () {
4615 return 'No results found';
4616 },
4617 searching: function () {
4618 return 'Searching…';
4619 }
4620 };
4621});
4622
4623S2.define('select2/defaults',[
4624 'jquery',
4625 'require',
4626
4627 './results',
4628
4629 './selection/single',
4630 './selection/multiple',
4631 './selection/placeholder',
4632 './selection/allowClear',
4633 './selection/search',
4634 './selection/eventRelay',
4635
4636 './utils',
4637 './translation',
4638 './diacritics',
4639
4640 './data/select',
4641 './data/array',
4642 './data/ajax',
4643 './data/tags',
4644 './data/tokenizer',
4645 './data/minimumInputLength',
4646 './data/maximumInputLength',
4647 './data/maximumSelectionLength',
4648
4649 './dropdown',
4650 './dropdown/search',
4651 './dropdown/hidePlaceholder',
4652 './dropdown/infiniteScroll',
4653 './dropdown/attachBody',
4654 './dropdown/minimumResultsForSearch',
4655 './dropdown/selectOnClose',
4656 './dropdown/closeOnSelect',
4657
4658 './i18n/en'
4659], function ($, require,
4660
4661 ResultsList,
4662
4663 SingleSelection, MultipleSelection, Placeholder, AllowClear,
4664 SelectionSearch, EventRelay,
4665
4666 Utils, Translation, DIACRITICS,
4667
4668 SelectData, ArrayData, AjaxData, Tags, Tokenizer,
4669 MinimumInputLength, MaximumInputLength, MaximumSelectionLength,
4670
4671 Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll,
4672 AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect,
4673
4674 EnglishTranslation) {
4675 function Defaults () {
4676 this.reset();
4677 }
4678
4679 Defaults.prototype.apply = function (options) {
4680 options = $.extend(true, {}, this.defaults, options);
4681
4682 if (options.dataAdapter == null) {
4683 if (options.ajax != null) {
4684 options.dataAdapter = AjaxData;
4685 } else if (options.data != null) {
4686 options.dataAdapter = ArrayData;
4687 } else {
4688 options.dataAdapter = SelectData;
4689 }
4690
4691 if (options.minimumInputLength > 0) {
4692 options.dataAdapter = Utils.Decorate(
4693 options.dataAdapter,
4694 MinimumInputLength
4695 );
4696 }
4697
4698 if (options.maximumInputLength > 0) {
4699 options.dataAdapter = Utils.Decorate(
4700 options.dataAdapter,
4701 MaximumInputLength
4702 );
4703 }
4704
4705 if (options.maximumSelectionLength > 0) {
4706 options.dataAdapter = Utils.Decorate(
4707 options.dataAdapter,
4708 MaximumSelectionLength
4709 );
4710 }
4711
4712 if (options.tags) {
4713 options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags);
4714 }
4715
4716 if (options.tokenSeparators != null || options.tokenizer != null) {
4717 options.dataAdapter = Utils.Decorate(
4718 options.dataAdapter,
4719 Tokenizer
4720 );
4721 }
4722
4723 if (options.query != null) {
4724 var Query = require(options.amdBase + 'compat/query');
4725
4726 options.dataAdapter = Utils.Decorate(
4727 options.dataAdapter,
4728 Query
4729 );
4730 }
4731
4732 if (options.initSelection != null) {
4733 var InitSelection = require(options.amdBase + 'compat/initSelection');
4734
4735 options.dataAdapter = Utils.Decorate(
4736 options.dataAdapter,
4737 InitSelection
4738 );
4739 }
4740 }
4741
4742 if (options.resultsAdapter == null) {
4743 options.resultsAdapter = ResultsList;
4744
4745 if (options.ajax != null) {
4746 options.resultsAdapter = Utils.Decorate(
4747 options.resultsAdapter,
4748 InfiniteScroll
4749 );
4750 }
4751
4752 if (options.placeholder != null) {
4753 options.resultsAdapter = Utils.Decorate(
4754 options.resultsAdapter,
4755 HidePlaceholder
4756 );
4757 }
4758
4759 if (options.selectOnClose) {
4760 options.resultsAdapter = Utils.Decorate(
4761 options.resultsAdapter,
4762 SelectOnClose
4763 );
4764 }
4765 }
4766
4767 if (options.dropdownAdapter == null) {
4768 if (options.multiple) {
4769 options.dropdownAdapter = Dropdown;
4770 } else {
4771 var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch);
4772
4773 options.dropdownAdapter = SearchableDropdown;
4774 }
4775
4776 if (options.minimumResultsForSearch !== 0) {
4777 options.dropdownAdapter = Utils.Decorate(
4778 options.dropdownAdapter,
4779 MinimumResultsForSearch
4780 );
4781 }
4782
4783 if (options.closeOnSelect) {
4784 options.dropdownAdapter = Utils.Decorate(
4785 options.dropdownAdapter,
4786 CloseOnSelect
4787 );
4788 }
4789
4790 if (
4791 options.dropdownCssClass != null ||
4792 options.dropdownCss != null ||
4793 options.adaptDropdownCssClass != null
4794 ) {
4795 var DropdownCSS = require(options.amdBase + 'compat/dropdownCss');
4796
4797 options.dropdownAdapter = Utils.Decorate(
4798 options.dropdownAdapter,
4799 DropdownCSS
4800 );
4801 }
4802
4803 options.dropdownAdapter = Utils.Decorate(
4804 options.dropdownAdapter,
4805 AttachBody
4806 );
4807 }
4808
4809 if (options.selectionAdapter == null) {
4810 if (options.multiple) {
4811 options.selectionAdapter = MultipleSelection;
4812 } else {
4813 options.selectionAdapter = SingleSelection;
4814 }
4815
4816 // Add the placeholder mixin if a placeholder was specified
4817 if (options.placeholder != null) {
4818 options.selectionAdapter = Utils.Decorate(
4819 options.selectionAdapter,
4820 Placeholder
4821 );
4822 }
4823
4824 if (options.allowClear) {
4825 options.selectionAdapter = Utils.Decorate(
4826 options.selectionAdapter,
4827 AllowClear
4828 );
4829 }
4830
4831 if (options.multiple) {
4832 options.selectionAdapter = Utils.Decorate(
4833 options.selectionAdapter,
4834 SelectionSearch
4835 );
4836 }
4837
4838 if (
4839 options.containerCssClass != null ||
4840 options.containerCss != null ||
4841 options.adaptContainerCssClass != null
4842 ) {
4843 var ContainerCSS = require(options.amdBase + 'compat/containerCss');
4844
4845 options.selectionAdapter = Utils.Decorate(
4846 options.selectionAdapter,
4847 ContainerCSS
4848 );
4849 }
4850
4851 options.selectionAdapter = Utils.Decorate(
4852 options.selectionAdapter,
4853 EventRelay
4854 );
4855 }
4856
4857 if (typeof options.language === 'string') {
4858 // Check if the language is specified with a region
4859 if (options.language.indexOf('-') > 0) {
4860 // Extract the region information if it is included
4861 var languageParts = options.language.split('-');
4862 var baseLanguage = languageParts[0];
4863
4864 options.language = [options.language, baseLanguage];
4865 } else {
4866 options.language = [options.language];
4867 }
4868 }
4869
4870 if ($.isArray(options.language)) {
4871 var languages = new Translation();
4872 options.language.push('en');
4873
4874 var languageNames = options.language;
4875
4876 for (var l = 0; l < languageNames.length; l++) {
4877 var name = languageNames[l];
4878 var language = {};
4879
4880 try {
4881 // Try to load it with the original name
4882 language = Translation.loadPath(name);
4883 } catch (e) {
4884 try {
4885 // If we couldn't load it, check if it wasn't the full path
4886 name = this.defaults.amdLanguageBase + name;
4887 language = Translation.loadPath(name);
4888 } catch (ex) {
4889 // The translation could not be loaded at all. Sometimes this is
4890 // because of a configuration problem, other times this can be
4891 // because of how Select2 helps load all possible translation files.
4892 if (options.debug && window.console && console.warn) {
4893 console.warn(
4894 'Select2: The language file for "' + name + '" could not be ' +
4895 'automatically loaded. A fallback will be used instead.'
4896 );
4897 }
4898
4899 continue;
4900 }
4901 }
4902
4903 languages.extend(language);
4904 }
4905
4906 options.translations = languages;
4907 } else {
4908 var baseTranslation = Translation.loadPath(
4909 this.defaults.amdLanguageBase + 'en'
4910 );
4911 var customTranslation = new Translation(options.language);
4912
4913 customTranslation.extend(baseTranslation);
4914
4915 options.translations = customTranslation;
4916 }
4917
4918 return options;
4919 };
4920
4921 Defaults.prototype.reset = function () {
4922 function stripDiacritics (text) {
4923 // Used 'uni range + named function' from http://jsperf.com/diacritics/18
4924 function match(a) {
4925 return DIACRITICS[a] || a;
4926 }
4927
4928 return text.replace(/[^\u0000-\u007E]/g, match);
4929 }
4930
4931 function matcher (params, data) {
4932 // Always return the object if there is nothing to compare
4933 if ($.trim(params.term) === '') {
4934 return data;
4935 }
4936
4937 // Do a recursive check for options with children
4938 if (data.children && data.children.length > 0) {
4939 // Clone the data object if there are children
4940 // This is required as we modify the object to remove any non-matches
4941 var match = $.extend(true, {}, data);
4942
4943 // Check each child of the option
4944 for (var c = data.children.length - 1; c >= 0; c--) {
4945 var child = data.children[c];
4946
4947 var matches = matcher(params, child);
4948
4949 // If there wasn't a match, remove the object in the array
4950 if (matches == null) {
4951 match.children.splice(c, 1);
4952 }
4953 }
4954
4955 // If any children matched, return the new object
4956 if (match.children.length > 0) {
4957 return match;
4958 }
4959
4960 // If there were no matching children, check just the plain object
4961 return matcher(params, match);
4962 }
4963
4964 var original = stripDiacritics(data.text).toUpperCase();
4965 var term = stripDiacritics(params.term).toUpperCase();
4966
4967 // Check if the text contains the term
4968 if (original.indexOf(term) > -1) {
4969 return data;
4970 }
4971
4972 // If it doesn't contain the term, don't return anything
4973 return null;
4974 }
4975
4976 this.defaults = {
4977 amdBase: './',
4978 amdLanguageBase: './i18n/',
4979 closeOnSelect: true,
4980 debug: false,
4981 dropdownAutoWidth: false,
4982 escapeMarkup: Utils.escapeMarkup,
4983 language: EnglishTranslation,
4984 matcher: matcher,
4985 minimumInputLength: 0,
4986 maximumInputLength: 0,
4987 maximumSelectionLength: 0,
4988 minimumResultsForSearch: 0,
4989 selectOnClose: false,
4990 sorter: function (data) {
4991 return data;
4992 },
4993 templateResult: function (result) {
4994 return result.text;
4995 },
4996 templateSelection: function (selection) {
4997 return selection.text;
4998 },
4999 theme: 'default',
5000 width: 'resolve'
5001 };
5002 };
5003
5004 Defaults.prototype.set = function (key, value) {
5005 var camelKey = $.camelCase(key);
5006
5007 var data = {};
5008 data[camelKey] = value;
5009
5010 var convertedData = Utils._convertData(data);
5011
5012 $.extend(true, this.defaults, convertedData);
5013 };
5014
5015 var defaults = new Defaults();
5016
5017 return defaults;
5018});
5019
5020S2.define('select2/options',[
5021 'require',
5022 'jquery',
5023 './defaults',
5024 './utils'
5025], function (require, $, Defaults, Utils) {
5026 function Options (options, $element) {
5027 this.options = options;
5028
5029 if ($element != null) {
5030 this.fromElement($element);
5031 }
5032
5033 this.options = Defaults.apply(this.options);
5034
5035 if ($element && $element.is('input')) {
5036 var InputCompat = require(this.get('amdBase') + 'compat/inputData');
5037
5038 this.options.dataAdapter = Utils.Decorate(
5039 this.options.dataAdapter,
5040 InputCompat
5041 );
5042 }
5043 }
5044
5045 Options.prototype.fromElement = function ($e) {
5046 var excludedData = ['select2'];
5047
5048 if (this.options.multiple == null) {
5049 this.options.multiple = $e.prop('multiple');
5050 }
5051
5052 if (this.options.disabled == null) {
5053 this.options.disabled = $e.prop('disabled');
5054 }
5055
5056 if (this.options.language == null) {
5057 if ($e.prop('lang')) {
5058 this.options.language = $e.prop('lang').toLowerCase();
5059 } else if ($e.closest('[lang]').prop('lang')) {
5060 this.options.language = $e.closest('[lang]').prop('lang');
5061 }
5062 }
5063
5064 if (this.options.dir == null) {
5065 if ($e.prop('dir')) {
5066 this.options.dir = $e.prop('dir');
5067 } else if ($e.closest('[dir]').prop('dir')) {
5068 this.options.dir = $e.closest('[dir]').prop('dir');
5069 } else {
5070 this.options.dir = 'ltr';
5071 }
5072 }
5073
5074 $e.prop('disabled', this.options.disabled);
5075 $e.prop('multiple', this.options.multiple);
5076
5077 if (Utils.GetData($e[0], 'select2Tags')) {
5078 if (this.options.debug && window.console && console.warn) {
5079 console.warn(
5080 'Select2: The `data-select2-tags` attribute has been changed to ' +
5081 'use the `data-data` and `data-tags="true"` attributes and will be ' +
5082 'removed in future versions of Select2.'
5083 );
5084 }
5085
5086 Utils.StoreData($e[0], 'data', Utils.GetData($e[0], 'select2Tags'));
5087 Utils.StoreData($e[0], 'tags', true);
5088 }
5089
5090 if (Utils.GetData($e[0], 'ajaxUrl')) {
5091 if (this.options.debug && window.console && console.warn) {
5092 console.warn(
5093 'Select2: The `data-ajax-url` attribute has been changed to ' +
5094 '`data-ajax--url` and support for the old attribute will be removed' +
5095 ' in future versions of Select2.'
5096 );
5097 }
5098
5099 $e.attr('ajax--url', Utils.GetData($e[0], 'ajaxUrl'));
5100 Utils.StoreData($e[0], 'ajax-Url', Utils.GetData($e[0], 'ajaxUrl'));
5101
5102 }
5103
5104 var dataset = {};
5105
5106 // Prefer the element's `dataset` attribute if it exists
5107 // jQuery 1.x does not correctly handle data attributes with multiple dashes
5108 if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) {
5109 dataset = $.extend(true, {}, $e[0].dataset, Utils.GetData($e[0]));
5110 } else {
5111 dataset = Utils.GetData($e[0]);
5112 }
5113
5114 var data = $.extend(true, {}, dataset);
5115
5116 data = Utils._convertData(data);
5117
5118 for (var key in data) {
5119 if ($.inArray(key, excludedData) > -1) {
5120 continue;
5121 }
5122
5123 if ($.isPlainObject(this.options[key])) {
5124 $.extend(this.options[key], data[key]);
5125 } else {
5126 this.options[key] = data[key];
5127 }
5128 }
5129
5130 return this;
5131 };
5132
5133 Options.prototype.get = function (key) {
5134 return this.options[key];
5135 };
5136
5137 Options.prototype.set = function (key, val) {
5138 this.options[key] = val;
5139 };
5140
5141 return Options;
5142});
5143
5144S2.define('select2/core',[
5145 'jquery',
5146 './options',
5147 './utils',
5148 './keys'
5149], function ($, Options, Utils, KEYS) {
5150 var Select2 = function ($element, options) {
5151 if (Utils.GetData($element[0], 'select2') != null) {
5152 Utils.GetData($element[0], 'select2').destroy();
5153 }
5154
5155 this.$element = $element;
5156
5157 this.id = this._generateId($element);
5158
5159 options = options || {};
5160
5161 this.options = new Options(options, $element);
5162
5163 Select2.__super__.constructor.call(this);
5164
5165 // Set up the tabindex
5166
5167 var tabindex = $element.attr('tabindex') || 0;
5168 Utils.StoreData($element[0], 'old-tabindex', tabindex);
5169 $element.attr('tabindex', '-1');
5170
5171 // Set up containers and adapters
5172
5173 var DataAdapter = this.options.get('dataAdapter');
5174 this.dataAdapter = new DataAdapter($element, this.options);
5175
5176 var $container = this.render();
5177
5178 this._placeContainer($container);
5179
5180 var SelectionAdapter = this.options.get('selectionAdapter');
5181 this.selection = new SelectionAdapter($element, this.options);
5182 this.$selection = this.selection.render();
5183
5184 this.selection.position(this.$selection, $container);
5185
5186 var DropdownAdapter = this.options.get('dropdownAdapter');
5187 this.dropdown = new DropdownAdapter($element, this.options);
5188 this.$dropdown = this.dropdown.render();
5189
5190 this.dropdown.position(this.$dropdown, $container);
5191
5192 var ResultsAdapter = this.options.get('resultsAdapter');
5193 this.results = new ResultsAdapter($element, this.options, this.dataAdapter);
5194 this.$results = this.results.render();
5195
5196 this.results.position(this.$results, this.$dropdown);
5197
5198 // Bind events
5199
5200 var self = this;
5201
5202 // Bind the container to all of the adapters
5203 this._bindAdapters();
5204
5205 // Register any DOM event handlers
5206 this._registerDomEvents();
5207
5208 // Register any internal event handlers
5209 this._registerDataEvents();
5210 this._registerSelectionEvents();
5211 this._registerDropdownEvents();
5212 this._registerResultsEvents();
5213 this._registerEvents();
5214
5215 // Set the initial state
5216 this.dataAdapter.current(function (initialData) {
5217 self.trigger('selection:update', {
5218 data: initialData
5219 });
5220 });
5221
5222 // Hide the original select
5223 $element.addClass('select2-hidden-accessible');
5224 $element.attr('aria-hidden', 'true');
5225
5226 // Synchronize any monitored attributes
5227 this._syncAttributes();
5228
5229 Utils.StoreData($element[0], 'select2', this);
5230
5231 // Ensure backwards compatibility with $element.data('select2').
5232 $element.data('select2', this);
5233 };
5234
5235 Utils.Extend(Select2, Utils.Observable);
5236
5237 Select2.prototype._generateId = function ($element) {
5238 var id = '';
5239
5240 if ($element.attr('id') != null) {
5241 id = $element.attr('id');
5242 } else if ($element.attr('name') != null) {
5243 id = $element.attr('name') + '-' + Utils.generateChars(2);
5244 } else {
5245 id = Utils.generateChars(4);
5246 }
5247
5248 id = id.replace(/(:|\.|\[|\]|,)/g, '');
5249 id = 'select2-' + id;
5250
5251 return id;
5252 };
5253
5254 Select2.prototype._placeContainer = function ($container) {
5255 $container.insertAfter(this.$element);
5256
5257 var width = this._resolveWidth(this.$element, this.options.get('width'));
5258
5259 if (width != null) {
5260 $container.css('width', width);
5261 }
5262 };
5263
5264 Select2.prototype._resolveWidth = function ($element, method) {
5265 var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;
5266
5267 if (method == 'resolve') {
5268 var styleWidth = this._resolveWidth($element, 'style');
5269
5270 if (styleWidth != null) {
5271 return styleWidth;
5272 }
5273
5274 return this._resolveWidth($element, 'element');
5275 }
5276
5277 if (method == 'element') {
5278 var elementWidth = $element.outerWidth(false);
5279
5280 if (elementWidth <= 0) {
5281 return 'auto';
5282 }
5283
5284 return elementWidth + 'px';
5285 }
5286
5287 if (method == 'style') {
5288 var style = $element.attr('style');
5289
5290 if (typeof(style) !== 'string') {
5291 return null;
5292 }
5293
5294 var attrs = style.split(';');
5295
5296 for (var i = 0, l = attrs.length; i < l; i = i + 1) {
5297 var attr = attrs[i].replace(/\s/g, '');
5298 var matches = attr.match(WIDTH);
5299
5300 if (matches !== null && matches.length >= 1) {
5301 return matches[1];
5302 }
5303 }
5304
5305 return null;
5306 }
5307
5308 return method;
5309 };
5310
5311 Select2.prototype._bindAdapters = function () {
5312 this.dataAdapter.bind(this, this.$container);
5313 this.selection.bind(this, this.$container);
5314
5315 this.dropdown.bind(this, this.$container);
5316 this.results.bind(this, this.$container);
5317 };
5318
5319 Select2.prototype._registerDomEvents = function () {
5320 var self = this;
5321
5322 this.$element.on('change.select2', function () {
5323 self.dataAdapter.current(function (data) {
5324 self.trigger('selection:update', {
5325 data: data
5326 });
5327 });
5328 });
5329
5330 this.$element.on('focus.select2', function (evt) {
5331 self.trigger('focus', evt);
5332 });
5333
5334 this._syncA = Utils.bind(this._syncAttributes, this);
5335 this._syncS = Utils.bind(this._syncSubtree, this);
5336
5337 if (this.$element[0].attachEvent) {
5338 this.$element[0].attachEvent('onpropertychange', this._syncA);
5339 }
5340
5341 var observer = window.MutationObserver ||
5342 window.WebKitMutationObserver ||
5343 window.MozMutationObserver
5344 ;
5345
5346 if (observer != null) {
5347 this._observer = new observer(function (mutations) {
5348 $.each(mutations, self._syncA);
5349 $.each(mutations, self._syncS);
5350 });
5351 this._observer.observe(this.$element[0], {
5352 attributes: true,
5353 childList: true,
5354 subtree: false
5355 });
5356 } else if (this.$element[0].addEventListener) {
5357 this.$element[0].addEventListener(
5358 'DOMAttrModified',
5359 self._syncA,
5360 false
5361 );
5362 this.$element[0].addEventListener(
5363 'DOMNodeInserted',
5364 self._syncS,
5365 false
5366 );
5367 this.$element[0].addEventListener(
5368 'DOMNodeRemoved',
5369 self._syncS,
5370 false
5371 );
5372 }
5373 };
5374
5375 Select2.prototype._registerDataEvents = function () {
5376 var self = this;
5377
5378 this.dataAdapter.on('*', function (name, params) {
5379 self.trigger(name, params);
5380 });
5381 };
5382
5383 Select2.prototype._registerSelectionEvents = function () {
5384 var self = this;
5385 var nonRelayEvents = ['toggle', 'focus'];
5386
5387 this.selection.on('toggle', function () {
5388 self.toggleDropdown();
5389 });
5390
5391 this.selection.on('focus', function (params) {
5392 self.focus(params);
5393 });
5394
5395 this.selection.on('*', function (name, params) {
5396 if ($.inArray(name, nonRelayEvents) !== -1) {
5397 return;
5398 }
5399
5400 self.trigger(name, params);
5401 });
5402 };
5403
5404 Select2.prototype._registerDropdownEvents = function () {
5405 var self = this;
5406
5407 this.dropdown.on('*', function (name, params) {
5408 self.trigger(name, params);
5409 });
5410 };
5411
5412 Select2.prototype._registerResultsEvents = function () {
5413 var self = this;
5414
5415 this.results.on('*', function (name, params) {
5416 self.trigger(name, params);
5417 });
5418 };
5419
5420 Select2.prototype._registerEvents = function () {
5421 var self = this;
5422
5423 this.on('open', function () {
5424 self.$container.addClass('select2-container--open');
5425 });
5426
5427 this.on('close', function () {
5428 self.$container.removeClass('select2-container--open');
5429 });
5430
5431 this.on('enable', function () {
5432 self.$container.removeClass('select2-container--disabled');
5433 });
5434
5435 this.on('disable', function () {
5436 self.$container.addClass('select2-container--disabled');
5437 });
5438
5439 this.on('blur', function () {
5440 self.$container.removeClass('select2-container--focus');
5441 });
5442
5443 this.on('query', function (params) {
5444 if (!self.isOpen()) {
5445 self.trigger('open', {});
5446 }
5447
5448 this.dataAdapter.query(params, function (data) {
5449 self.trigger('results:all', {
5450 data: data,
5451 query: params
5452 });
5453 });
5454 });
5455
5456 this.on('query:append', function (params) {
5457 this.dataAdapter.query(params, function (data) {
5458 self.trigger('results:append', {
5459 data: data,
5460 query: params
5461 });
5462 });
5463 });
5464
5465 this.on('keypress', function (evt) {
5466 var key = evt.which;
5467
5468 if (self.isOpen()) {
5469 if (key === KEYS.ESC || key === KEYS.TAB ||
5470 (key === KEYS.UP && evt.altKey)) {
5471 self.close();
5472
5473 evt.preventDefault();
5474 } else if (key === KEYS.ENTER) {
5475 self.trigger('results:select', {});
5476
5477 evt.preventDefault();
5478 } else if ((key === KEYS.SPACE && evt.ctrlKey)) {
5479 self.trigger('results:toggle', {});
5480
5481 evt.preventDefault();
5482 } else if (key === KEYS.UP) {
5483 self.trigger('results:previous', {});
5484
5485 evt.preventDefault();
5486 } else if (key === KEYS.DOWN) {
5487 self.trigger('results:next', {});
5488
5489 evt.preventDefault();
5490 }
5491 } else {
5492 if (key === KEYS.ENTER || key === KEYS.SPACE ||
5493 (key === KEYS.DOWN && evt.altKey)) {
5494 self.open();
5495
5496 evt.preventDefault();
5497 }
5498 }
5499 });
5500 };
5501
5502 Select2.prototype._syncAttributes = function () {
5503 this.options.set('disabled', this.$element.prop('disabled'));
5504
5505 if (this.options.get('disabled')) {
5506 if (this.isOpen()) {
5507 this.close();
5508 }
5509
5510 this.trigger('disable', {});
5511 } else {
5512 this.trigger('enable', {});
5513 }
5514 };
5515
5516 Select2.prototype._syncSubtree = function (evt, mutations) {
5517 var changed = false;
5518 var self = this;
5519
5520 // Ignore any mutation events raised for elements that aren't options or
5521 // optgroups. This handles the case when the select element is destroyed
5522 if (
5523 evt && evt.target && (
5524 evt.target.nodeName !== 'OPTION' && evt.target.nodeName !== 'OPTGROUP'
5525 )
5526 ) {
5527 return;
5528 }
5529
5530 if (!mutations) {
5531 // If mutation events aren't supported, then we can only assume that the
5532 // change affected the selections
5533 changed = true;
5534 } else if (mutations.addedNodes && mutations.addedNodes.length > 0) {
5535 for (var n = 0; n < mutations.addedNodes.length; n++) {
5536 var node = mutations.addedNodes[n];
5537
5538 if (node.selected) {
5539 changed = true;
5540 }
5541 }
5542 } else if (mutations.removedNodes && mutations.removedNodes.length > 0) {
5543 changed = true;
5544 }
5545
5546 // Only re-pull the data if we think there is a change
5547 if (changed) {
5548 this.dataAdapter.current(function (currentData) {
5549 self.trigger('selection:update', {
5550 data: currentData
5551 });
5552 });
5553 }
5554 };
5555
5556 /**
5557 * Override the trigger method to automatically trigger pre-events when
5558 * there are events that can be prevented.
5559 */
5560 Select2.prototype.trigger = function (name, args) {
5561 var actualTrigger = Select2.__super__.trigger;
5562 var preTriggerMap = {
5563 'open': 'opening',
5564 'close': 'closing',
5565 'select': 'selecting',
5566 'unselect': 'unselecting',
5567 'clear': 'clearing'
5568 };
5569
5570 if (args === undefined) {
5571 args = {};
5572 }
5573
5574 if (name in preTriggerMap) {
5575 var preTriggerName = preTriggerMap[name];
5576 var preTriggerArgs = {
5577 prevented: false,
5578 name: name,
5579 args: args
5580 };
5581
5582 actualTrigger.call(this, preTriggerName, preTriggerArgs);
5583
5584 if (preTriggerArgs.prevented) {
5585 args.prevented = true;
5586
5587 return;
5588 }
5589 }
5590
5591 actualTrigger.call(this, name, args);
5592 };
5593
5594 Select2.prototype.toggleDropdown = function () {
5595 if (this.options.get('disabled')) {
5596 return;
5597 }
5598
5599 if (this.isOpen()) {
5600 this.close();
5601 } else {
5602 this.open();
5603 }
5604 };
5605
5606 Select2.prototype.open = function () {
5607 if (this.isOpen()) {
5608 return;
5609 }
5610
5611 this.trigger('query', {});
5612 };
5613
5614 Select2.prototype.close = function () {
5615 if (!this.isOpen()) {
5616 return;
5617 }
5618
5619 this.trigger('close', {});
5620 };
5621
5622 Select2.prototype.isOpen = function () {
5623 return this.$container.hasClass('select2-container--open');
5624 };
5625
5626 Select2.prototype.hasFocus = function () {
5627 return this.$container.hasClass('select2-container--focus');
5628 };
5629
5630 Select2.prototype.focus = function (data) {
5631 // No need to re-trigger focus events if we are already focused
5632 if (this.hasFocus()) {
5633 return;
5634 }
5635
5636 this.$container.addClass('select2-container--focus');
5637 this.trigger('focus', {});
5638 };
5639
5640 Select2.prototype.enable = function (args) {
5641 if (this.options.get('debug') && window.console && console.warn) {
5642 console.warn(
5643 'Select2: The `select2("enable")` method has been deprecated and will' +
5644 ' be removed in later Select2 versions. Use $element.prop("disabled")' +
5645 ' instead.'
5646 );
5647 }
5648
5649 if (args == null || args.length === 0) {
5650 args = [true];
5651 }
5652
5653 var disabled = !args[0];
5654
5655 this.$element.prop('disabled', disabled);
5656 };
5657
5658 Select2.prototype.data = function () {
5659 if (this.options.get('debug') &&
5660 arguments.length > 0 && window.console && console.warn) {
5661 console.warn(
5662 'Select2: Data can no longer be set using `select2("data")`. You ' +
5663 'should consider setting the value instead using `$element.val()`.'
5664 );
5665 }
5666
5667 var data = [];
5668
5669 this.dataAdapter.current(function (currentData) {
5670 data = currentData;
5671 });
5672
5673 return data;
5674 };
5675
5676 Select2.prototype.val = function (args) {
5677 if (this.options.get('debug') && window.console && console.warn) {
5678 console.warn(
5679 'Select2: The `select2("val")` method has been deprecated and will be' +
5680 ' removed in later Select2 versions. Use $element.val() instead.'
5681 );
5682 }
5683
5684 if (args == null || args.length === 0) {
5685 return this.$element.val();
5686 }
5687
5688 var newVal = args[0];
5689
5690 if ($.isArray(newVal)) {
5691 newVal = $.map(newVal, function (obj) {
5692 return obj.toString();
5693 });
5694 }
5695
5696 this.$element.val(newVal).trigger('change');
5697 };
5698
5699 Select2.prototype.destroy = function () {
5700 this.$container.remove();
5701
5702 if (this.$element[0].detachEvent) {
5703 this.$element[0].detachEvent('onpropertychange', this._syncA);
5704 }
5705
5706 if (this._observer != null) {
5707 this._observer.disconnect();
5708 this._observer = null;
5709 } else if (this.$element[0].removeEventListener) {
5710 this.$element[0]
5711 .removeEventListener('DOMAttrModified', this._syncA, false);
5712 this.$element[0]
5713 .removeEventListener('DOMNodeInserted', this._syncS, false);
5714 this.$element[0]
5715 .removeEventListener('DOMNodeRemoved', this._syncS, false);
5716 }
5717
5718 this._syncA = null;
5719 this._syncS = null;
5720
5721 this.$element.off('.select2');
5722 this.$element.attr('tabindex',
5723 Utils.GetData(this.$element[0], 'old-tabindex'));
5724
5725 this.$element.removeClass('select2-hidden-accessible');
5726 this.$element.attr('aria-hidden', 'false');
5727 Utils.RemoveData(this.$element[0]);
5728 this.$element.removeData('select2');
5729
5730 this.dataAdapter.destroy();
5731 this.selection.destroy();
5732 this.dropdown.destroy();
5733 this.results.destroy();
5734
5735 this.dataAdapter = null;
5736 this.selection = null;
5737 this.dropdown = null;
5738 this.results = null;
5739 };
5740
5741 Select2.prototype.render = function () {
5742 var $container = $(
5743 '<span class="select2 select2-container">' +
5744 '<span class="selection"></span>' +
5745 '<span class="dropdown-wrapper" aria-hidden="true"></span>' +
5746 '</span>'
5747 );
5748
5749 $container.attr('dir', this.options.get('dir'));
5750
5751 this.$container = $container;
5752
5753 this.$container.addClass('select2-container--' + this.options.get('theme'));
5754
5755 Utils.StoreData($container[0], 'element', this.$element);
5756
5757 return $container;
5758 };
5759
5760 return Select2;
5761});
5762
5763S2.define('jquery-mousewheel',[
5764 'jquery'
5765], function ($) {
5766 // Used to shim jQuery.mousewheel for non-full builds.
5767 return $;
5768});
5769
5770S2.define('jquery.select2',[
5771 'jquery',
5772 'jquery-mousewheel',
5773
5774 './select2/core',
5775 './select2/defaults',
5776 './select2/utils'
5777], function ($, _, Select2, Defaults, Utils) {
5778 if ($.fn.select2 == null) {
5779 // All methods that should return the element
5780 var thisMethods = ['open', 'close', 'destroy'];
5781
5782 $.fn.select2 = function (options) {
5783 options = options || {};
5784
5785 if (typeof options === 'object') {
5786 this.each(function () {
5787 var instanceOptions = $.extend(true, {}, options);
5788
5789 var instance = new Select2($(this), instanceOptions);
5790 });
5791
5792 return this;
5793 } else if (typeof options === 'string') {
5794 var ret;
5795 var args = Array.prototype.slice.call(arguments, 1);
5796
5797 this.each(function () {
5798 var instance = Utils.GetData(this, 'select2');
5799
5800 if (instance == null && window.console && console.error) {
5801 console.error(
5802 'The select2(\'' + options + '\') method was called on an ' +
5803 'element that is not using Select2.'
5804 );
5805 }
5806
5807 ret = instance[options].apply(instance, args);
5808 });
5809
5810 // Check if we should be returning `this`
5811 if ($.inArray(options, thisMethods) > -1) {
5812 return this;
5813 }
5814
5815 return ret;
5816 } else {
5817 throw new Error('Invalid arguments for Select2: ' + options);
5818 }
5819 };
5820 }
5821
5822 if ($.fn.select2.defaults == null) {
5823 $.fn.select2.defaults = Defaults;
5824 }
5825
5826 return Select2;
5827});
5828
5829 // Return the AMD loader configuration so it can be used outside of this file
5830 return {
5831 define: S2.define,
5832 require: S2.require
5833 };
5834}());
5835
5836 // Autoload the jQuery bindings
5837 // We know that all of the modules exist above this, so we're safe
5838 var select2 = S2.require('jquery.select2');
5839
5840 // Hold the AMD module references on the jQuery function that was just loaded
5841 // This allows Select2 to use the internal loader outside of this file, such
5842 // as in the language files.
5843 jQuery.fn.select2.amd = S2;
5844
5845 // Return the Select2 instance for anyone who is importing it.
5846 return select2;
5847}));
Note: See TracBrowser for help on using the repository browser.