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