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