select2-rails 4.0.3 → 4.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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(