select2-rails 4.0.3 → 4.0.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +8 -2
  3. data/lib/select2-rails/version.rb +1 -1
  4. data/select2-rails.gemspec +1 -1
  5. data/vendor/assets/javascripts/select2-full.js +670 -286
  6. data/vendor/assets/javascripts/select2.js +663 -280
  7. data/vendor/assets/javascripts/select2_locale_af.js +3 -0
  8. data/vendor/assets/javascripts/select2_locale_ar.js +2 -2
  9. data/vendor/assets/javascripts/select2_locale_az.js +2 -2
  10. data/vendor/assets/javascripts/select2_locale_bg.js +2 -2
  11. data/vendor/assets/javascripts/select2_locale_bn.js +3 -0
  12. data/vendor/assets/javascripts/select2_locale_bs.js +3 -0
  13. data/vendor/assets/javascripts/select2_locale_ca.js +2 -2
  14. data/vendor/assets/javascripts/select2_locale_cs.js +2 -2
  15. data/vendor/assets/javascripts/select2_locale_da.js +2 -2
  16. data/vendor/assets/javascripts/select2_locale_de.js +2 -2
  17. data/vendor/assets/javascripts/select2_locale_dsb.js +3 -0
  18. data/vendor/assets/javascripts/select2_locale_el.js +2 -2
  19. data/vendor/assets/javascripts/select2_locale_en.js +2 -2
  20. data/vendor/assets/javascripts/select2_locale_es.js +2 -2
  21. data/vendor/assets/javascripts/select2_locale_et.js +2 -2
  22. data/vendor/assets/javascripts/select2_locale_eu.js +2 -2
  23. data/vendor/assets/javascripts/select2_locale_fa.js +2 -2
  24. data/vendor/assets/javascripts/select2_locale_fi.js +2 -2
  25. data/vendor/assets/javascripts/select2_locale_fr.js +2 -2
  26. data/vendor/assets/javascripts/select2_locale_gl.js +2 -2
  27. data/vendor/assets/javascripts/select2_locale_he.js +2 -2
  28. data/vendor/assets/javascripts/select2_locale_hi.js +2 -2
  29. data/vendor/assets/javascripts/select2_locale_hr.js +2 -2
  30. data/vendor/assets/javascripts/select2_locale_hsb.js +3 -0
  31. data/vendor/assets/javascripts/select2_locale_hu.js +2 -2
  32. data/vendor/assets/javascripts/select2_locale_hy.js +3 -0
  33. data/vendor/assets/javascripts/select2_locale_id.js +2 -2
  34. data/vendor/assets/javascripts/select2_locale_is.js +2 -2
  35. data/vendor/assets/javascripts/select2_locale_it.js +2 -2
  36. data/vendor/assets/javascripts/select2_locale_ja.js +2 -2
  37. data/vendor/assets/javascripts/select2_locale_ka.js +3 -0
  38. data/vendor/assets/javascripts/select2_locale_km.js +2 -2
  39. data/vendor/assets/javascripts/select2_locale_ko.js +2 -2
  40. data/vendor/assets/javascripts/select2_locale_lt.js +2 -2
  41. data/vendor/assets/javascripts/select2_locale_lv.js +2 -2
  42. data/vendor/assets/javascripts/select2_locale_mk.js +2 -2
  43. data/vendor/assets/javascripts/select2_locale_ms.js +2 -2
  44. data/vendor/assets/javascripts/select2_locale_nb.js +2 -2
  45. data/vendor/assets/javascripts/select2_locale_ne.js +3 -0
  46. data/vendor/assets/javascripts/select2_locale_nl.js +2 -2
  47. data/vendor/assets/javascripts/select2_locale_pl.js +2 -2
  48. data/vendor/assets/javascripts/select2_locale_ps.js +3 -0
  49. data/vendor/assets/javascripts/select2_locale_pt-BR.js +2 -2
  50. data/vendor/assets/javascripts/select2_locale_pt.js +2 -2
  51. data/vendor/assets/javascripts/select2_locale_ro.js +2 -2
  52. data/vendor/assets/javascripts/select2_locale_ru.js +2 -2
  53. data/vendor/assets/javascripts/select2_locale_sk.js +2 -2
  54. data/vendor/assets/javascripts/select2_locale_sl.js +3 -0
  55. data/vendor/assets/javascripts/select2_locale_sq.js +3 -0
  56. data/vendor/assets/javascripts/select2_locale_sr-Cyrl.js +2 -2
  57. data/vendor/assets/javascripts/select2_locale_sr.js +2 -2
  58. data/vendor/assets/javascripts/select2_locale_sv.js +2 -2
  59. data/vendor/assets/javascripts/select2_locale_th.js +2 -2
  60. data/vendor/assets/javascripts/select2_locale_tk.js +3 -0
  61. data/vendor/assets/javascripts/select2_locale_tr.js +2 -2
  62. data/vendor/assets/javascripts/select2_locale_uk.js +2 -2
  63. data/vendor/assets/javascripts/select2_locale_vi.js +2 -2
  64. data/vendor/assets/javascripts/select2_locale_zh-CN.js +2 -2
  65. data/vendor/assets/javascripts/select2_locale_zh-TW.js +2 -2
  66. data/vendor/assets/stylesheets/select2.css +8 -11
  67. metadata +18 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d128112240be89bfb1d73d73f957f94d983edb61
4
- data.tar.gz: dfdda950dd61f0fa042db94f1ab74914e7fc5b29
2
+ SHA256:
3
+ metadata.gz: c74819abcc9a780c3221badc68cc4d2bc999e016c8d3a412c6c197545451126c
4
+ data.tar.gz: 1b22502c83b69ebbe348018e3e069aa640f160fd0e99c385c6d18064bd662ffa
5
5
  SHA512:
6
- metadata.gz: ee533ad76c7a28de7f3365beba124c8d1810b7be557a2ffc5ac2474bbf262f1dead42b3f36cbeb5b09c597873f4def72e6a17a6b50cf8ebfb13244ebed0669ef
7
- data.tar.gz: 76db3585d883fce0d6d0047ce8aa32b48766fb4f0dea49dd21de862f3759939f054ec10c06dcfee7fe2ce1b1eda3188c2e24ebd26739be7088f0528a8598ab4d
6
+ metadata.gz: 044aca6303e13dee71f8e2532db1369fd757fb58cda8945e9f7d20a1244205a75c8a72e4fed02a4e768ff7379a9a0579ed0735baa9fb421c11a5c2722481ed4b
7
+ data.tar.gz: 2fc02500109a54e3d47fddccfe6d477741e4f3e9bb6b2a937cffc658c4eec2777940ba3ee66bc436645eb7bcb6d6e11e580460c15abf2b982bc86c9575bdbcce
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- #Select2 for rails asset pipeline
1
+ # Select2 for rails asset pipeline
2
2
 
3
3
  [Select2](https://github.com/select2/select2) is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.
4
4
 
@@ -48,9 +48,15 @@ Add the following to your `app/assets/javascripts/application.js`:
48
48
 
49
49
  //= require select2_locale_"any possible language"
50
50
 
51
+ To apply the language, pass whatever language you'd like to use to the [`language`](https://select2.github.io/examples.html#language) option when initializing Select2:
52
+
53
+ $( "#dropdown" ).select2({
54
+ language: "zh-TW"
55
+ });
56
+
51
57
  Possible languages:
52
58
 
53
- ar, az, bg, ca, cs, da, de, el, en, es, et, eu, fa, fi, fr, gl, he, hi, hr, hu, id, is, it, ja, km, ko, lt, lv, mk, ms, nb, nl, pl, pt, pt-BR, ro, ru, sk, sr, sr-Cyrl, sv, th, tr, uk, vi, zh-CN, zh-TW
59
+ af, ar, az, bg, bn, bs, ca, cs, da, de, dsb, el, en, es, et, eu, fa, fi, fr, gl, he, hi, hr, hsb, hu, hy, id, is, it, ja, ka, km, ko, lt, lv, mk, ms, nb, ne, nl, pl, ps, pt, pt-BR, ro, ru, sk, sl, sq, sr, sr-Cyrl, sv, th, tk, tr, uk, vi, zh-CN, zh-TW
54
60
 
55
61
  ## Example
56
62
  Code [here](https://github.com/argerim/select_2_example)
@@ -1,5 +1,5 @@
1
1
  module Select2
2
2
  module Rails
3
- VERSION = '4.0.3'
3
+ VERSION = '4.0.13'
4
4
  end
5
5
  end
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
15
15
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
16
  s.require_paths = ["lib"]
17
17
 
18
- s.add_dependency "thor", "~> 0.14"
18
+ s.add_development_dependency "thor", "~> 1"
19
19
  s.add_development_dependency "bundler", "~> 1.0"
20
20
  s.add_development_dependency "rails", ">= 3.0"
21
21
  s.add_development_dependency "httpclient", "~> 2.2"
@@ -1,27 +1,41 @@
1
1
  /*!
2
- * Select2 4.0.3
2
+ * Select2 4.0.13
3
3
  * https://select2.github.io
4
4
  *
5
5
  * Released under the MIT license
6
6
  * https://github.com/select2/select2/blob/master/LICENSE.md
7
7
  */
8
- (function (factory) {
8
+ ;(function (factory) {
9
9
  if (typeof define === 'function' && define.amd) {
10
10
  // AMD. Register as an anonymous module.
11
11
  define(['jquery'], factory);
12
- } else if (typeof exports === 'object') {
12
+ } else if (typeof module === 'object' && module.exports) {
13
13
  // Node/CommonJS
14
- factory(require('jquery'));
14
+ module.exports = function (root, jQuery) {
15
+ if (jQuery === undefined) {
16
+ // require('jQuery') returns a factory that requires window to
17
+ // build a jQuery instance, we normalize how we use modules
18
+ // that require this pattern but the window provided is a noop
19
+ // if it's defined (how jquery works)
20
+ if (typeof window !== 'undefined') {
21
+ jQuery = require('jquery');
22
+ }
23
+ else {
24
+ jQuery = require('jquery')(root);
25
+ }
26
+ }
27
+ factory(jQuery);
28
+ return jQuery;
29
+ };
15
30
  } else {
16
31
  // Browser globals
17
32
  factory(jQuery);
18
33
  }
19
- }(function (jQuery) {
34
+ } (function (jQuery) {
20
35
  // This is needed so we can catch the AMD loader configuration and use it
21
36
  // The inner file should be wrapped (by `banner.start.js`) in a function that
22
37
  // returns the AMD loader references.
23
- var S2 =
24
- (function () {
38
+ var S2 =(function () {
25
39
  // Restore the Select2 AMD loader so it can be used
26
40
  // Needed mostly in the language files, where the loader is not inserted
27
41
  if (jQuery && jQuery.fn && jQuery.fn.select2 && jQuery.fn.select2.amd) {
@@ -30,13 +44,11 @@
30
44
  var S2;(function () { if (!S2 || !S2.requirejs) {
31
45
  if (!S2) { S2 = {}; } else { require = S2; }
32
46
  /**
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
47
+ * @license almond 0.3.3 Copyright jQuery Foundation and other contributors.
48
+ * Released under MIT license, http://github.com/requirejs/almond/LICENSE
36
49
  */
37
50
  //Going sloppy to avoid 'use strict' string cost, but strict practices should
38
51
  //be followed.
39
- /*jslint sloppy: true */
40
52
  /*global setTimeout: false */
41
53
 
42
54
  var requirejs, require, define;
@@ -64,60 +76,58 @@ var requirejs, require, define;
64
76
  */
65
77
  function normalize(name, baseName) {
66
78
  var nameParts, nameSegment, mapValue, foundMap, lastIndex,
67
- foundI, foundStarMap, starI, i, j, part,
79
+ foundI, foundStarMap, starI, i, j, part, normalizedBaseParts,
68
80
  baseParts = baseName && baseName.split("/"),
69
81
  map = config.map,
70
82
  starMap = (map && map['*']) || {};
71
83
 
72
84
  //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
+ if (name) {
86
+ name = name.split('/');
87
+ lastIndex = name.length - 1;
88
+
89
+ // If wanting node ID compatibility, strip .js from end
90
+ // of IDs. Have to do this here, and not in nameToUrl
91
+ // because node allows either .js or non .js to map
92
+ // to same file.
93
+ if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
94
+ name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
95
+ }
85
96
 
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
- }
97
+ // Starts with a '.' so need the baseName
98
+ if (name[0].charAt(0) === '.' && baseParts) {
99
+ //Convert baseName to array, and lop off the last part,
100
+ //so that . matches that 'directory' and not name of the baseName's
101
+ //module. For instance, baseName of 'one/two/three', maps to
102
+ //'one/two/three.js', but we want the directory, 'one/two' for
103
+ //this normalization.
104
+ normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
105
+ name = normalizedBaseParts.concat(name);
106
+ }
107
+
108
+ //start trimDots
109
+ for (i = 0; i < name.length; i++) {
110
+ part = name[i];
111
+ if (part === '.') {
112
+ name.splice(i, 1);
113
+ i -= 1;
114
+ } else if (part === '..') {
115
+ // If at the start, or previous value is still ..,
116
+ // keep them so that when converted to a path it may
117
+ // still work when converted to a path, even though
118
+ // as an ID it is less than ideal. In larger point
119
+ // releases, may be better to just kick out an error.
120
+ if (i === 0 || (i === 1 && name[2] === '..') || name[i - 1] === '..') {
121
+ continue;
122
+ } else if (i > 0) {
123
+ name.splice(i - 1, 2);
124
+ i -= 2;
111
125
  }
112
126
  }
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
127
  }
128
+ //end trimDots
129
+
130
+ name = name.join('/');
121
131
  }
122
132
 
123
133
  //Apply map config if available.
@@ -230,32 +240,39 @@ var requirejs, require, define;
230
240
  return [prefix, name];
231
241
  }
232
242
 
243
+ //Creates a parts array for a relName where first part is plugin ID,
244
+ //second part is resource ID. Assumes relName has already been normalized.
245
+ function makeRelParts(relName) {
246
+ return relName ? splitPrefix(relName) : [];
247
+ }
248
+
233
249
  /**
234
250
  * Makes a name map, normalizing the name, and using a plugin
235
251
  * for normalization if necessary. Grabs a ref to plugin
236
252
  * too, as an optimization.
237
253
  */
238
- makeMap = function (name, relName) {
254
+ makeMap = function (name, relParts) {
239
255
  var plugin,
240
256
  parts = splitPrefix(name),
241
- prefix = parts[0];
257
+ prefix = parts[0],
258
+ relResourceName = relParts[1];
242
259
 
243
260
  name = parts[1];
244
261
 
245
262
  if (prefix) {
246
- prefix = normalize(prefix, relName);
263
+ prefix = normalize(prefix, relResourceName);
247
264
  plugin = callDep(prefix);
248
265
  }
249
266
 
250
267
  //Normalize according
251
268
  if (prefix) {
252
269
  if (plugin && plugin.normalize) {
253
- name = plugin.normalize(name, makeNormalize(relName));
270
+ name = plugin.normalize(name, makeNormalize(relResourceName));
254
271
  } else {
255
- name = normalize(name, relName);
272
+ name = normalize(name, relResourceName);
256
273
  }
257
274
  } else {
258
- name = normalize(name, relName);
275
+ name = normalize(name, relResourceName);
259
276
  parts = splitPrefix(name);
260
277
  prefix = parts[0];
261
278
  name = parts[1];
@@ -302,13 +319,14 @@ var requirejs, require, define;
302
319
  };
303
320
 
304
321
  main = function (name, deps, callback, relName) {
305
- var cjsModule, depName, ret, map, i,
322
+ var cjsModule, depName, ret, map, i, relParts,
306
323
  args = [],
307
324
  callbackType = typeof callback,
308
325
  usingExports;
309
326
 
310
327
  //Use name if no relName
311
328
  relName = relName || name;
329
+ relParts = makeRelParts(relName);
312
330
 
313
331
  //Call the callback to define the module, if necessary.
314
332
  if (callbackType === 'undefined' || callbackType === 'function') {
@@ -317,7 +335,7 @@ var requirejs, require, define;
317
335
  //Default to [require, exports, module] if no deps
318
336
  deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
319
337
  for (i = 0; i < deps.length; i += 1) {
320
- map = makeMap(deps[i], relName);
338
+ map = makeMap(deps[i], relParts);
321
339
  depName = map.f;
322
340
 
323
341
  //Fast path CommonJS standard dependencies.
@@ -373,7 +391,7 @@ var requirejs, require, define;
373
391
  //deps arg is the module name, and second arg (if passed)
374
392
  //is just the relName.
375
393
  //Normalize module name, if it contains . or ..
376
- return callDep(makeMap(deps, callback).f);
394
+ return callDep(makeMap(deps, makeRelParts(callback)).f);
377
395
  } else if (!deps.splice) {
378
396
  //deps is a config object, not an array.
379
397
  config = deps;
@@ -556,10 +574,10 @@ S2.define('select2/utils',[
556
574
  DecoratedClass.prototype = new ctr();
557
575
 
558
576
  for (var m = 0; m < superMethods.length; m++) {
559
- var superMethod = superMethods[m];
577
+ var superMethod = superMethods[m];
560
578
 
561
- DecoratedClass.prototype[superMethod] =
562
- SuperClass.prototype[superMethod];
579
+ DecoratedClass.prototype[superMethod] =
580
+ SuperClass.prototype[superMethod];
563
581
  }
564
582
 
565
583
  var calledMethod = function (methodName) {
@@ -754,6 +772,70 @@ S2.define('select2/utils',[
754
772
  $element.append($nodes);
755
773
  };
756
774
 
775
+ // Cache objects in Utils.__cache instead of $.data (see #4346)
776
+ Utils.__cache = {};
777
+
778
+ var id = 0;
779
+ Utils.GetUniqueElementId = function (element) {
780
+ // Get a unique element Id. If element has no id,
781
+ // creates a new unique number, stores it in the id
782
+ // attribute and returns the new id.
783
+ // If an id already exists, it simply returns it.
784
+
785
+ var select2Id = element.getAttribute('data-select2-id');
786
+ if (select2Id == null) {
787
+ // If element has id, use it.
788
+ if (element.id) {
789
+ select2Id = element.id;
790
+ element.setAttribute('data-select2-id', select2Id);
791
+ } else {
792
+ element.setAttribute('data-select2-id', ++id);
793
+ select2Id = id.toString();
794
+ }
795
+ }
796
+ return select2Id;
797
+ };
798
+
799
+ Utils.StoreData = function (element, name, value) {
800
+ // Stores an item in the cache for a specified element.
801
+ // name is the cache key.
802
+ var id = Utils.GetUniqueElementId(element);
803
+ if (!Utils.__cache[id]) {
804
+ Utils.__cache[id] = {};
805
+ }
806
+
807
+ Utils.__cache[id][name] = value;
808
+ };
809
+
810
+ Utils.GetData = function (element, name) {
811
+ // Retrieves a value from the cache by its key (name)
812
+ // name is optional. If no name specified, return
813
+ // all cache items for the specified element.
814
+ // and for a specified element.
815
+ var id = Utils.GetUniqueElementId(element);
816
+ if (name) {
817
+ if (Utils.__cache[id]) {
818
+ if (Utils.__cache[id][name] != null) {
819
+ return Utils.__cache[id][name];
820
+ }
821
+ return $(element).data(name); // Fallback to HTML5 data attribs.
822
+ }
823
+ return $(element).data(name); // Fallback to HTML5 data attribs.
824
+ } else {
825
+ return Utils.__cache[id];
826
+ }
827
+ };
828
+
829
+ Utils.RemoveData = function (element) {
830
+ // Removes all cached items for a specified element.
831
+ var id = Utils.GetUniqueElementId(element);
832
+ if (Utils.__cache[id] != null) {
833
+ delete Utils.__cache[id];
834
+ }
835
+
836
+ element.removeAttribute('data-select2-id');
837
+ };
838
+
757
839
  return Utils;
758
840
  });
759
841
 
@@ -773,7 +855,7 @@ S2.define('select2/results',[
773
855
 
774
856
  Results.prototype.render = function () {
775
857
  var $results = $(
776
- '<ul class="select2-results__options" role="tree"></ul>'
858
+ '<ul class="select2-results__options" role="listbox"></ul>'
777
859
  );
778
860
 
779
861
  if (this.options.get('multiple')) {
@@ -796,7 +878,7 @@ S2.define('select2/results',[
796
878
  this.hideLoading();
797
879
 
798
880
  var $message = $(
799
- '<li role="treeitem" aria-live="assertive"' +
881
+ '<li role="alert" aria-live="assertive"' +
800
882
  ' class="select2-results__option"></li>'
801
883
  );
802
884
 
@@ -889,7 +971,7 @@ S2.define('select2/results',[
889
971
  $options.each(function () {
890
972
  var $option = $(this);
891
973
 
892
- var item = $.data(this, 'data');
974
+ var item = Utils.GetData(this, 'data');
893
975
 
894
976
  // id needs to be converted to a string when comparing
895
977
  var id = '' + item.id;
@@ -930,11 +1012,16 @@ S2.define('select2/results',[
930
1012
  option.className = 'select2-results__option';
931
1013
 
932
1014
  var attrs = {
933
- 'role': 'treeitem',
1015
+ 'role': 'option',
934
1016
  'aria-selected': 'false'
935
1017
  };
936
1018
 
937
- if (data.disabled) {
1019
+ var matches = window.Element.prototype.matches ||
1020
+ window.Element.prototype.msMatchesSelector ||
1021
+ window.Element.prototype.webkitMatchesSelector;
1022
+
1023
+ if ((data.element != null && matches.call(data.element, ':disabled')) ||
1024
+ (data.element == null && data.disabled)) {
938
1025
  delete attrs['aria-selected'];
939
1026
  attrs['aria-disabled'] = 'true';
940
1027
  }
@@ -994,7 +1081,7 @@ S2.define('select2/results',[
994
1081
  this.template(data, option);
995
1082
  }
996
1083
 
997
- $.data(option, 'data', data);
1084
+ Utils.StoreData(option, 'data', data);
998
1085
 
999
1086
  return option;
1000
1087
  };
@@ -1035,7 +1122,10 @@ S2.define('select2/results',[
1035
1122
  }
1036
1123
 
1037
1124
  self.setClasses();
1038
- self.highlightFirstItem();
1125
+
1126
+ if (self.options.get('scrollAfterSelect')) {
1127
+ self.highlightFirstItem();
1128
+ }
1039
1129
  });
1040
1130
 
1041
1131
  container.on('unselect', function () {
@@ -1044,7 +1134,10 @@ S2.define('select2/results',[
1044
1134
  }
1045
1135
 
1046
1136
  self.setClasses();
1047
- self.highlightFirstItem();
1137
+
1138
+ if (self.options.get('scrollAfterSelect')) {
1139
+ self.highlightFirstItem();
1140
+ }
1048
1141
  });
1049
1142
 
1050
1143
  container.on('open', function () {
@@ -1080,7 +1173,7 @@ S2.define('select2/results',[
1080
1173
  return;
1081
1174
  }
1082
1175
 
1083
- var data = $highlighted.data('data');
1176
+ var data = Utils.GetData($highlighted[0], 'data');
1084
1177
 
1085
1178
  if ($highlighted.attr('aria-selected') == 'true') {
1086
1179
  self.trigger('close', {});
@@ -1098,8 +1191,9 @@ S2.define('select2/results',[
1098
1191
 
1099
1192
  var currentIndex = $options.index($highlighted);
1100
1193
 
1101
- // If we are already at te top, don't move further
1102
- if (currentIndex === 0) {
1194
+ // If we are already at the top, don't move further
1195
+ // If no options, currentIndex will be -1
1196
+ if (currentIndex <= 0) {
1103
1197
  return;
1104
1198
  }
1105
1199
 
@@ -1192,7 +1286,7 @@ S2.define('select2/results',[
1192
1286
  function (evt) {
1193
1287
  var $this = $(this);
1194
1288
 
1195
- var data = $this.data('data');
1289
+ var data = Utils.GetData(this, 'data');
1196
1290
 
1197
1291
  if ($this.attr('aria-selected') === 'true') {
1198
1292
  if (self.options.get('multiple')) {
@@ -1215,7 +1309,7 @@ S2.define('select2/results',[
1215
1309
 
1216
1310
  this.$results.on('mouseenter', '.select2-results__option[aria-selected]',
1217
1311
  function (evt) {
1218
- var data = $(this).data('data');
1312
+ var data = Utils.GetData(this, 'data');
1219
1313
 
1220
1314
  self.getHighlightedResults()
1221
1315
  .removeClass('select2-results__option--highlighted');
@@ -1330,14 +1424,15 @@ S2.define('select2/selection/base',[
1330
1424
 
1331
1425
  this._tabindex = 0;
1332
1426
 
1333
- if (this.$element.data('old-tabindex') != null) {
1334
- this._tabindex = this.$element.data('old-tabindex');
1427
+ if (Utils.GetData(this.$element[0], 'old-tabindex') != null) {
1428
+ this._tabindex = Utils.GetData(this.$element[0], 'old-tabindex');
1335
1429
  } else if (this.$element.attr('tabindex') != null) {
1336
1430
  this._tabindex = this.$element.attr('tabindex');
1337
1431
  }
1338
1432
 
1339
1433
  $selection.attr('title', this.$element.attr('title'));
1340
1434
  $selection.attr('tabindex', this._tabindex);
1435
+ $selection.attr('aria-disabled', 'false');
1341
1436
 
1342
1437
  this.$selection = $selection;
1343
1438
 
@@ -1347,7 +1442,6 @@ S2.define('select2/selection/base',[
1347
1442
  BaseSelection.prototype.bind = function (container, $container) {
1348
1443
  var self = this;
1349
1444
 
1350
- var id = container.id + '-container';
1351
1445
  var resultsId = container.id + '-results';
1352
1446
 
1353
1447
  this.container = container;
@@ -1390,17 +1484,19 @@ S2.define('select2/selection/base',[
1390
1484
  self.$selection.removeAttr('aria-activedescendant');
1391
1485
  self.$selection.removeAttr('aria-owns');
1392
1486
 
1393
- self.$selection.focus();
1487
+ self.$selection.trigger('focus');
1394
1488
 
1395
1489
  self._detachCloseHandler(container);
1396
1490
  });
1397
1491
 
1398
1492
  container.on('enable', function () {
1399
1493
  self.$selection.attr('tabindex', self._tabindex);
1494
+ self.$selection.attr('aria-disabled', 'false');
1400
1495
  });
1401
1496
 
1402
1497
  container.on('disable', function () {
1403
1498
  self.$selection.attr('tabindex', '-1');
1499
+ self.$selection.attr('aria-disabled', 'true');
1404
1500
  });
1405
1501
  };
1406
1502
 
@@ -1423,7 +1519,6 @@ S2.define('select2/selection/base',[
1423
1519
  };
1424
1520
 
1425
1521
  BaseSelection.prototype._attachCloseHandler = function (container) {
1426
- var self = this;
1427
1522
 
1428
1523
  $(document.body).on('mousedown.select2.' + container.id, function (e) {
1429
1524
  var $target = $(e.target);
@@ -1433,13 +1528,11 @@ S2.define('select2/selection/base',[
1433
1528
  var $all = $('.select2.select2-container--open');
1434
1529
 
1435
1530
  $all.each(function () {
1436
- var $this = $(this);
1437
-
1438
1531
  if (this == $select[0]) {
1439
1532
  return;
1440
1533
  }
1441
1534
 
1442
- var $element = $this.data('element');
1535
+ var $element = Utils.GetData(this, 'element');
1443
1536
 
1444
1537
  $element.select2('close');
1445
1538
  });
@@ -1463,6 +1556,27 @@ S2.define('select2/selection/base',[
1463
1556
  throw new Error('The `update` method must be defined in child classes.');
1464
1557
  };
1465
1558
 
1559
+ /**
1560
+ * Helper method to abstract the "enabled" (not "disabled") state of this
1561
+ * object.
1562
+ *
1563
+ * @return {true} if the instance is not disabled.
1564
+ * @return {false} if the instance is disabled.
1565
+ */
1566
+ BaseSelection.prototype.isEnabled = function () {
1567
+ return !this.isDisabled();
1568
+ };
1569
+
1570
+ /**
1571
+ * Helper method to abstract the "disabled" state of this object.
1572
+ *
1573
+ * @return {true} if the disabled option is true.
1574
+ * @return {false} if the disabled option is false.
1575
+ */
1576
+ BaseSelection.prototype.isDisabled = function () {
1577
+ return this.options.get('disabled');
1578
+ };
1579
+
1466
1580
  return BaseSelection;
1467
1581
  });
1468
1582
 
@@ -1500,7 +1614,10 @@ S2.define('select2/selection/single',[
1500
1614
 
1501
1615
  var id = container.id + '-container';
1502
1616
 
1503
- this.$selection.find('.select2-selection__rendered').attr('id', id);
1617
+ this.$selection.find('.select2-selection__rendered')
1618
+ .attr('id', id)
1619
+ .attr('role', 'textbox')
1620
+ .attr('aria-readonly', 'true');
1504
1621
  this.$selection.attr('aria-labelledby', id);
1505
1622
 
1506
1623
  this.$selection.on('mousedown', function (evt) {
@@ -1524,17 +1641,15 @@ S2.define('select2/selection/single',[
1524
1641
 
1525
1642
  container.on('focus', function (evt) {
1526
1643
  if (!container.isOpen()) {
1527
- self.$selection.focus();
1644
+ self.$selection.trigger('focus');
1528
1645
  }
1529
1646
  });
1530
-
1531
- container.on('selection:update', function (params) {
1532
- self.update(params.data);
1533
- });
1534
1647
  };
1535
1648
 
1536
1649
  SingleSelection.prototype.clear = function () {
1537
- this.$selection.find('.select2-selection__rendered').empty();
1650
+ var $rendered = this.$selection.find('.select2-selection__rendered');
1651
+ $rendered.empty();
1652
+ $rendered.removeAttr('title'); // clear tooltip on empty
1538
1653
  };
1539
1654
 
1540
1655
  SingleSelection.prototype.display = function (data, container) {
@@ -1560,7 +1675,14 @@ S2.define('select2/selection/single',[
1560
1675
  var formatted = this.display(selection, $rendered);
1561
1676
 
1562
1677
  $rendered.empty().append(formatted);
1563
- $rendered.prop('title', selection.title || selection.text);
1678
+
1679
+ var title = selection.title || selection.text;
1680
+
1681
+ if (title) {
1682
+ $rendered.attr('title', title);
1683
+ } else {
1684
+ $rendered.removeAttr('title');
1685
+ }
1564
1686
  };
1565
1687
 
1566
1688
  return SingleSelection;
@@ -1605,14 +1727,14 @@ S2.define('select2/selection/multiple',[
1605
1727
  '.select2-selection__choice__remove',
1606
1728
  function (evt) {
1607
1729
  // Ignore the event if it is disabled
1608
- if (self.options.get('disabled')) {
1730
+ if (self.isDisabled()) {
1609
1731
  return;
1610
1732
  }
1611
1733
 
1612
1734
  var $remove = $(this);
1613
1735
  var $selection = $remove.parent();
1614
1736
 
1615
- var data = $selection.data('data');
1737
+ var data = Utils.GetData($selection[0], 'data');
1616
1738
 
1617
1739
  self.trigger('unselect', {
1618
1740
  originalEvent: evt,
@@ -1623,7 +1745,9 @@ S2.define('select2/selection/multiple',[
1623
1745
  };
1624
1746
 
1625
1747
  MultipleSelection.prototype.clear = function () {
1626
- this.$selection.find('.select2-selection__rendered').empty();
1748
+ var $rendered = this.$selection.find('.select2-selection__rendered');
1749
+ $rendered.empty();
1750
+ $rendered.removeAttr('title');
1627
1751
  };
1628
1752
 
1629
1753
  MultipleSelection.prototype.display = function (data, container) {
@@ -1661,9 +1785,14 @@ S2.define('select2/selection/multiple',[
1661
1785
  var formatted = this.display(selection, $selection);
1662
1786
 
1663
1787
  $selection.append(formatted);
1664
- $selection.prop('title', selection.title || selection.text);
1665
1788
 
1666
- $selection.data('data', selection);
1789
+ var title = selection.title || selection.text;
1790
+
1791
+ if (title) {
1792
+ $selection.attr('title', title);
1793
+ }
1794
+
1795
+ Utils.StoreData($selection[0], 'data', selection);
1667
1796
 
1668
1797
  $selections.push($selection);
1669
1798
  }
@@ -1728,8 +1857,9 @@ S2.define('select2/selection/placeholder',[
1728
1857
 
1729
1858
  S2.define('select2/selection/allowClear',[
1730
1859
  'jquery',
1731
- '../keys'
1732
- ], function ($, KEYS) {
1860
+ '../keys',
1861
+ '../utils'
1862
+ ], function ($, KEYS, Utils) {
1733
1863
  function AllowClear () { }
1734
1864
 
1735
1865
  AllowClear.prototype.bind = function (decorated, container, $container) {
@@ -1758,7 +1888,7 @@ S2.define('select2/selection/allowClear',[
1758
1888
 
1759
1889
  AllowClear.prototype._handleClear = function (_, evt) {
1760
1890
  // Ignore the event if it is disabled
1761
- if (this.options.get('disabled')) {
1891
+ if (this.isDisabled()) {
1762
1892
  return;
1763
1893
  }
1764
1894
 
@@ -1771,10 +1901,22 @@ S2.define('select2/selection/allowClear',[
1771
1901
 
1772
1902
  evt.stopPropagation();
1773
1903
 
1774
- var data = $clear.data('data');
1904
+ var data = Utils.GetData($clear[0], 'data');
1905
+
1906
+ var previousVal = this.$element.val();
1907
+ this.$element.val(this.placeholder.id);
1908
+
1909
+ var unselectData = {
1910
+ data: data
1911
+ };
1912
+ this.trigger('clear', unselectData);
1913
+ if (unselectData.prevented) {
1914
+ this.$element.val(previousVal);
1915
+ return;
1916
+ }
1775
1917
 
1776
1918
  for (var d = 0; d < data.length; d++) {
1777
- var unselectData = {
1919
+ unselectData = {
1778
1920
  data: data[d]
1779
1921
  };
1780
1922
 
@@ -1784,11 +1926,12 @@ S2.define('select2/selection/allowClear',[
1784
1926
 
1785
1927
  // If the event was prevented, don't clear it out.
1786
1928
  if (unselectData.prevented) {
1929
+ this.$element.val(previousVal);
1787
1930
  return;
1788
1931
  }
1789
1932
  }
1790
1933
 
1791
- this.$element.val(this.placeholder.id).trigger('change');
1934
+ this.$element.trigger('input').trigger('change');
1792
1935
 
1793
1936
  this.trigger('toggle', {});
1794
1937
  };
@@ -1811,12 +1954,14 @@ S2.define('select2/selection/allowClear',[
1811
1954
  return;
1812
1955
  }
1813
1956
 
1957
+ var removeAll = this.options.get('translations').get('removeAllItems');
1958
+
1814
1959
  var $remove = $(
1815
- '<span class="select2-selection__clear">' +
1960
+ '<span class="select2-selection__clear" title="' + removeAll() +'">' +
1816
1961
  '&times;' +
1817
1962
  '</span>'
1818
1963
  );
1819
- $remove.data('data', data);
1964
+ Utils.StoreData($remove[0], 'data', data);
1820
1965
 
1821
1966
  this.$selection.find('.select2-selection__rendered').prepend($remove);
1822
1967
  };
@@ -1837,8 +1982,8 @@ S2.define('select2/selection/search',[
1837
1982
  var $search = $(
1838
1983
  '<li class="select2-search select2-search--inline">' +
1839
1984
  '<input class="select2-search__field" type="search" tabindex="-1"' +
1840
- ' autocomplete="off" autocorrect="off" autocapitalize="off"' +
1841
- ' spellcheck="false" role="textbox" aria-autocomplete="list" />' +
1985
+ ' autocomplete="off" autocorrect="off" autocapitalize="none"' +
1986
+ ' spellcheck="false" role="searchbox" aria-autocomplete="list" />' +
1842
1987
  '</li>'
1843
1988
  );
1844
1989
 
@@ -1855,14 +2000,18 @@ S2.define('select2/selection/search',[
1855
2000
  Search.prototype.bind = function (decorated, container, $container) {
1856
2001
  var self = this;
1857
2002
 
2003
+ var resultsId = container.id + '-results';
2004
+
1858
2005
  decorated.call(this, container, $container);
1859
2006
 
1860
2007
  container.on('open', function () {
2008
+ self.$search.attr('aria-controls', resultsId);
1861
2009
  self.$search.trigger('focus');
1862
2010
  });
1863
2011
 
1864
2012
  container.on('close', function () {
1865
2013
  self.$search.val('');
2014
+ self.$search.removeAttr('aria-controls');
1866
2015
  self.$search.removeAttr('aria-activedescendant');
1867
2016
  self.$search.trigger('focus');
1868
2017
  });
@@ -1882,7 +2031,11 @@ S2.define('select2/selection/search',[
1882
2031
  });
1883
2032
 
1884
2033
  container.on('results:focus', function (params) {
1885
- self.$search.attr('aria-activedescendant', params.id);
2034
+ if (params.data._resultId) {
2035
+ self.$search.attr('aria-activedescendant', params.data._resultId);
2036
+ } else {
2037
+ self.$search.removeAttr('aria-activedescendant');
2038
+ }
1886
2039
  });
1887
2040
 
1888
2041
  this.$selection.on('focusin', '.select2-search--inline', function (evt) {
@@ -1907,7 +2060,7 @@ S2.define('select2/selection/search',[
1907
2060
  .prev('.select2-selection__choice');
1908
2061
 
1909
2062
  if ($previousChoice.length > 0) {
1910
- var item = $previousChoice.data('data');
2063
+ var item = Utils.GetData($previousChoice[0], 'data');
1911
2064
 
1912
2065
  self.searchRemoveChoice(item);
1913
2066
 
@@ -1916,6 +2069,12 @@ S2.define('select2/selection/search',[
1916
2069
  }
1917
2070
  });
1918
2071
 
2072
+ this.$selection.on('click', '.select2-search--inline', function (evt) {
2073
+ if (self.$search.val()) {
2074
+ evt.stopPropagation();
2075
+ }
2076
+ });
2077
+
1919
2078
  // Try to detect the IE version should the `documentMode` property that
1920
2079
  // is stored on the document. This is only implemented in IE and is
1921
2080
  // slightly cleaner than doing a user agent check.
@@ -2001,7 +2160,7 @@ S2.define('select2/selection/search',[
2001
2160
 
2002
2161
  this.resizeSearch();
2003
2162
  if (searchHadFocus) {
2004
- this.$search.focus();
2163
+ this.$search.trigger('focus');
2005
2164
  }
2006
2165
  };
2007
2166
 
@@ -2034,7 +2193,7 @@ S2.define('select2/selection/search',[
2034
2193
  var width = '';
2035
2194
 
2036
2195
  if (this.$search.attr('placeholder') !== '') {
2037
- width = this.$selection.find('.select2-selection__rendered').innerWidth();
2196
+ width = this.$selection.find('.select2-selection__rendered').width();
2038
2197
  } else {
2039
2198
  var minimumWidth = this.$search.val().length + 1;
2040
2199
 
@@ -2058,10 +2217,13 @@ S2.define('select2/selection/eventRelay',[
2058
2217
  'open', 'opening',
2059
2218
  'close', 'closing',
2060
2219
  'select', 'selecting',
2061
- 'unselect', 'unselecting'
2220
+ 'unselect', 'unselecting',
2221
+ 'clear', 'clearing'
2062
2222
  ];
2063
2223
 
2064
- var preventableEvents = ['opening', 'closing', 'selecting', 'unselecting'];
2224
+ var preventableEvents = [
2225
+ 'opening', 'closing', 'selecting', 'unselecting', 'clearing'
2226
+ ];
2065
2227
 
2066
2228
  decorated.call(this, container, $container);
2067
2229
 
@@ -2394,6 +2556,7 @@ S2.define('select2/diacritics',[
2394
2556
  '\u019F': 'O',
2395
2557
  '\uA74A': 'O',
2396
2558
  '\uA74C': 'O',
2559
+ '\u0152': 'OE',
2397
2560
  '\u01A2': 'OI',
2398
2561
  '\uA74E': 'OO',
2399
2562
  '\u0222': 'OU',
@@ -2803,6 +2966,7 @@ S2.define('select2/diacritics',[
2803
2966
  '\uA74B': 'o',
2804
2967
  '\uA74D': 'o',
2805
2968
  '\u0275': 'o',
2969
+ '\u0153': 'oe',
2806
2970
  '\u01A3': 'oi',
2807
2971
  '\u0223': 'ou',
2808
2972
  '\uA74F': 'oo',
@@ -2971,8 +3135,9 @@ S2.define('select2/diacritics',[
2971
3135
  '\u03CD': '\u03C5',
2972
3136
  '\u03CB': '\u03C5',
2973
3137
  '\u03B0': '\u03C5',
2974
- '\u03C9': '\u03C9',
2975
- '\u03C2': '\u03C3'
3138
+ '\u03CE': '\u03C9',
3139
+ '\u03C2': '\u03C3',
3140
+ '\u2019': '\''
2976
3141
  };
2977
3142
 
2978
3143
  return diacritics;
@@ -3057,7 +3222,7 @@ S2.define('select2/data/select',[
3057
3222
  if ($(data.element).is('option')) {
3058
3223
  data.element.selected = true;
3059
3224
 
3060
- this.$element.trigger('change');
3225
+ this.$element.trigger('input').trigger('change');
3061
3226
 
3062
3227
  return;
3063
3228
  }
@@ -3078,13 +3243,13 @@ S2.define('select2/data/select',[
3078
3243
  }
3079
3244
 
3080
3245
  self.$element.val(val);
3081
- self.$element.trigger('change');
3246
+ self.$element.trigger('input').trigger('change');
3082
3247
  });
3083
3248
  } else {
3084
3249
  var val = data.id;
3085
3250
 
3086
3251
  this.$element.val(val);
3087
- this.$element.trigger('change');
3252
+ this.$element.trigger('input').trigger('change');
3088
3253
  }
3089
3254
  };
3090
3255
 
@@ -3100,7 +3265,7 @@ S2.define('select2/data/select',[
3100
3265
  if ($(data.element).is('option')) {
3101
3266
  data.element.selected = false;
3102
3267
 
3103
- this.$element.trigger('change');
3268
+ this.$element.trigger('input').trigger('change');
3104
3269
 
3105
3270
  return;
3106
3271
  }
@@ -3118,7 +3283,7 @@ S2.define('select2/data/select',[
3118
3283
 
3119
3284
  self.$element.val(val);
3120
3285
 
3121
- self.$element.trigger('change');
3286
+ self.$element.trigger('input').trigger('change');
3122
3287
  });
3123
3288
  };
3124
3289
 
@@ -3140,7 +3305,7 @@ S2.define('select2/data/select',[
3140
3305
  // Remove anything added to child elements
3141
3306
  this.$element.find('*').each(function () {
3142
3307
  // Remove any custom data set by Select2
3143
- $.removeData(this, 'data');
3308
+ Utils.RemoveData(this);
3144
3309
  });
3145
3310
  };
3146
3311
 
@@ -3191,7 +3356,7 @@ S2.define('select2/data/select',[
3191
3356
  }
3192
3357
  }
3193
3358
 
3194
- if (data.id) {
3359
+ if (data.id !== undefined) {
3195
3360
  option.value = data.id;
3196
3361
  }
3197
3362
 
@@ -3213,7 +3378,7 @@ S2.define('select2/data/select',[
3213
3378
  normalizedData.element = option;
3214
3379
 
3215
3380
  // Override the option's data with the combined data
3216
- $.data(option, 'data', normalizedData);
3381
+ Utils.StoreData(option, 'data', normalizedData);
3217
3382
 
3218
3383
  return $option;
3219
3384
  };
@@ -3221,7 +3386,7 @@ S2.define('select2/data/select',[
3221
3386
  SelectAdapter.prototype.item = function ($option) {
3222
3387
  var data = {};
3223
3388
 
3224
- data = $.data($option[0], 'data');
3389
+ data = Utils.GetData($option[0], 'data');
3225
3390
 
3226
3391
  if (data != null) {
3227
3392
  return data;
@@ -3259,13 +3424,13 @@ S2.define('select2/data/select',[
3259
3424
  data = this._normalizeItem(data);
3260
3425
  data.element = $option[0];
3261
3426
 
3262
- $.data($option[0], 'data', data);
3427
+ Utils.StoreData($option[0], 'data', data);
3263
3428
 
3264
3429
  return data;
3265
3430
  };
3266
3431
 
3267
3432
  SelectAdapter.prototype._normalizeItem = function (item) {
3268
- if (!$.isPlainObject(item)) {
3433
+ if (item !== Object(item)) {
3269
3434
  item = {
3270
3435
  id: item,
3271
3436
  text: item
@@ -3311,15 +3476,19 @@ S2.define('select2/data/array',[
3311
3476
  'jquery'
3312
3477
  ], function (SelectAdapter, Utils, $) {
3313
3478
  function ArrayAdapter ($element, options) {
3314
- var data = options.get('data') || [];
3479
+ this._dataToConvert = options.get('data') || [];
3315
3480
 
3316
3481
  ArrayAdapter.__super__.constructor.call(this, $element, options);
3317
-
3318
- this.addOptions(this.convertToOptions(data));
3319
3482
  }
3320
3483
 
3321
3484
  Utils.Extend(ArrayAdapter, SelectAdapter);
3322
3485
 
3486
+ ArrayAdapter.prototype.bind = function (container, $container) {
3487
+ ArrayAdapter.__super__.bind.call(this, container, $container);
3488
+
3489
+ this.addOptions(this.convertToOptions(this._dataToConvert));
3490
+ };
3491
+
3323
3492
  ArrayAdapter.prototype.select = function (data) {
3324
3493
  var $option = this.$element.find('option').filter(function (i, elm) {
3325
3494
  return elm.value == data.id.toString();
@@ -3469,7 +3638,8 @@ S2.define('select2/data/ajax',[
3469
3638
  }, function () {
3470
3639
  // Attempt to detect if a request was aborted
3471
3640
  // Only works if the transport exposes a status property
3472
- if ($request.status && $request.status === '0') {
3641
+ if ('status' in $request &&
3642
+ ($request.status === 0 || $request.status === '0')) {
3473
3643
  return;
3474
3644
  }
3475
3645
 
@@ -3550,7 +3720,10 @@ S2.define('select2/data/tags',[
3550
3720
  }, true)
3551
3721
  );
3552
3722
 
3553
- var checkText = option.text === params.term;
3723
+ var optionText = (option.text || '').toUpperCase();
3724
+ var paramsTerm = (params.term || '').toUpperCase();
3725
+
3726
+ var checkText = optionText === paramsTerm;
3554
3727
 
3555
3728
  if (checkText || checkChildren) {
3556
3729
  if (child) {
@@ -3605,8 +3778,6 @@ S2.define('select2/data/tags',[
3605
3778
  };
3606
3779
 
3607
3780
  Tags.prototype._removeOldTags = function (_) {
3608
- var tag = this._lastTag;
3609
-
3610
3781
  var $options = this.$element.find('option[data-select2-tag]');
3611
3782
 
3612
3783
  $options.each(function () {
@@ -3681,7 +3852,7 @@ S2.define('select2/data/tokenizer',[
3681
3852
  // Replace the search term if we have the search box
3682
3853
  if (this.$search.length) {
3683
3854
  this.$search.val(tokenData.term);
3684
- this.$search.focus();
3855
+ this.$search.trigger('focus');
3685
3856
  }
3686
3857
 
3687
3858
  params.term = tokenData.term;
@@ -3810,10 +3981,30 @@ S2.define('select2/data/maximumSelectionLength',[
3810
3981
  decorated.call(this, $e, options);
3811
3982
  }
3812
3983
 
3984
+ MaximumSelectionLength.prototype.bind =
3985
+ function (decorated, container, $container) {
3986
+ var self = this;
3987
+
3988
+ decorated.call(this, container, $container);
3989
+
3990
+ container.on('select', function () {
3991
+ self._checkIfMaximumSelected();
3992
+ });
3993
+ };
3994
+
3813
3995
  MaximumSelectionLength.prototype.query =
3814
3996
  function (decorated, params, callback) {
3815
3997
  var self = this;
3816
3998
 
3999
+ this._checkIfMaximumSelected(function () {
4000
+ decorated.call(self, params, callback);
4001
+ });
4002
+ };
4003
+
4004
+ MaximumSelectionLength.prototype._checkIfMaximumSelected =
4005
+ function (_, successCallback) {
4006
+ var self = this;
4007
+
3817
4008
  this.current(function (currentData) {
3818
4009
  var count = currentData != null ? currentData.length : 0;
3819
4010
  if (self.maximumSelectionLength > 0 &&
@@ -3826,7 +4017,10 @@ S2.define('select2/data/maximumSelectionLength',[
3826
4017
  });
3827
4018
  return;
3828
4019
  }
3829
- decorated.call(self, params, callback);
4020
+
4021
+ if (successCallback) {
4022
+ successCallback();
4023
+ }
3830
4024
  });
3831
4025
  };
3832
4026
 
@@ -3865,7 +4059,7 @@ S2.define('select2/dropdown',[
3865
4059
  };
3866
4060
 
3867
4061
  Dropdown.prototype.position = function ($dropdown, $container) {
3868
- // Should be implmented in subclasses
4062
+ // Should be implemented in subclasses
3869
4063
  };
3870
4064
 
3871
4065
  Dropdown.prototype.destroy = function () {
@@ -3888,8 +4082,8 @@ S2.define('select2/dropdown/search',[
3888
4082
  var $search = $(
3889
4083
  '<span class="select2-search select2-search--dropdown">' +
3890
4084
  '<input class="select2-search__field" type="search" tabindex="-1"' +
3891
- ' autocomplete="off" autocorrect="off" autocapitalize="off"' +
3892
- ' spellcheck="false" role="textbox" />' +
4085
+ ' autocomplete="off" autocorrect="off" autocapitalize="none"' +
4086
+ ' spellcheck="false" role="searchbox" aria-autocomplete="list" />' +
3893
4087
  '</span>'
3894
4088
  );
3895
4089
 
@@ -3904,6 +4098,8 @@ S2.define('select2/dropdown/search',[
3904
4098
  Search.prototype.bind = function (decorated, container, $container) {
3905
4099
  var self = this;
3906
4100
 
4101
+ var resultsId = container.id + '-results';
4102
+
3907
4103
  decorated.call(this, container, $container);
3908
4104
 
3909
4105
  this.$search.on('keydown', function (evt) {
@@ -3926,23 +4122,27 @@ S2.define('select2/dropdown/search',[
3926
4122
 
3927
4123
  container.on('open', function () {
3928
4124
  self.$search.attr('tabindex', 0);
4125
+ self.$search.attr('aria-controls', resultsId);
3929
4126
 
3930
- self.$search.focus();
4127
+ self.$search.trigger('focus');
3931
4128
 
3932
4129
  window.setTimeout(function () {
3933
- self.$search.focus();
4130
+ self.$search.trigger('focus');
3934
4131
  }, 0);
3935
4132
  });
3936
4133
 
3937
4134
  container.on('close', function () {
3938
4135
  self.$search.attr('tabindex', -1);
4136
+ self.$search.removeAttr('aria-controls');
4137
+ self.$search.removeAttr('aria-activedescendant');
3939
4138
 
3940
4139
  self.$search.val('');
4140
+ self.$search.trigger('blur');
3941
4141
  });
3942
4142
 
3943
4143
  container.on('focus', function () {
3944
- if (container.isOpen()) {
3945
- self.$search.focus();
4144
+ if (!container.isOpen()) {
4145
+ self.$search.trigger('focus');
3946
4146
  }
3947
4147
  });
3948
4148
 
@@ -3957,6 +4157,14 @@ S2.define('select2/dropdown/search',[
3957
4157
  }
3958
4158
  }
3959
4159
  });
4160
+
4161
+ container.on('results:focus', function (params) {
4162
+ if (params.data._resultId) {
4163
+ self.$search.attr('aria-activedescendant', params.data._resultId);
4164
+ } else {
4165
+ self.$search.removeAttr('aria-activedescendant');
4166
+ }
4167
+ });
3960
4168
  };
3961
4169
 
3962
4170
  Search.prototype.handleSearch = function (evt) {
@@ -4041,6 +4249,7 @@ S2.define('select2/dropdown/infiniteScroll',[
4041
4249
 
4042
4250
  if (this.showLoadingMore(data)) {
4043
4251
  this.$results.append(this.$loadingMore);
4252
+ this.loadMoreIfNeeded();
4044
4253
  }
4045
4254
  };
4046
4255
 
@@ -4059,25 +4268,27 @@ S2.define('select2/dropdown/infiniteScroll',[
4059
4268
  self.loading = true;
4060
4269
  });
4061
4270
 
4062
- this.$results.on('scroll', function () {
4063
- var isLoadMoreVisible = $.contains(
4064
- document.documentElement,
4065
- self.$loadingMore[0]
4066
- );
4271
+ this.$results.on('scroll', this.loadMoreIfNeeded.bind(this));
4272
+ };
4067
4273
 
4068
- if (self.loading || !isLoadMoreVisible) {
4069
- return;
4070
- }
4274
+ InfiniteScroll.prototype.loadMoreIfNeeded = function () {
4275
+ var isLoadMoreVisible = $.contains(
4276
+ document.documentElement,
4277
+ this.$loadingMore[0]
4278
+ );
4071
4279
 
4072
- var currentOffset = self.$results.offset().top +
4073
- self.$results.outerHeight(false);
4074
- var loadingMoreOffset = self.$loadingMore.offset().top +
4075
- self.$loadingMore.outerHeight(false);
4280
+ if (this.loading || !isLoadMoreVisible) {
4281
+ return;
4282
+ }
4076
4283
 
4077
- if (currentOffset + 50 >= loadingMoreOffset) {
4078
- self.loadMore();
4079
- }
4080
- });
4284
+ var currentOffset = this.$results.offset().top +
4285
+ this.$results.outerHeight(false);
4286
+ var loadingMoreOffset = this.$loadingMore.offset().top +
4287
+ this.$loadingMore.outerHeight(false);
4288
+
4289
+ if (currentOffset + 50 >= loadingMoreOffset) {
4290
+ this.loadMore();
4291
+ }
4081
4292
  };
4082
4293
 
4083
4294
  InfiniteScroll.prototype.loadMore = function () {
@@ -4098,7 +4309,7 @@ S2.define('select2/dropdown/infiniteScroll',[
4098
4309
  var $option = $(
4099
4310
  '<li ' +
4100
4311
  'class="select2-results__option select2-results__option--load-more"' +
4101
- 'role="treeitem" aria-disabled="true"></li>'
4312
+ 'role="option" aria-disabled="true"></li>'
4102
4313
  );
4103
4314
 
4104
4315
  var message = this.options.get('translations').get('loadingMore');
@@ -4116,7 +4327,7 @@ S2.define('select2/dropdown/attachBody',[
4116
4327
  '../utils'
4117
4328
  ], function ($, Utils) {
4118
4329
  function AttachBody (decorated, $element, options) {
4119
- this.$dropdownParent = options.get('dropdownParent') || $(document.body);
4330
+ this.$dropdownParent = $(options.get('dropdownParent') || document.body);
4120
4331
 
4121
4332
  decorated.call(this, $element, options);
4122
4333
  }
@@ -4124,27 +4335,14 @@ S2.define('select2/dropdown/attachBody',[
4124
4335
  AttachBody.prototype.bind = function (decorated, container, $container) {
4125
4336
  var self = this;
4126
4337
 
4127
- var setupResultsEvents = false;
4128
-
4129
4338
  decorated.call(this, container, $container);
4130
4339
 
4131
4340
  container.on('open', function () {
4132
4341
  self._showDropdown();
4133
4342
  self._attachPositioningHandler(container);
4134
4343
 
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
- }
4344
+ // Must bind after the results handlers to ensure correct sizing
4345
+ self._bindContainerResultHandlers(container);
4148
4346
  });
4149
4347
 
4150
4348
  container.on('close', function () {
@@ -4193,6 +4391,44 @@ S2.define('select2/dropdown/attachBody',[
4193
4391
  this.$dropdownContainer.detach();
4194
4392
  };
4195
4393
 
4394
+ AttachBody.prototype._bindContainerResultHandlers =
4395
+ function (decorated, container) {
4396
+
4397
+ // These should only be bound once
4398
+ if (this._containerResultsHandlersBound) {
4399
+ return;
4400
+ }
4401
+
4402
+ var self = this;
4403
+
4404
+ container.on('results:all', function () {
4405
+ self._positionDropdown();
4406
+ self._resizeDropdown();
4407
+ });
4408
+
4409
+ container.on('results:append', function () {
4410
+ self._positionDropdown();
4411
+ self._resizeDropdown();
4412
+ });
4413
+
4414
+ container.on('results:message', function () {
4415
+ self._positionDropdown();
4416
+ self._resizeDropdown();
4417
+ });
4418
+
4419
+ container.on('select', function () {
4420
+ self._positionDropdown();
4421
+ self._resizeDropdown();
4422
+ });
4423
+
4424
+ container.on('unselect', function () {
4425
+ self._positionDropdown();
4426
+ self._resizeDropdown();
4427
+ });
4428
+
4429
+ this._containerResultsHandlersBound = true;
4430
+ };
4431
+
4196
4432
  AttachBody.prototype._attachPositioningHandler =
4197
4433
  function (decorated, container) {
4198
4434
  var self = this;
@@ -4203,14 +4439,14 @@ S2.define('select2/dropdown/attachBody',[
4203
4439
 
4204
4440
  var $watchers = this.$container.parents().filter(Utils.hasScroll);
4205
4441
  $watchers.each(function () {
4206
- $(this).data('select2-scroll-position', {
4442
+ Utils.StoreData(this, 'select2-scroll-position', {
4207
4443
  x: $(this).scrollLeft(),
4208
4444
  y: $(this).scrollTop()
4209
4445
  });
4210
4446
  });
4211
4447
 
4212
4448
  $watchers.on(scrollEvent, function (ev) {
4213
- var position = $(this).data('select2-scroll-position');
4449
+ var position = Utils.GetData(this, 'select2-scroll-position');
4214
4450
  $(this).scrollTop(position.y);
4215
4451
  });
4216
4452
 
@@ -4269,16 +4505,26 @@ S2.define('select2/dropdown/attachBody',[
4269
4505
  top: container.bottom
4270
4506
  };
4271
4507
 
4272
- // Determine what the parent element is to use for calciulating the offset
4508
+ // Determine what the parent element is to use for calculating the offset
4273
4509
  var $offsetParent = this.$dropdownParent;
4274
4510
 
4275
- // For statically positoned elements, we need to get the element
4511
+ // For statically positioned elements, we need to get the element
4276
4512
  // that is determining the offset
4277
4513
  if ($offsetParent.css('position') === 'static') {
4278
4514
  $offsetParent = $offsetParent.offsetParent();
4279
4515
  }
4280
4516
 
4281
- var parentOffset = $offsetParent.offset();
4517
+ var parentOffset = {
4518
+ top: 0,
4519
+ left: 0
4520
+ };
4521
+
4522
+ if (
4523
+ $.contains(document.body, $offsetParent[0]) ||
4524
+ $offsetParent[0].isConnected
4525
+ ) {
4526
+ parentOffset = $offsetParent.offset();
4527
+ }
4282
4528
 
4283
4529
  css.top -= parentOffset.top;
4284
4530
  css.left -= parentOffset.left;
@@ -4375,8 +4621,8 @@ S2.define('select2/dropdown/minimumResultsForSearch',[
4375
4621
  });
4376
4622
 
4377
4623
  S2.define('select2/dropdown/selectOnClose',[
4378
-
4379
- ], function () {
4624
+ '../utils'
4625
+ ], function (Utils) {
4380
4626
  function SelectOnClose () { }
4381
4627
 
4382
4628
  SelectOnClose.prototype.bind = function (decorated, container, $container) {
@@ -4407,7 +4653,7 @@ S2.define('select2/dropdown/selectOnClose',[
4407
4653
  return;
4408
4654
  }
4409
4655
 
4410
- var data = $highlightedResults.data('data');
4656
+ var data = Utils.GetData($highlightedResults[0], 'data');
4411
4657
 
4412
4658
  // Don't re-select already selected resulte
4413
4659
  if (
@@ -4448,7 +4694,7 @@ S2.define('select2/dropdown/closeOnSelect',[
4448
4694
  var originalEvent = evt.originalEvent;
4449
4695
 
4450
4696
  // Don't close if the control key is being held
4451
- if (originalEvent && originalEvent.ctrlKey) {
4697
+ if (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey)) {
4452
4698
  return;
4453
4699
  }
4454
4700
 
@@ -4502,6 +4748,9 @@ S2.define('select2/i18n/en',[],function () {
4502
4748
  },
4503
4749
  searching: function () {
4504
4750
  return 'Searching…';
4751
+ },
4752
+ removeAllItems: function () {
4753
+ return 'Remove all items';
4505
4754
  }
4506
4755
  };
4507
4756
  });
@@ -4740,66 +4989,29 @@ S2.define('select2/defaults',[
4740
4989
  );
4741
4990
  }
4742
4991
 
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
- }
4992
+ // If the defaults were not previously applied from an element, it is
4993
+ // possible for the language option to have not been resolved
4994
+ options.language = this._resolveLanguage(options.language);
4755
4995
 
4756
- if ($.isArray(options.language)) {
4757
- var languages = new Translation();
4758
- options.language.push('en');
4996
+ // Always fall back to English since it will always be complete
4997
+ options.language.push('en');
4759
4998
 
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
- }
4999
+ var uniqueLanguages = [];
4784
5000
 
4785
- continue;
4786
- }
4787
- }
5001
+ for (var l = 0; l < options.language.length; l++) {
5002
+ var language = options.language[l];
4788
5003
 
4789
- languages.extend(language);
5004
+ if (uniqueLanguages.indexOf(language) === -1) {
5005
+ uniqueLanguages.push(language);
4790
5006
  }
5007
+ }
4791
5008
 
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);
5009
+ options.language = uniqueLanguages;
4800
5010
 
4801
- options.translations = customTranslation;
4802
- }
5011
+ options.translations = this._processTranslations(
5012
+ options.language,
5013
+ options.debug
5014
+ );
4803
5015
 
4804
5016
  return options;
4805
5017
  };
@@ -4866,13 +5078,14 @@ S2.define('select2/defaults',[
4866
5078
  debug: false,
4867
5079
  dropdownAutoWidth: false,
4868
5080
  escapeMarkup: Utils.escapeMarkup,
4869
- language: EnglishTranslation,
5081
+ language: {},
4870
5082
  matcher: matcher,
4871
5083
  minimumInputLength: 0,
4872
5084
  maximumInputLength: 0,
4873
5085
  maximumSelectionLength: 0,
4874
5086
  minimumResultsForSearch: 0,
4875
5087
  selectOnClose: false,
5088
+ scrollAfterSelect: false,
4876
5089
  sorter: function (data) {
4877
5090
  return data;
4878
5091
  },
@@ -4887,6 +5100,103 @@ S2.define('select2/defaults',[
4887
5100
  };
4888
5101
  };
4889
5102
 
5103
+ Defaults.prototype.applyFromElement = function (options, $element) {
5104
+ var optionLanguage = options.language;
5105
+ var defaultLanguage = this.defaults.language;
5106
+ var elementLanguage = $element.prop('lang');
5107
+ var parentLanguage = $element.closest('[lang]').prop('lang');
5108
+
5109
+ var languages = Array.prototype.concat.call(
5110
+ this._resolveLanguage(elementLanguage),
5111
+ this._resolveLanguage(optionLanguage),
5112
+ this._resolveLanguage(defaultLanguage),
5113
+ this._resolveLanguage(parentLanguage)
5114
+ );
5115
+
5116
+ options.language = languages;
5117
+
5118
+ return options;
5119
+ };
5120
+
5121
+ Defaults.prototype._resolveLanguage = function (language) {
5122
+ if (!language) {
5123
+ return [];
5124
+ }
5125
+
5126
+ if ($.isEmptyObject(language)) {
5127
+ return [];
5128
+ }
5129
+
5130
+ if ($.isPlainObject(language)) {
5131
+ return [language];
5132
+ }
5133
+
5134
+ var languages;
5135
+
5136
+ if (!$.isArray(language)) {
5137
+ languages = [language];
5138
+ } else {
5139
+ languages = language;
5140
+ }
5141
+
5142
+ var resolvedLanguages = [];
5143
+
5144
+ for (var l = 0; l < languages.length; l++) {
5145
+ resolvedLanguages.push(languages[l]);
5146
+
5147
+ if (typeof languages[l] === 'string' && languages[l].indexOf('-') > 0) {
5148
+ // Extract the region information if it is included
5149
+ var languageParts = languages[l].split('-');
5150
+ var baseLanguage = languageParts[0];
5151
+
5152
+ resolvedLanguages.push(baseLanguage);
5153
+ }
5154
+ }
5155
+
5156
+ return resolvedLanguages;
5157
+ };
5158
+
5159
+ Defaults.prototype._processTranslations = function (languages, debug) {
5160
+ var translations = new Translation();
5161
+
5162
+ for (var l = 0; l < languages.length; l++) {
5163
+ var languageData = new Translation();
5164
+
5165
+ var language = languages[l];
5166
+
5167
+ if (typeof language === 'string') {
5168
+ try {
5169
+ // Try to load it with the original name
5170
+ languageData = Translation.loadPath(language);
5171
+ } catch (e) {
5172
+ try {
5173
+ // If we couldn't load it, check if it wasn't the full path
5174
+ language = this.defaults.amdLanguageBase + language;
5175
+ languageData = Translation.loadPath(language);
5176
+ } catch (ex) {
5177
+ // The translation could not be loaded at all. Sometimes this is
5178
+ // because of a configuration problem, other times this can be
5179
+ // because of how Select2 helps load all possible translation files
5180
+ if (debug && window.console && console.warn) {
5181
+ console.warn(
5182
+ 'Select2: The language file for "' + language + '" could ' +
5183
+ 'not be automatically loaded. A fallback will be used instead.'
5184
+ );
5185
+ }
5186
+ }
5187
+ }
5188
+ } else if ($.isPlainObject(language)) {
5189
+ languageData = new Translation(language);
5190
+ } else {
5191
+ languageData = language;
5192
+ }
5193
+
5194
+ translations.extend(languageData);
5195
+ }
5196
+
5197
+ return translations;
5198
+ };
5199
+
4890
5200
  Defaults.prototype.set = function (key, value) {
4891
5201
  var camelKey = $.camelCase(key);
4892
5202
 
@@ -4895,7 +5205,7 @@ S2.define('select2/defaults',[
4895
5205
 
4896
5206
  var convertedData = Utils._convertData(data);
4897
5207
 
4898
- $.extend(this.defaults, convertedData);
5208
+ $.extend(true, this.defaults, convertedData);
4899
5209
  };
4900
5210
 
4901
5211
  var defaults = new Defaults();
@@ -4916,6 +5226,10 @@ S2.define('select2/options',[
4916
5226
  this.fromElement($element);
4917
5227
  }
4918
5228
 
5229
+ if ($element != null) {
5230
+ this.options = Defaults.applyFromElement(this.options, $element);
5231
+ }
5232
+
4919
5233
  this.options = Defaults.apply(this.options);
4920
5234
 
4921
5235
  if ($element && $element.is('input')) {
@@ -4939,14 +5253,6 @@ S2.define('select2/options',[
4939
5253
  this.options.disabled = $e.prop('disabled');
4940
5254
  }
4941
5255
 
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
5256
  if (this.options.dir == null) {
4951
5257
  if ($e.prop('dir')) {
4952
5258
  this.options.dir = $e.prop('dir');
@@ -4960,7 +5266,7 @@ S2.define('select2/options',[
4960
5266
  $e.prop('disabled', this.options.disabled);
4961
5267
  $e.prop('multiple', this.options.multiple);
4962
5268
 
4963
- if ($e.data('select2Tags')) {
5269
+ if (Utils.GetData($e[0], 'select2Tags')) {
4964
5270
  if (this.options.debug && window.console && console.warn) {
4965
5271
  console.warn(
4966
5272
  'Select2: The `data-select2-tags` attribute has been changed to ' +
@@ -4969,11 +5275,11 @@ S2.define('select2/options',[
4969
5275
  );
4970
5276
  }
4971
5277
 
4972
- $e.data('data', $e.data('select2Tags'));
4973
- $e.data('tags', true);
5278
+ Utils.StoreData($e[0], 'data', Utils.GetData($e[0], 'select2Tags'));
5279
+ Utils.StoreData($e[0], 'tags', true);
4974
5280
  }
4975
5281
 
4976
- if ($e.data('ajaxUrl')) {
5282
+ if (Utils.GetData($e[0], 'ajaxUrl')) {
4977
5283
  if (this.options.debug && window.console && console.warn) {
4978
5284
  console.warn(
4979
5285
  'Select2: The `data-ajax-url` attribute has been changed to ' +
@@ -4982,21 +5288,45 @@ S2.define('select2/options',[
4982
5288
  );
4983
5289
  }
4984
5290
 
4985
- $e.attr('ajax--url', $e.data('ajaxUrl'));
4986
- $e.data('ajax--url', $e.data('ajaxUrl'));
5291
+ $e.attr('ajax--url', Utils.GetData($e[0], 'ajaxUrl'));
5292
+ Utils.StoreData($e[0], 'ajax-Url', Utils.GetData($e[0], 'ajaxUrl'));
4987
5293
  }
4988
5294
 
4989
5295
  var dataset = {};
4990
5296
 
5297
+ function upperCaseLetter(_, letter) {
5298
+ return letter.toUpperCase();
5299
+ }
5300
+
5301
+ // Pre-load all of the attributes which are prefixed with `data-`
5302
+ for (var attr = 0; attr < $e[0].attributes.length; attr++) {
5303
+ var attributeName = $e[0].attributes[attr].name;
5304
+ var prefix = 'data-';
5305
+
5306
+ if (attributeName.substr(0, prefix.length) == prefix) {
5307
+ // Get the contents of the attribute after `data-`
5308
+ var dataName = attributeName.substring(prefix.length);
5309
+
5310
+ // Get the data contents from the consistent source
5311
+ // This is more than likely the jQuery data helper
5312
+ var dataValue = Utils.GetData($e[0], dataName);
5313
+
5314
+ // camelCase the attribute name to match the spec
5315
+ var camelDataName = dataName.replace(/-([a-z])/g, upperCaseLetter);
5316
+
5317
+ // Store the data attribute contents into the dataset since
5318
+ dataset[camelDataName] = dataValue;
5319
+ }
5320
+ }
5321
+
4991
5322
  // Prefer the element's `dataset` attribute if it exists
4992
5323
  // jQuery 1.x does not correctly handle data attributes with multiple dashes
4993
5324
  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();
5325
+ dataset = $.extend(true, {}, $e[0].dataset, dataset);
4997
5326
  }
4998
5327
 
4999
- var data = $.extend(true, {}, dataset);
5328
+ // Prefer our internal data cache if it exists
5329
+ var data = $.extend(true, {}, Utils.GetData($e[0]), dataset);
5000
5330
 
5001
5331
  data = Utils._convertData(data);
5002
5332
 
@@ -5033,8 +5363,8 @@ S2.define('select2/core',[
5033
5363
  './keys'
5034
5364
  ], function ($, Options, Utils, KEYS) {
5035
5365
  var Select2 = function ($element, options) {
5036
- if ($element.data('select2') != null) {
5037
- $element.data('select2').destroy();
5366
+ if (Utils.GetData($element[0], 'select2') != null) {
5367
+ Utils.GetData($element[0], 'select2').destroy();
5038
5368
  }
5039
5369
 
5040
5370
  this.$element = $element;
@@ -5050,7 +5380,7 @@ S2.define('select2/core',[
5050
5380
  // Set up the tabindex
5051
5381
 
5052
5382
  var tabindex = $element.attr('tabindex') || 0;
5053
- $element.data('old-tabindex', tabindex);
5383
+ Utils.StoreData($element[0], 'old-tabindex', tabindex);
5054
5384
  $element.attr('tabindex', '-1');
5055
5385
 
5056
5386
  // Set up containers and adapters
@@ -5111,6 +5441,9 @@ S2.define('select2/core',[
5111
5441
  // Synchronize any monitored attributes
5112
5442
  this._syncAttributes();
5113
5443
 
5444
+ Utils.StoreData($element[0], 'select2', this);
5445
+
5446
+ // Ensure backwards compatibility with $element.data('select2').
5114
5447
  $element.data('select2', this);
5115
5448
  };
5116
5449
 
@@ -5187,6 +5520,12 @@ S2.define('select2/core',[
5187
5520
  return null;
5188
5521
  }
5189
5522
 
5523
+ if (method == 'computedstyle') {
5524
+ var computedStyle = window.getComputedStyle($element[0]);
5525
+
5526
+ return computedStyle.width;
5527
+ }
5528
+
5190
5529
  return method;
5191
5530
  };
5192
5531
 
@@ -5227,8 +5566,8 @@ S2.define('select2/core',[
5227
5566
 
5228
5567
  if (observer != null) {
5229
5568
  this._observer = new observer(function (mutations) {
5230
- $.each(mutations, self._syncA);
5231
- $.each(mutations, self._syncS);
5569
+ self._syncA();
5570
+ self._syncS(null, mutations);
5232
5571
  });
5233
5572
  this._observer.observe(this.$element[0], {
5234
5573
  attributes: true,
@@ -5350,7 +5689,7 @@ S2.define('select2/core',[
5350
5689
  if (self.isOpen()) {
5351
5690
  if (key === KEYS.ESC || key === KEYS.TAB ||
5352
5691
  (key === KEYS.UP && evt.altKey)) {
5353
- self.close();
5692
+ self.close(evt);
5354
5693
 
5355
5694
  evt.preventDefault();
5356
5695
  } else if (key === KEYS.ENTER) {
@@ -5384,7 +5723,7 @@ S2.define('select2/core',[
5384
5723
  Select2.prototype._syncAttributes = function () {
5385
5724
  this.options.set('disabled', this.$element.prop('disabled'));
5386
5725
 
5387
- if (this.options.get('disabled')) {
5726
+ if (this.isDisabled()) {
5388
5727
  if (this.isOpen()) {
5389
5728
  this.close();
5390
5729
  }
@@ -5395,7 +5734,7 @@ S2.define('select2/core',[
5395
5734
  }
5396
5735
  };
5397
5736
 
5398
- Select2.prototype._syncSubtree = function (evt, mutations) {
5737
+ Select2.prototype._isChangeMutation = function (evt, mutations) {
5399
5738
  var changed = false;
5400
5739
  var self = this;
5401
5740
 
@@ -5423,7 +5762,22 @@ S2.define('select2/core',[
5423
5762
  }
5424
5763
  } else if (mutations.removedNodes && mutations.removedNodes.length > 0) {
5425
5764
  changed = true;
5765
+ } else if ($.isArray(mutations)) {
5766
+ $.each(mutations, function(evt, mutation) {
5767
+ if (self._isChangeMutation(evt, mutation)) {
5768
+ // We've found a change mutation.
5769
+ // Let's escape from the loop and continue
5770
+ changed = true;
5771
+ return false;
5772
+ }
5773
+ });
5426
5774
  }
5775
+ return changed;
5776
+ };
5777
+
5778
+ Select2.prototype._syncSubtree = function (evt, mutations) {
5779
+ var changed = this._isChangeMutation(evt, mutations);
5780
+ var self = this;
5427
5781
 
5428
5782
  // Only re-pull the data if we think there is a change
5429
5783
  if (changed) {
@@ -5445,7 +5799,8 @@ S2.define('select2/core',[
5445
5799
  'open': 'opening',
5446
5800
  'close': 'closing',
5447
5801
  'select': 'selecting',
5448
- 'unselect': 'unselecting'
5802
+ 'unselect': 'unselecting',
5803
+ 'clear': 'clearing'
5449
5804
  };
5450
5805
 
5451
5806
  if (args === undefined) {
@@ -5473,7 +5828,7 @@ S2.define('select2/core',[
5473
5828
  };
5474
5829
 
5475
5830
  Select2.prototype.toggleDropdown = function () {
5476
- if (this.options.get('disabled')) {
5831
+ if (this.isDisabled()) {
5477
5832
  return;
5478
5833
  }
5479
5834
 
@@ -5489,15 +5844,40 @@ S2.define('select2/core',[
5489
5844
  return;
5490
5845
  }
5491
5846
 
5847
+ if (this.isDisabled()) {
5848
+ return;
5849
+ }
5850
+
5492
5851
  this.trigger('query', {});
5493
5852
  };
5494
5853
 
5495
- Select2.prototype.close = function () {
5854
+ Select2.prototype.close = function (evt) {
5496
5855
  if (!this.isOpen()) {
5497
5856
  return;
5498
5857
  }
5499
5858
 
5500
- this.trigger('close', {});
5859
+ this.trigger('close', { originalEvent : evt });
5860
+ };
5861
+
5862
+ /**
5863
+ * Helper method to abstract the "enabled" (not "disabled") state of this
5864
+ * object.
5865
+ *
5866
+ * @return {true} if the instance is not disabled.
5867
+ * @return {false} if the instance is disabled.
5868
+ */
5869
+ Select2.prototype.isEnabled = function () {
5870
+ return !this.isDisabled();
5871
+ };
5872
+
5873
+ /**
5874
+ * Helper method to abstract the "disabled" state of this object.
5875
+ *
5876
+ * @return {true} if the disabled option is true.
5877
+ * @return {false} if the disabled option is false.
5878
+ */
5879
+ Select2.prototype.isDisabled = function () {
5880
+ return this.options.get('disabled');
5501
5881
  };
5502
5882
 
5503
5883
  Select2.prototype.isOpen = function () {
@@ -5574,7 +5954,7 @@ S2.define('select2/core',[
5574
5954
  });
5575
5955
  }
5576
5956
 
5577
- this.$element.val(newVal).trigger('change');
5957
+ this.$element.val(newVal).trigger('input').trigger('change');
5578
5958
  };
5579
5959
 
5580
5960
  Select2.prototype.destroy = function () {
@@ -5600,10 +5980,12 @@ S2.define('select2/core',[
5600
5980
  this._syncS = null;
5601
5981
 
5602
5982
  this.$element.off('.select2');
5603
- this.$element.attr('tabindex', this.$element.data('old-tabindex'));
5983
+ this.$element.attr('tabindex',
5984
+ Utils.GetData(this.$element[0], 'old-tabindex'));
5604
5985
 
5605
5986
  this.$element.removeClass('select2-hidden-accessible');
5606
5987
  this.$element.attr('aria-hidden', 'false');
5988
+ Utils.RemoveData(this.$element[0]);
5607
5989
  this.$element.removeData('select2');
5608
5990
 
5609
5991
  this.dataAdapter.destroy();
@@ -5631,7 +6013,7 @@ S2.define('select2/core',[
5631
6013
 
5632
6014
  this.$container.addClass('select2-container--' + this.options.get('theme'));
5633
6015
 
5634
- $container.data('element', this.$element);
6016
+ Utils.StoreData($container[0], 'element', this.$element);
5635
6017
 
5636
6018
  return $container;
5637
6019
  };
@@ -5841,8 +6223,9 @@ S2.define('select2/compat/initSelection',[
5841
6223
  });
5842
6224
 
5843
6225
  S2.define('select2/compat/inputData',[
5844
- 'jquery'
5845
- ], function ($) {
6226
+ 'jquery',
6227
+ '../utils'
6228
+ ], function ($, Utils) {
5846
6229
  function InputData (decorated, $element, options) {
5847
6230
  this._currentData = [];
5848
6231
  this._valueSeparator = options.get('valueSeparator') || ',';
@@ -5906,13 +6289,13 @@ S2.define('select2/compat/inputData',[
5906
6289
  });
5907
6290
 
5908
6291
  this.$element.val(data.id);
5909
- this.$element.trigger('change');
6292
+ this.$element.trigger('input').trigger('change');
5910
6293
  } else {
5911
6294
  var value = this.$element.val();
5912
6295
  value += this._valueSeparator + data.id;
5913
6296
 
5914
6297
  this.$element.val(value);
5915
- this.$element.trigger('change');
6298
+ this.$element.trigger('input').trigger('change');
5916
6299
  }
5917
6300
  };
5918
6301
 
@@ -5935,7 +6318,7 @@ S2.define('select2/compat/inputData',[
5935
6318
  }
5936
6319
 
5937
6320
  self.$element.val(values.join(self._valueSeparator));
5938
- self.$element.trigger('change');
6321
+ self.$element.trigger('input').trigger('change');
5939
6322
  });
5940
6323
  };
5941
6324
 
@@ -5959,7 +6342,7 @@ S2.define('select2/compat/inputData',[
5959
6342
 
5960
6343
  InputData.prototype.addOptions = function (_, $options) {
5961
6344
  var options = $.map($options, function ($option) {
5962
- return $.data($option[0], 'data');
6345
+ return Utils.GetData($option[0], 'data');
5963
6346
  });
5964
6347
 
5965
6348
  this._currentData.push.apply(this._currentData, options);
@@ -6362,8 +6745,9 @@ S2.define('jquery.select2',[
6362
6745
  'jquery-mousewheel',
6363
6746
 
6364
6747
  './select2/core',
6365
- './select2/defaults'
6366
- ], function ($, _, Select2, Defaults) {
6748
+ './select2/defaults',
6749
+ './select2/utils'
6750
+ ], function ($, _, Select2, Defaults, Utils) {
6367
6751
  if ($.fn.select2 == null) {
6368
6752
  // All methods that should return the element
6369
6753
  var thisMethods = ['open', 'close', 'destroy'];
@@ -6384,7 +6768,7 @@ S2.define('jquery.select2',[
6384
6768
  var args = Array.prototype.slice.call(arguments, 1);
6385
6769
 
6386
6770
  this.each(function () {
6387
- var instance = $(this).data('select2');
6771
+ var instance = Utils.GetData(this, 'select2');
6388
6772
 
6389
6773
  if (instance == null && window.console && console.error) {
6390
6774
  console.error(