select2-rails 3.5.4 → 3.5.10

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 +4 -4
  2. data/README.md +6 -6
  3. data/Rakefile +0 -1
  4. data/lib/select2-rails/engine.rb +5 -1
  5. data/lib/select2-rails/source_file.rb +13 -32
  6. data/lib/select2-rails/version.rb +1 -1
  7. data/{app → vendor}/assets/images/select2-spinner.gif +0 -0
  8. data/{app → vendor}/assets/images/select2.png +0 -0
  9. data/{app → vendor}/assets/images/select2x2.png +0 -0
  10. data/{app → vendor}/assets/javascripts/select2.js +735 -261
  11. data/vendor/assets/javascripts/select2_locale_ar.js +19 -0
  12. data/vendor/assets/javascripts/select2_locale_az.js +20 -0
  13. data/{app → vendor}/assets/javascripts/select2_locale_bg.js +12 -9
  14. data/{app → vendor}/assets/javascripts/select2_locale_ca.js +6 -4
  15. data/{app → vendor}/assets/javascripts/select2_locale_cs.js +6 -4
  16. data/{app → vendor}/assets/javascripts/select2_locale_da.js +4 -2
  17. data/{app → vendor}/assets/javascripts/select2_locale_de.js +7 -4
  18. data/{app → vendor}/assets/javascripts/select2_locale_el.js +11 -9
  19. data/{app → vendor}/assets/javascripts/select2_locale_es.js +10 -6
  20. data/{app → vendor}/assets/javascripts/select2_locale_et.js +4 -2
  21. data/{app → vendor}/assets/javascripts/select2_locale_eu.js +6 -4
  22. data/vendor/assets/javascripts/select2_locale_fa.js +21 -0
  23. data/{app → vendor}/assets/javascripts/select2_locale_fi.js +6 -4
  24. data/{app → vendor}/assets/javascripts/select2_locale_fr.js +9 -6
  25. data/{app → vendor}/assets/javascripts/select2_locale_gl.js +6 -4
  26. data/{app → vendor}/assets/javascripts/select2_locale_he.js +6 -4
  27. data/vendor/assets/javascripts/select2_locale_hr.js +24 -0
  28. data/{app → vendor}/assets/javascripts/select2_locale_hu.js +7 -5
  29. data/vendor/assets/javascripts/select2_locale_id.js +21 -0
  30. data/{app → vendor}/assets/javascripts/select2_locale_is.js +8 -7
  31. data/{app → vendor}/assets/javascripts/select2_locale_it.js +6 -4
  32. data/{app → vendor}/assets/javascripts/select2_locale_ja.js +4 -2
  33. data/vendor/assets/javascripts/select2_locale_ka.js +19 -0
  34. data/{app → vendor}/assets/javascripts/select2_locale_ko.js +6 -4
  35. data/vendor/assets/javascripts/select2_locale_lt.js +26 -0
  36. data/{app → vendor}/assets/javascripts/select2_locale_lv.js +12 -9
  37. data/{app → vendor}/assets/javascripts/select2_locale_mk.js +6 -4
  38. data/{app → vendor}/assets/javascripts/select2_locale_ms.js +8 -4
  39. data/vendor/assets/javascripts/select2_locale_nb.js +22 -0
  40. data/{app → vendor}/assets/javascripts/select2_locale_nl.js +9 -7
  41. data/{app → vendor}/assets/javascripts/select2_locale_no.js +6 -4
  42. data/vendor/assets/javascripts/select2_locale_pl.js +54 -0
  43. data/{app → vendor}/assets/javascripts/select2_locale_pt-BR.js +9 -6
  44. data/{app → vendor}/assets/javascripts/select2_locale_pt-PT.js +6 -4
  45. data/{app → vendor}/assets/javascripts/select2_locale_ro.js +6 -4
  46. data/vendor/assets/javascripts/select2_locale_rs.js +19 -0
  47. data/vendor/assets/javascripts/select2_locale_ru.js +23 -0
  48. data/{app → vendor}/assets/javascripts/select2_locale_sk.js +15 -13
  49. data/{app → vendor}/assets/javascripts/select2_locale_sv.js +6 -4
  50. data/{app → vendor}/assets/javascripts/select2_locale_th.js +6 -4
  51. data/{app → vendor}/assets/javascripts/select2_locale_tr.js +7 -4
  52. data/vendor/assets/javascripts/select2_locale_ug-CN.js +16 -0
  53. data/vendor/assets/javascripts/select2_locale_uk.js +25 -0
  54. data/{app → vendor}/assets/javascripts/select2_locale_vi.js +10 -8
  55. data/{app → vendor}/assets/javascripts/select2_locale_zh-CN.js +6 -4
  56. data/{app → vendor}/assets/javascripts/select2_locale_zh-TW.js +6 -4
  57. data/{app → vendor}/assets/stylesheets/select2-bootstrap.css +1 -1
  58. data/{app/assets/stylesheets/select2.css.erb → vendor/assets/stylesheets/select2.scss} +136 -62
  59. metadata +66 -61
  60. data/app/assets/javascripts/select2_locale_ar.js +0 -17
  61. data/app/assets/javascripts/select2_locale_fa.js +0 -17
  62. data/app/assets/javascripts/select2_locale_hr.js +0 -42
  63. data/app/assets/javascripts/select2_locale_id.js +0 -17
  64. data/app/assets/javascripts/select2_locale_lt.js +0 -29
  65. data/app/assets/javascripts/select2_locale_pl.js +0 -37
  66. data/app/assets/javascripts/select2_locale_ru.js +0 -15
  67. data/app/assets/javascripts/select2_locale_uk.js +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e3f7b9a99c762dedfa76ab00bce7f13060632ca6
4
- data.tar.gz: e5682bb1caef623ac6613d8fc252680fe81ec332
3
+ metadata.gz: 61c9e3939e4e444390089b9dacb6ac6d953df32e
4
+ data.tar.gz: 29be608e120f118cc931776616b7daf7a48f2c59
5
5
  SHA512:
6
- metadata.gz: 7929bfc1e29f1cf3c782363ca3d1951b67467c6f9beac94763a3d4d58187d7c43e8b7b966fc007e5b91767e428c67fcc0493e5b7d1763ab007c385d560ca2bee
7
- data.tar.gz: 3559db642b5b4fb60765239ce37330b49764ebc893710b217ea9277f5ae9a19f6fb326113d4d2d3b28e2e658016e0e3902dc4889046d56c107e84d3fb2820651
6
+ metadata.gz: 2bf9acdc28ff60bf0726b5eace683f32f78713b6983c53ce5cb1ff99ccb3b268870ed5c96902ecd4c7bf06e744b9884f86f6169833cb12dbe0cefc1b46fabef5
7
+ data.tar.gz: d204594781a00a38d902592087e229d5722c3b6edc69c72ae0ca5f68a523c82375f35280f9091c43c4158ca8a6694396056b21610bd2fa7dbbc9e82695dc9f60
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  #Select2 for rails asset pipeline
2
2
 
3
- [Select2](https://github.com/ivaynberg/select2) is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.
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
 
5
5
  The `select2-rails` gem integrates the `Select2` jQuery plugin with the Rails asset pipeline.
6
6
 
@@ -26,7 +26,7 @@ Add to your `app/assets/stylesheets/application.css`:
26
26
 
27
27
  *= require select2
28
28
 
29
- If you are using Twitter Boostrap you can require ethe bootstrap theme CSS
29
+ If you are using Twitter Boostrap you need to also require the bootstrap theme CSS in addition to the above require.
30
30
 
31
31
  *= require select2-bootstrap
32
32
 
@@ -40,7 +40,7 @@ Add the following to your `app/assets/javascripts/application.js`:
40
40
 
41
41
  Possible languages:
42
42
 
43
- ar, ca, cs, da, de, el, es, et, eu, fi, fr, gl, he, hr, hu, id, is, it, ja, ko, lt, lv, mk, ms, nl, no, pl, pt-BR, pt-PT, ro, ru, sk, sv, tr, uk, vi, zh-CN, zh-TW
43
+ ar, ca, cs, da, de, el, es, et, eu, fi, fr, gl, he, hr, hu, id, is, it, ja, ka, ko, lt, lv, mk, ms, nl, no, pl, pt-BR, pt-PT, ro, rs, ru, sk, sv, tr, uk, vi, zh-CN, zh-TW
44
44
 
45
45
  ## Example
46
46
  Code [here](https://github.com/argerim/select_2_example)
@@ -65,9 +65,9 @@ The last number of the version is the patch version specific to the gem. For exa
65
65
 
66
66
  If you want to contribute, please:
67
67
 
68
- * Fork the project.
69
- * Make your feature addition or bug fix.
70
- * Send me a pull request on Github.
68
+ * Fork the project.
69
+ * Make your feature addition or bug fix.
70
+ * Send me a pull request on Github.
71
71
 
72
72
  ## License
73
73
 
data/Rakefile CHANGED
@@ -7,5 +7,4 @@ task "update-select2" do
7
7
  files = SourceFile.new
8
8
  files.fetch
9
9
  files.convert
10
- files.cleanup
11
10
  end
@@ -1,6 +1,10 @@
1
1
  module Select2
2
2
  module Rails
3
3
  class Engine < ::Rails::Engine
4
+ initializer :images do |app|
5
+ app.config.assets.precompile +=
6
+ %w(select2.png select2-spinner.gif select2x2.png)
7
+ end
4
8
  end
5
9
  end
6
- end
10
+ end
@@ -9,12 +9,12 @@ class SourceFile < Thor
9
9
  def fetch
10
10
  filtered_tags = fetch_tags
11
11
  tag = select("Which tag do you want to fetch?", filtered_tags)
12
- self.destination_root = "app/assets"
13
- remote = "https://github.com/ivaynberg/select2"
12
+ self.destination_root = "vendor/assets"
13
+ remote = "https://github.com/select2/select2"
14
14
  get "#{remote}/raw/#{tag}/select2.png", "images/select2.png"
15
15
  get "#{remote}/raw/#{tag}/select2x2.png", "images/select2x2.png"
16
16
  get "#{remote}/raw/#{tag}/select2-spinner.gif", "images/select2-spinner.gif"
17
- get "#{remote}/raw/#{tag}/select2.css", "stylesheets/select2.css"
17
+ get "#{remote}/raw/#{tag}/select2.css", "stylesheets/select2.scss"
18
18
  get "#{remote}/raw/#{tag}/select2-bootstrap.css", "stylesheets/select2-bootstrap.css"
19
19
  get "#{remote}/raw/#{tag}/select2.js", "javascripts/select2.js"
20
20
  languages.each do |lang|
@@ -22,35 +22,30 @@ class SourceFile < Thor
22
22
  end
23
23
  end
24
24
 
25
- desc "convert css to css.erb file", "make css preprocess with erb"
25
+ desc "convert css to use rails paths", "make css use rails paths"
26
26
  def convert
27
- self.destination_root = "app/assets"
27
+ self.destination_root = "vendor/assets"
28
28
  inside destination_root do
29
- run("cp stylesheets/select2.css stylesheets/select2.css.erb")
30
- build_image_dependencies
31
- gsub_file 'stylesheets/select2.css.erb', %r/url\(([^\)]*)\)/, 'url(<%= asset_path(\1) %>)'
29
+ gsub_file 'stylesheets/select2.scss', %r/url\(([^\)]*)\)/, 'image-url(\1)'
32
30
  end
33
31
  end
34
32
 
35
- desc "clean up useless files", "clean up useless files"
36
- def cleanup
37
- self.destination_root = "app/assets"
38
- remove_file "stylesheets/select2.css"
39
- end
40
-
41
33
  private
42
34
 
43
35
  def fetch_tags
44
36
  http = HTTPClient.new
45
- response = JSON.parse(http.get("https://api.github.com/repos/ivaynberg/select2/tags").body)
37
+ #http.ssl_config.ssl_version = :SSLv23
38
+ response = JSON.parse(http.get("https://api.github.com/repos/select2/select2/tags").body)
46
39
  response.map{|tag| tag["name"]}.sort
47
40
  end
41
+
48
42
  def languages
49
- [ "ar", "bg", "ca", "cs", "da", "de", "el", "es", "et", "eu", "fa", "fi", "fr", "gl", "he", "hr",
50
- "hu", "id", "is", "it", "ja", "ko", "lt", "lv", "mk", "ms", "nl", "no", "pl", "pt-BR",
51
- "pt-PT", "ro", "ru", "sk", "sv", "th", "tr", "ua", "vi", "zh-CN", "zh-TW"
43
+ [ "ar", "az", "bg", "ca", "cs", "da", "de", "el", "es", "et", "eu", "fa", "fi", "fr", "gl", "he", "hr",
44
+ "hu", "id", "is", "it", "ja", "ka", "ko", "lt", "lv", "mk", "ms", "nb", "nl", "pl", "pt-BR",
45
+ "pt-PT", "ro", "rs", "ru", "sk", "sv", "th", "tr", "ug-CN", "uk", "vi", "zh-CN", "zh-TW"
52
46
  ].sort
53
47
  end
48
+
54
49
  def select msg, elements
55
50
  elements.each_with_index do |element, index|
56
51
  say(block_given? ? yield(element, index + 1) : ("#{index + 1}. #{element.to_s}"))
@@ -59,18 +54,4 @@ class SourceFile < Thor
59
54
  elements[result - 1]
60
55
  end
61
56
 
62
- def build_image_dependencies
63
- f = File.open("stylesheets/select2.css.erb", "r+")
64
- lines = f.readlines
65
- f.close
66
- lines = ["//= depend_on_asset \"select2.png\"\n"] +
67
- ["//= depend_on_asset \"select2-spinner.gif\"\n"] +
68
- ["//= depend_on_asset \"select2x2.png\"\n"] +
69
- lines
70
-
71
- output = File.new("stylesheets/select2.css.erb", "w")
72
- lines.each { |line| output.write line }
73
- output.close
74
- end
75
-
76
57
  end
@@ -1,5 +1,5 @@
1
1
  module Select2
2
2
  module Rails
3
- VERSION = "3.5.4"
3
+ VERSION = "3.5.10"
4
4
  end
5
5
  end
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  Copyright 2012 Igor Vaynberg
3
3
 
4
- Version: 3.4.5 Timestamp: Mon Nov 4 08:22:42 PST 2013
4
+ Version: 3.5.4 Timestamp: Sun Aug 30 13:30:32 EDT 2015
5
5
 
6
6
  This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
7
7
  General Public License version 2 (the "GPL License"). You may choose either license to govern your
@@ -14,7 +14,7 @@ You may obtain a copy of the Apache License and the GPL License at:
14
14
  http://www.gnu.org/licenses/gpl-2.0.html
15
15
 
16
16
  Unless required by applicable law or agreed to in writing, software distributed under the
17
- Apache License or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
17
+ Apache License or the GPL License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
18
18
  CONDITIONS OF ANY KIND, either express or implied. See the Apache License and the GPL License for
19
19
  the specific language governing permissions and limitations under the Apache License and the GPL License.
20
20
  */
@@ -46,7 +46,7 @@ the specific language governing permissions and limitations under the Apache Lic
46
46
  return;
47
47
  }
48
48
 
49
- var KEY, AbstractSelect2, SingleSelect2, MultiSelect2, nextUid, sizer,
49
+ var AbstractSelect2, SingleSelect2, MultiSelect2, nextUid, sizer,
50
50
  lastMousePosition={x:0,y:0}, $document, scrollBarDimensions,
51
51
 
52
52
  KEY = {
@@ -98,24 +98,28 @@ the specific language governing permissions and limitations under the Apache Lic
98
98
  },
99
99
  MEASURE_SCROLLBAR_TEMPLATE = "<div class='select2-measure-scrollbar'></div>",
100
100
 
101
- DIACRITICS = {"\u24B6":"A","\uFF21":"A","\u00C0":"A","\u00C1":"A","\u00C2":"A","\u1EA6":"A","\u1EA4":"A","\u1EAA":"A","\u1EA8":"A","\u00C3":"A","\u0100":"A","\u0102":"A","\u1EB0":"A","\u1EAE":"A","\u1EB4":"A","\u1EB2":"A","\u0226":"A","\u01E0":"A","\u00C4":"A","\u01DE":"A","\u1EA2":"A","\u00C5":"A","\u01FA":"A","\u01CD":"A","\u0200":"A","\u0202":"A","\u1EA0":"A","\u1EAC":"A","\u1EB6":"A","\u1E00":"A","\u0104":"A","\u023A":"A","\u2C6F":"A","\uA732":"AA","\u00C6":"AE","\u01FC":"AE","\u01E2":"AE","\uA734":"AO","\uA736":"AU","\uA738":"AV","\uA73A":"AV","\uA73C":"AY","\u24B7":"B","\uFF22":"B","\u1E02":"B","\u1E04":"B","\u1E06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24B8":"C","\uFF23":"C","\u0106":"C","\u0108":"C","\u010A":"C","\u010C":"C","\u00C7":"C","\u1E08":"C","\u0187":"C","\u023B":"C","\uA73E":"C","\u24B9":"D","\uFF24":"D","\u1E0A":"D","\u010E":"D","\u1E0C":"D","\u1E10":"D","\u1E12":"D","\u1E0E":"D","\u0110":"D","\u018B":"D","\u018A":"D","\u0189":"D","\uA779":"D","\u01F1":"DZ","\u01C4":"DZ","\u01F2":"Dz","\u01C5":"Dz","\u24BA":"E","\uFF25":"E","\u00C8":"E","\u00C9":"E","\u00CA":"E","\u1EC0":"E","\u1EBE":"E","\u1EC4":"E","\u1EC2":"E","\u1EBC":"E","\u0112":"E","\u1E14":"E","\u1E16":"E","\u0114":"E","\u0116":"E","\u00CB":"E","\u1EBA":"E","\u011A":"E","\u0204":"E","\u0206":"E","\u1EB8":"E","\u1EC6":"E","\u0228":"E","\u1E1C":"E","\u0118":"E","\u1E18":"E","\u1E1A":"E","\u0190":"E","\u018E":"E","\u24BB":"F","\uFF26":"F","\u1E1E":"F","\u0191":"F","\uA77B":"F","\u24BC":"G","\uFF27":"G","\u01F4":"G","\u011C":"G","\u1E20":"G","\u011E":"G","\u0120":"G","\u01E6":"G","\u0122":"G","\u01E4":"G","\u0193":"G","\uA7A0":"G","\uA77D":"G","\uA77E":"G","\u24BD":"H","\uFF28":"H","\u0124":"H","\u1E22":"H","\u1E26":"H","\u021E":"H","\u1E24":"H","\u1E28":"H","\u1E2A":"H","\u0126":"H","\u2C67":"H","\u2C75":"H","\uA78D":"H","\u24BE":"I","\uFF29":"I","\u00CC":"I","\u00CD":"I","\u00CE":"I","\u0128":"I","\u012A":"I","\u012C":"I","\u0130":"I","\u00CF":"I","\u1E2E":"I","\u1EC8":"I","\u01CF":"I","\u0208":"I","\u020A":"I","\u1ECA":"I","\u012E":"I","\u1E2C":"I","\u0197":"I","\u24BF":"J","\uFF2A":"J","\u0134":"J","\u0248":"J","\u24C0":"K","\uFF2B":"K","\u1E30":"K","\u01E8":"K","\u1E32":"K","\u0136":"K","\u1E34":"K","\u0198":"K","\u2C69":"K","\uA740":"K","\uA742":"K","\uA744":"K","\uA7A2":"K","\u24C1":"L","\uFF2C":"L","\u013F":"L","\u0139":"L","\u013D":"L","\u1E36":"L","\u1E38":"L","\u013B":"L","\u1E3C":"L","\u1E3A":"L","\u0141":"L","\u023D":"L","\u2C62":"L","\u2C60":"L","\uA748":"L","\uA746":"L","\uA780":"L","\u01C7":"LJ","\u01C8":"Lj","\u24C2":"M","\uFF2D":"M","\u1E3E":"M","\u1E40":"M","\u1E42":"M","\u2C6E":"M","\u019C":"M","\u24C3":"N","\uFF2E":"N","\u01F8":"N","\u0143":"N","\u00D1":"N","\u1E44":"N","\u0147":"N","\u1E46":"N","\u0145":"N","\u1E4A":"N","\u1E48":"N","\u0220":"N","\u019D":"N","\uA790":"N","\uA7A4":"N","\u01CA":"NJ","\u01CB":"Nj","\u24C4":"O","\uFF2F":"O","\u00D2":"O","\u00D3":"O","\u00D4":"O","\u1ED2":"O","\u1ED0":"O","\u1ED6":"O","\u1ED4":"O","\u00D5":"O","\u1E4C":"O","\u022C":"O","\u1E4E":"O","\u014C":"O","\u1E50":"O","\u1E52":"O","\u014E":"O","\u022E":"O","\u0230":"O","\u00D6":"O","\u022A":"O","\u1ECE":"O","\u0150":"O","\u01D1":"O","\u020C":"O","\u020E":"O","\u01A0":"O","\u1EDC":"O","\u1EDA":"O","\u1EE0":"O","\u1EDE":"O","\u1EE2":"O","\u1ECC":"O","\u1ED8":"O","\u01EA":"O","\u01EC":"O","\u00D8":"O","\u01FE":"O","\u0186":"O","\u019F":"O","\uA74A":"O","\uA74C":"O","\u01A2":"OI","\uA74E":"OO","\u0222":"OU","\u24C5":"P","\uFF30":"P","\u1E54":"P","\u1E56":"P","\u01A4":"P","\u2C63":"P","\uA750":"P","\uA752":"P","\uA754":"P","\u24C6":"Q","\uFF31":"Q","\uA756":"Q","\uA758":"Q","\u024A":"Q","\u24C7":"R","\uFF32":"R","\u0154":"R","\u1E58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1E5A":"R","\u1E5C":"R","\u0156":"R","\u1E5E":"R","\u024C":"R","\u2C64":"R","\uA75A":"R","\uA7A6":"R","\uA782":"R","\u24C8":"S","\uFF33":"S","\u1E9E":"S","\u015A":"S","\u1E64":"S","\u015C":"S","\u1E60":"S","\u0160":"S","\u1E66":"S","\u1E62":"S","\u1E68":"S","\u0218":"S","\u015E":"S","\u2C7E":"S","\uA7A8":"S","\uA784":"S","\u24C9":"T","\uFF34":"T","\u1E6A":"T","\u0164":"T","\u1E6C":"T","\u021A":"T","\u0162":"T","\u1E70":"T","\u1E6E":"T","\u0166":"T","\u01AC":"T","\u01AE":"T","\u023E":"T","\uA786":"T","\uA728":"TZ","\u24CA":"U","\uFF35":"U","\u00D9":"U","\u00DA":"U","\u00DB":"U","\u0168":"U","\u1E78":"U","\u016A":"U","\u1E7A":"U","\u016C":"U","\u00DC":"U","\u01DB":"U","\u01D7":"U","\u01D5":"U","\u01D9":"U","\u1EE6":"U","\u016E":"U","\u0170":"U","\u01D3":"U","\u0214":"U","\u0216":"U","\u01AF":"U","\u1EEA":"U","\u1EE8":"U","\u1EEE":"U","\u1EEC":"U","\u1EF0":"U","\u1EE4":"U","\u1E72":"U","\u0172":"U","\u1E76":"U","\u1E74":"U","\u0244":"U","\u24CB":"V","\uFF36":"V","\u1E7C":"V","\u1E7E":"V","\u01B2":"V","\uA75E":"V","\u0245":"V","\uA760":"VY","\u24CC":"W","\uFF37":"W","\u1E80":"W","\u1E82":"W","\u0174":"W","\u1E86":"W","\u1E84":"W","\u1E88":"W","\u2C72":"W","\u24CD":"X","\uFF38":"X","\u1E8A":"X","\u1E8C":"X","\u24CE":"Y","\uFF39":"Y","\u1EF2":"Y","\u00DD":"Y","\u0176":"Y","\u1EF8":"Y","\u0232":"Y","\u1E8E":"Y","\u0178":"Y","\u1EF6":"Y","\u1EF4":"Y","\u01B3":"Y","\u024E":"Y","\u1EFE":"Y","\u24CF":"Z","\uFF3A":"Z","\u0179":"Z","\u1E90":"Z","\u017B":"Z","\u017D":"Z","\u1E92":"Z","\u1E94":"Z","\u01B5":"Z","\u0224":"Z","\u2C7F":"Z","\u2C6B":"Z","\uA762":"Z","\u24D0":"a","\uFF41":"a","\u1E9A":"a","\u00E0":"a","\u00E1":"a","\u00E2":"a","\u1EA7":"a","\u1EA5":"a","\u1EAB":"a","\u1EA9":"a","\u00E3":"a","\u0101":"a","\u0103":"a","\u1EB1":"a","\u1EAF":"a","\u1EB5":"a","\u1EB3":"a","\u0227":"a","\u01E1":"a","\u00E4":"a","\u01DF":"a","\u1EA3":"a","\u00E5":"a","\u01FB":"a","\u01CE":"a","\u0201":"a","\u0203":"a","\u1EA1":"a","\u1EAD":"a","\u1EB7":"a","\u1E01":"a","\u0105":"a","\u2C65":"a","\u0250":"a","\uA733":"aa","\u00E6":"ae","\u01FD":"ae","\u01E3":"ae","\uA735":"ao","\uA737":"au","\uA739":"av","\uA73B":"av","\uA73D":"ay","\u24D1":"b","\uFF42":"b","\u1E03":"b","\u1E05":"b","\u1E07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24D2":"c","\uFF43":"c","\u0107":"c","\u0109":"c","\u010B":"c","\u010D":"c","\u00E7":"c","\u1E09":"c","\u0188":"c","\u023C":"c","\uA73F":"c","\u2184":"c","\u24D3":"d","\uFF44":"d","\u1E0B":"d","\u010F":"d","\u1E0D":"d","\u1E11":"d","\u1E13":"d","\u1E0F":"d","\u0111":"d","\u018C":"d","\u0256":"d","\u0257":"d","\uA77A":"d","\u01F3":"dz","\u01C6":"dz","\u24D4":"e","\uFF45":"e","\u00E8":"e","\u00E9":"e","\u00EA":"e","\u1EC1":"e","\u1EBF":"e","\u1EC5":"e","\u1EC3":"e","\u1EBD":"e","\u0113":"e","\u1E15":"e","\u1E17":"e","\u0115":"e","\u0117":"e","\u00EB":"e","\u1EBB":"e","\u011B":"e","\u0205":"e","\u0207":"e","\u1EB9":"e","\u1EC7":"e","\u0229":"e","\u1E1D":"e","\u0119":"e","\u1E19":"e","\u1E1B":"e","\u0247":"e","\u025B":"e","\u01DD":"e","\u24D5":"f","\uFF46":"f","\u1E1F":"f","\u0192":"f","\uA77C":"f","\u24D6":"g","\uFF47":"g","\u01F5":"g","\u011D":"g","\u1E21":"g","\u011F":"g","\u0121":"g","\u01E7":"g","\u0123":"g","\u01E5":"g","\u0260":"g","\uA7A1":"g","\u1D79":"g","\uA77F":"g","\u24D7":"h","\uFF48":"h","\u0125":"h","\u1E23":"h","\u1E27":"h","\u021F":"h","\u1E25":"h","\u1E29":"h","\u1E2B":"h","\u1E96":"h","\u0127":"h","\u2C68":"h","\u2C76":"h","\u0265":"h","\u0195":"hv","\u24D8":"i","\uFF49":"i","\u00EC":"i","\u00ED":"i","\u00EE":"i","\u0129":"i","\u012B":"i","\u012D":"i","\u00EF":"i","\u1E2F":"i","\u1EC9":"i","\u01D0":"i","\u0209":"i","\u020B":"i","\u1ECB":"i","\u012F":"i","\u1E2D":"i","\u0268":"i","\u0131":"i","\u24D9":"j","\uFF4A":"j","\u0135":"j","\u01F0":"j","\u0249":"j","\u24DA":"k","\uFF4B":"k","\u1E31":"k","\u01E9":"k","\u1E33":"k","\u0137":"k","\u1E35":"k","\u0199":"k","\u2C6A":"k","\uA741":"k","\uA743":"k","\uA745":"k","\uA7A3":"k","\u24DB":"l","\uFF4C":"l","\u0140":"l","\u013A":"l","\u013E":"l","\u1E37":"l","\u1E39":"l","\u013C":"l","\u1E3D":"l","\u1E3B":"l","\u017F":"l","\u0142":"l","\u019A":"l","\u026B":"l","\u2C61":"l","\uA749":"l","\uA781":"l","\uA747":"l","\u01C9":"lj","\u24DC":"m","\uFF4D":"m","\u1E3F":"m","\u1E41":"m","\u1E43":"m","\u0271":"m","\u026F":"m","\u24DD":"n","\uFF4E":"n","\u01F9":"n","\u0144":"n","\u00F1":"n","\u1E45":"n","\u0148":"n","\u1E47":"n","\u0146":"n","\u1E4B":"n","\u1E49":"n","\u019E":"n","\u0272":"n","\u0149":"n","\uA791":"n","\uA7A5":"n","\u01CC":"nj","\u24DE":"o","\uFF4F":"o","\u00F2":"o","\u00F3":"o","\u00F4":"o","\u1ED3":"o","\u1ED1":"o","\u1ED7":"o","\u1ED5":"o","\u00F5":"o","\u1E4D":"o","\u022D":"o","\u1E4F":"o","\u014D":"o","\u1E51":"o","\u1E53":"o","\u014F":"o","\u022F":"o","\u0231":"o","\u00F6":"o","\u022B":"o","\u1ECF":"o","\u0151":"o","\u01D2":"o","\u020D":"o","\u020F":"o","\u01A1":"o","\u1EDD":"o","\u1EDB":"o","\u1EE1":"o","\u1EDF":"o","\u1EE3":"o","\u1ECD":"o","\u1ED9":"o","\u01EB":"o","\u01ED":"o","\u00F8":"o","\u01FF":"o","\u0254":"o","\uA74B":"o","\uA74D":"o","\u0275":"o","\u01A3":"oi","\u0223":"ou","\uA74F":"oo","\u24DF":"p","\uFF50":"p","\u1E55":"p","\u1E57":"p","\u01A5":"p","\u1D7D":"p","\uA751":"p","\uA753":"p","\uA755":"p","\u24E0":"q","\uFF51":"q","\u024B":"q","\uA757":"q","\uA759":"q","\u24E1":"r","\uFF52":"r","\u0155":"r","\u1E59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1E5B":"r","\u1E5D":"r","\u0157":"r","\u1E5F":"r","\u024D":"r","\u027D":"r","\uA75B":"r","\uA7A7":"r","\uA783":"r","\u24E2":"s","\uFF53":"s","\u00DF":"s","\u015B":"s","\u1E65":"s","\u015D":"s","\u1E61":"s","\u0161":"s","\u1E67":"s","\u1E63":"s","\u1E69":"s","\u0219":"s","\u015F":"s","\u023F":"s","\uA7A9":"s","\uA785":"s","\u1E9B":"s","\u24E3":"t","\uFF54":"t","\u1E6B":"t","\u1E97":"t","\u0165":"t","\u1E6D":"t","\u021B":"t","\u0163":"t","\u1E71":"t","\u1E6F":"t","\u0167":"t","\u01AD":"t","\u0288":"t","\u2C66":"t","\uA787":"t","\uA729":"tz","\u24E4":"u","\uFF55":"u","\u00F9":"u","\u00FA":"u","\u00FB":"u","\u0169":"u","\u1E79":"u","\u016B":"u","\u1E7B":"u","\u016D":"u","\u00FC":"u","\u01DC":"u","\u01D8":"u","\u01D6":"u","\u01DA":"u","\u1EE7":"u","\u016F":"u","\u0171":"u","\u01D4":"u","\u0215":"u","\u0217":"u","\u01B0":"u","\u1EEB":"u","\u1EE9":"u","\u1EEF":"u","\u1EED":"u","\u1EF1":"u","\u1EE5":"u","\u1E73":"u","\u0173":"u","\u1E77":"u","\u1E75":"u","\u0289":"u","\u24E5":"v","\uFF56":"v","\u1E7D":"v","\u1E7F":"v","\u028B":"v","\uA75F":"v","\u028C":"v","\uA761":"vy","\u24E6":"w","\uFF57":"w","\u1E81":"w","\u1E83":"w","\u0175":"w","\u1E87":"w","\u1E85":"w","\u1E98":"w","\u1E89":"w","\u2C73":"w","\u24E7":"x","\uFF58":"x","\u1E8B":"x","\u1E8D":"x","\u24E8":"y","\uFF59":"y","\u1EF3":"y","\u00FD":"y","\u0177":"y","\u1EF9":"y","\u0233":"y","\u1E8F":"y","\u00FF":"y","\u1EF7":"y","\u1E99":"y","\u1EF5":"y","\u01B4":"y","\u024F":"y","\u1EFF":"y","\u24E9":"z","\uFF5A":"z","\u017A":"z","\u1E91":"z","\u017C":"z","\u017E":"z","\u1E93":"z","\u1E95":"z","\u01B6":"z","\u0225":"z","\u0240":"z","\u2C6C":"z","\uA763":"z"};
101
+ DIACRITICS = {"\u24B6":"A","\uFF21":"A","\u00C0":"A","\u00C1":"A","\u00C2":"A","\u1EA6":"A","\u1EA4":"A","\u1EAA":"A","\u1EA8":"A","\u00C3":"A","\u0100":"A","\u0102":"A","\u1EB0":"A","\u1EAE":"A","\u1EB4":"A","\u1EB2":"A","\u0226":"A","\u01E0":"A","\u00C4":"A","\u01DE":"A","\u1EA2":"A","\u00C5":"A","\u01FA":"A","\u01CD":"A","\u0200":"A","\u0202":"A","\u1EA0":"A","\u1EAC":"A","\u1EB6":"A","\u1E00":"A","\u0104":"A","\u023A":"A","\u2C6F":"A","\uA732":"AA","\u00C6":"AE","\u01FC":"AE","\u01E2":"AE","\uA734":"AO","\uA736":"AU","\uA738":"AV","\uA73A":"AV","\uA73C":"AY","\u24B7":"B","\uFF22":"B","\u1E02":"B","\u1E04":"B","\u1E06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24B8":"C","\uFF23":"C","\u0106":"C","\u0108":"C","\u010A":"C","\u010C":"C","\u00C7":"C","\u1E08":"C","\u0187":"C","\u023B":"C","\uA73E":"C","\u24B9":"D","\uFF24":"D","\u1E0A":"D","\u010E":"D","\u1E0C":"D","\u1E10":"D","\u1E12":"D","\u1E0E":"D","\u0110":"D","\u018B":"D","\u018A":"D","\u0189":"D","\uA779":"D","\u01F1":"DZ","\u01C4":"DZ","\u01F2":"Dz","\u01C5":"Dz","\u24BA":"E","\uFF25":"E","\u00C8":"E","\u00C9":"E","\u00CA":"E","\u1EC0":"E","\u1EBE":"E","\u1EC4":"E","\u1EC2":"E","\u1EBC":"E","\u0112":"E","\u1E14":"E","\u1E16":"E","\u0114":"E","\u0116":"E","\u00CB":"E","\u1EBA":"E","\u011A":"E","\u0204":"E","\u0206":"E","\u1EB8":"E","\u1EC6":"E","\u0228":"E","\u1E1C":"E","\u0118":"E","\u1E18":"E","\u1E1A":"E","\u0190":"E","\u018E":"E","\u24BB":"F","\uFF26":"F","\u1E1E":"F","\u0191":"F","\uA77B":"F","\u24BC":"G","\uFF27":"G","\u01F4":"G","\u011C":"G","\u1E20":"G","\u011E":"G","\u0120":"G","\u01E6":"G","\u0122":"G","\u01E4":"G","\u0193":"G","\uA7A0":"G","\uA77D":"G","\uA77E":"G","\u24BD":"H","\uFF28":"H","\u0124":"H","\u1E22":"H","\u1E26":"H","\u021E":"H","\u1E24":"H","\u1E28":"H","\u1E2A":"H","\u0126":"H","\u2C67":"H","\u2C75":"H","\uA78D":"H","\u24BE":"I","\uFF29":"I","\u00CC":"I","\u00CD":"I","\u00CE":"I","\u0128":"I","\u012A":"I","\u012C":"I","\u0130":"I","\u00CF":"I","\u1E2E":"I","\u1EC8":"I","\u01CF":"I","\u0208":"I","\u020A":"I","\u1ECA":"I","\u012E":"I","\u1E2C":"I","\u0197":"I","\u24BF":"J","\uFF2A":"J","\u0134":"J","\u0248":"J","\u24C0":"K","\uFF2B":"K","\u1E30":"K","\u01E8":"K","\u1E32":"K","\u0136":"K","\u1E34":"K","\u0198":"K","\u2C69":"K","\uA740":"K","\uA742":"K","\uA744":"K","\uA7A2":"K","\u24C1":"L","\uFF2C":"L","\u013F":"L","\u0139":"L","\u013D":"L","\u1E36":"L","\u1E38":"L","\u013B":"L","\u1E3C":"L","\u1E3A":"L","\u0141":"L","\u023D":"L","\u2C62":"L","\u2C60":"L","\uA748":"L","\uA746":"L","\uA780":"L","\u01C7":"LJ","\u01C8":"Lj","\u24C2":"M","\uFF2D":"M","\u1E3E":"M","\u1E40":"M","\u1E42":"M","\u2C6E":"M","\u019C":"M","\u24C3":"N","\uFF2E":"N","\u01F8":"N","\u0143":"N","\u00D1":"N","\u1E44":"N","\u0147":"N","\u1E46":"N","\u0145":"N","\u1E4A":"N","\u1E48":"N","\u0220":"N","\u019D":"N","\uA790":"N","\uA7A4":"N","\u01CA":"NJ","\u01CB":"Nj","\u24C4":"O","\uFF2F":"O","\u00D2":"O","\u00D3":"O","\u00D4":"O","\u1ED2":"O","\u1ED0":"O","\u1ED6":"O","\u1ED4":"O","\u00D5":"O","\u1E4C":"O","\u022C":"O","\u1E4E":"O","\u014C":"O","\u1E50":"O","\u1E52":"O","\u014E":"O","\u022E":"O","\u0230":"O","\u00D6":"O","\u022A":"O","\u1ECE":"O","\u0150":"O","\u01D1":"O","\u020C":"O","\u020E":"O","\u01A0":"O","\u1EDC":"O","\u1EDA":"O","\u1EE0":"O","\u1EDE":"O","\u1EE2":"O","\u1ECC":"O","\u1ED8":"O","\u01EA":"O","\u01EC":"O","\u00D8":"O","\u01FE":"O","\u0186":"O","\u019F":"O","\uA74A":"O","\uA74C":"O","\u01A2":"OI","\uA74E":"OO","\u0222":"OU","\u24C5":"P","\uFF30":"P","\u1E54":"P","\u1E56":"P","\u01A4":"P","\u2C63":"P","\uA750":"P","\uA752":"P","\uA754":"P","\u24C6":"Q","\uFF31":"Q","\uA756":"Q","\uA758":"Q","\u024A":"Q","\u24C7":"R","\uFF32":"R","\u0154":"R","\u1E58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1E5A":"R","\u1E5C":"R","\u0156":"R","\u1E5E":"R","\u024C":"R","\u2C64":"R","\uA75A":"R","\uA7A6":"R","\uA782":"R","\u24C8":"S","\uFF33":"S","\u1E9E":"S","\u015A":"S","\u1E64":"S","\u015C":"S","\u1E60":"S","\u0160":"S","\u1E66":"S","\u1E62":"S","\u1E68":"S","\u0218":"S","\u015E":"S","\u2C7E":"S","\uA7A8":"S","\uA784":"S","\u24C9":"T","\uFF34":"T","\u1E6A":"T","\u0164":"T","\u1E6C":"T","\u021A":"T","\u0162":"T","\u1E70":"T","\u1E6E":"T","\u0166":"T","\u01AC":"T","\u01AE":"T","\u023E":"T","\uA786":"T","\uA728":"TZ","\u24CA":"U","\uFF35":"U","\u00D9":"U","\u00DA":"U","\u00DB":"U","\u0168":"U","\u1E78":"U","\u016A":"U","\u1E7A":"U","\u016C":"U","\u00DC":"U","\u01DB":"U","\u01D7":"U","\u01D5":"U","\u01D9":"U","\u1EE6":"U","\u016E":"U","\u0170":"U","\u01D3":"U","\u0214":"U","\u0216":"U","\u01AF":"U","\u1EEA":"U","\u1EE8":"U","\u1EEE":"U","\u1EEC":"U","\u1EF0":"U","\u1EE4":"U","\u1E72":"U","\u0172":"U","\u1E76":"U","\u1E74":"U","\u0244":"U","\u24CB":"V","\uFF36":"V","\u1E7C":"V","\u1E7E":"V","\u01B2":"V","\uA75E":"V","\u0245":"V","\uA760":"VY","\u24CC":"W","\uFF37":"W","\u1E80":"W","\u1E82":"W","\u0174":"W","\u1E86":"W","\u1E84":"W","\u1E88":"W","\u2C72":"W","\u24CD":"X","\uFF38":"X","\u1E8A":"X","\u1E8C":"X","\u24CE":"Y","\uFF39":"Y","\u1EF2":"Y","\u00DD":"Y","\u0176":"Y","\u1EF8":"Y","\u0232":"Y","\u1E8E":"Y","\u0178":"Y","\u1EF6":"Y","\u1EF4":"Y","\u01B3":"Y","\u024E":"Y","\u1EFE":"Y","\u24CF":"Z","\uFF3A":"Z","\u0179":"Z","\u1E90":"Z","\u017B":"Z","\u017D":"Z","\u1E92":"Z","\u1E94":"Z","\u01B5":"Z","\u0224":"Z","\u2C7F":"Z","\u2C6B":"Z","\uA762":"Z","\u24D0":"a","\uFF41":"a","\u1E9A":"a","\u00E0":"a","\u00E1":"a","\u00E2":"a","\u1EA7":"a","\u1EA5":"a","\u1EAB":"a","\u1EA9":"a","\u00E3":"a","\u0101":"a","\u0103":"a","\u1EB1":"a","\u1EAF":"a","\u1EB5":"a","\u1EB3":"a","\u0227":"a","\u01E1":"a","\u00E4":"a","\u01DF":"a","\u1EA3":"a","\u00E5":"a","\u01FB":"a","\u01CE":"a","\u0201":"a","\u0203":"a","\u1EA1":"a","\u1EAD":"a","\u1EB7":"a","\u1E01":"a","\u0105":"a","\u2C65":"a","\u0250":"a","\uA733":"aa","\u00E6":"ae","\u01FD":"ae","\u01E3":"ae","\uA735":"ao","\uA737":"au","\uA739":"av","\uA73B":"av","\uA73D":"ay","\u24D1":"b","\uFF42":"b","\u1E03":"b","\u1E05":"b","\u1E07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24D2":"c","\uFF43":"c","\u0107":"c","\u0109":"c","\u010B":"c","\u010D":"c","\u00E7":"c","\u1E09":"c","\u0188":"c","\u023C":"c","\uA73F":"c","\u2184":"c","\u24D3":"d","\uFF44":"d","\u1E0B":"d","\u010F":"d","\u1E0D":"d","\u1E11":"d","\u1E13":"d","\u1E0F":"d","\u0111":"d","\u018C":"d","\u0256":"d","\u0257":"d","\uA77A":"d","\u01F3":"dz","\u01C6":"dz","\u24D4":"e","\uFF45":"e","\u00E8":"e","\u00E9":"e","\u00EA":"e","\u1EC1":"e","\u1EBF":"e","\u1EC5":"e","\u1EC3":"e","\u1EBD":"e","\u0113":"e","\u1E15":"e","\u1E17":"e","\u0115":"e","\u0117":"e","\u00EB":"e","\u1EBB":"e","\u011B":"e","\u0205":"e","\u0207":"e","\u1EB9":"e","\u1EC7":"e","\u0229":"e","\u1E1D":"e","\u0119":"e","\u1E19":"e","\u1E1B":"e","\u0247":"e","\u025B":"e","\u01DD":"e","\u24D5":"f","\uFF46":"f","\u1E1F":"f","\u0192":"f","\uA77C":"f","\u24D6":"g","\uFF47":"g","\u01F5":"g","\u011D":"g","\u1E21":"g","\u011F":"g","\u0121":"g","\u01E7":"g","\u0123":"g","\u01E5":"g","\u0260":"g","\uA7A1":"g","\u1D79":"g","\uA77F":"g","\u24D7":"h","\uFF48":"h","\u0125":"h","\u1E23":"h","\u1E27":"h","\u021F":"h","\u1E25":"h","\u1E29":"h","\u1E2B":"h","\u1E96":"h","\u0127":"h","\u2C68":"h","\u2C76":"h","\u0265":"h","\u0195":"hv","\u24D8":"i","\uFF49":"i","\u00EC":"i","\u00ED":"i","\u00EE":"i","\u0129":"i","\u012B":"i","\u012D":"i","\u00EF":"i","\u1E2F":"i","\u1EC9":"i","\u01D0":"i","\u0209":"i","\u020B":"i","\u1ECB":"i","\u012F":"i","\u1E2D":"i","\u0268":"i","\u0131":"i","\u24D9":"j","\uFF4A":"j","\u0135":"j","\u01F0":"j","\u0249":"j","\u24DA":"k","\uFF4B":"k","\u1E31":"k","\u01E9":"k","\u1E33":"k","\u0137":"k","\u1E35":"k","\u0199":"k","\u2C6A":"k","\uA741":"k","\uA743":"k","\uA745":"k","\uA7A3":"k","\u24DB":"l","\uFF4C":"l","\u0140":"l","\u013A":"l","\u013E":"l","\u1E37":"l","\u1E39":"l","\u013C":"l","\u1E3D":"l","\u1E3B":"l","\u017F":"l","\u0142":"l","\u019A":"l","\u026B":"l","\u2C61":"l","\uA749":"l","\uA781":"l","\uA747":"l","\u01C9":"lj","\u24DC":"m","\uFF4D":"m","\u1E3F":"m","\u1E41":"m","\u1E43":"m","\u0271":"m","\u026F":"m","\u24DD":"n","\uFF4E":"n","\u01F9":"n","\u0144":"n","\u00F1":"n","\u1E45":"n","\u0148":"n","\u1E47":"n","\u0146":"n","\u1E4B":"n","\u1E49":"n","\u019E":"n","\u0272":"n","\u0149":"n","\uA791":"n","\uA7A5":"n","\u01CC":"nj","\u24DE":"o","\uFF4F":"o","\u00F2":"o","\u00F3":"o","\u00F4":"o","\u1ED3":"o","\u1ED1":"o","\u1ED7":"o","\u1ED5":"o","\u00F5":"o","\u1E4D":"o","\u022D":"o","\u1E4F":"o","\u014D":"o","\u1E51":"o","\u1E53":"o","\u014F":"o","\u022F":"o","\u0231":"o","\u00F6":"o","\u022B":"o","\u1ECF":"o","\u0151":"o","\u01D2":"o","\u020D":"o","\u020F":"o","\u01A1":"o","\u1EDD":"o","\u1EDB":"o","\u1EE1":"o","\u1EDF":"o","\u1EE3":"o","\u1ECD":"o","\u1ED9":"o","\u01EB":"o","\u01ED":"o","\u00F8":"o","\u01FF":"o","\u0254":"o","\uA74B":"o","\uA74D":"o","\u0275":"o","\u01A3":"oi","\u0223":"ou","\uA74F":"oo","\u24DF":"p","\uFF50":"p","\u1E55":"p","\u1E57":"p","\u01A5":"p","\u1D7D":"p","\uA751":"p","\uA753":"p","\uA755":"p","\u24E0":"q","\uFF51":"q","\u024B":"q","\uA757":"q","\uA759":"q","\u24E1":"r","\uFF52":"r","\u0155":"r","\u1E59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1E5B":"r","\u1E5D":"r","\u0157":"r","\u1E5F":"r","\u024D":"r","\u027D":"r","\uA75B":"r","\uA7A7":"r","\uA783":"r","\u24E2":"s","\uFF53":"s","\u00DF":"s","\u015B":"s","\u1E65":"s","\u015D":"s","\u1E61":"s","\u0161":"s","\u1E67":"s","\u1E63":"s","\u1E69":"s","\u0219":"s","\u015F":"s","\u023F":"s","\uA7A9":"s","\uA785":"s","\u1E9B":"s","\u24E3":"t","\uFF54":"t","\u1E6B":"t","\u1E97":"t","\u0165":"t","\u1E6D":"t","\u021B":"t","\u0163":"t","\u1E71":"t","\u1E6F":"t","\u0167":"t","\u01AD":"t","\u0288":"t","\u2C66":"t","\uA787":"t","\uA729":"tz","\u24E4":"u","\uFF55":"u","\u00F9":"u","\u00FA":"u","\u00FB":"u","\u0169":"u","\u1E79":"u","\u016B":"u","\u1E7B":"u","\u016D":"u","\u00FC":"u","\u01DC":"u","\u01D8":"u","\u01D6":"u","\u01DA":"u","\u1EE7":"u","\u016F":"u","\u0171":"u","\u01D4":"u","\u0215":"u","\u0217":"u","\u01B0":"u","\u1EEB":"u","\u1EE9":"u","\u1EEF":"u","\u1EED":"u","\u1EF1":"u","\u1EE5":"u","\u1E73":"u","\u0173":"u","\u1E77":"u","\u1E75":"u","\u0289":"u","\u24E5":"v","\uFF56":"v","\u1E7D":"v","\u1E7F":"v","\u028B":"v","\uA75F":"v","\u028C":"v","\uA761":"vy","\u24E6":"w","\uFF57":"w","\u1E81":"w","\u1E83":"w","\u0175":"w","\u1E87":"w","\u1E85":"w","\u1E98":"w","\u1E89":"w","\u2C73":"w","\u24E7":"x","\uFF58":"x","\u1E8B":"x","\u1E8D":"x","\u24E8":"y","\uFF59":"y","\u1EF3":"y","\u00FD":"y","\u0177":"y","\u1EF9":"y","\u0233":"y","\u1E8F":"y","\u00FF":"y","\u1EF7":"y","\u1E99":"y","\u1EF5":"y","\u01B4":"y","\u024F":"y","\u1EFF":"y","\u24E9":"z","\uFF5A":"z","\u017A":"z","\u1E91":"z","\u017C":"z","\u017E":"z","\u1E93":"z","\u1E95":"z","\u01B6":"z","\u0225":"z","\u0240":"z","\u2C6C":"z","\uA763":"z","\u0386":"\u0391","\u0388":"\u0395","\u0389":"\u0397","\u038A":"\u0399","\u03AA":"\u0399","\u038C":"\u039F","\u038E":"\u03A5","\u03AB":"\u03A5","\u038F":"\u03A9","\u03AC":"\u03B1","\u03AD":"\u03B5","\u03AE":"\u03B7","\u03AF":"\u03B9","\u03CA":"\u03B9","\u0390":"\u03B9","\u03CC":"\u03BF","\u03CD":"\u03C5","\u03CB":"\u03C5","\u03B0":"\u03C5","\u03C9":"\u03C9","\u03C2":"\u03C3"};
102
102
 
103
103
  $document = $(document);
104
104
 
105
105
  nextUid=(function() { var counter=1; return function() { return counter++; }; }());
106
106
 
107
107
 
108
- function stripDiacritics(str) {
109
- var ret, i, l, c;
108
+ function reinsertElement(element) {
109
+ var placeholder = $(document.createTextNode(''));
110
110
 
111
- if (!str || str.length < 1) return str;
111
+ element.before(placeholder);
112
+ placeholder.before(element);
113
+ placeholder.remove();
114
+ }
112
115
 
113
- ret = "";
114
- for (i = 0, l = str.length; i < l; i++) {
115
- c = str.charAt(i);
116
- ret += DIACRITICS[c] || c;
116
+ function stripDiacritics(str) {
117
+ // Used 'uni range + named function' from http://jsperf.com/diacritics/18
118
+ function match(a) {
119
+ return DIACRITICS[a] || a;
117
120
  }
118
- return ret;
121
+
122
+ return str.replace(/[^\u0000-\u007E]/g, match);
119
123
  }
120
124
 
121
125
  function indexOf(value, array) {
@@ -128,7 +132,7 @@ the specific language governing permissions and limitations under the Apache Lic
128
132
 
129
133
  function measureScrollbar () {
130
134
  var $template = $( MEASURE_SCROLLBAR_TEMPLATE );
131
- $template.appendTo('body');
135
+ $template.appendTo(document.body);
132
136
 
133
137
  var dim = {
134
138
  width: $template.width() - $template[0].clientWidth,
@@ -156,16 +160,16 @@ the specific language governing permissions and limitations under the Apache Lic
156
160
  }
157
161
 
158
162
  /**
159
- * Splits the string into an array of values, trimming each value. An empty array is returned for nulls or empty
163
+ * Splits the string into an array of values, transforming each value. An empty array is returned for nulls or empty
160
164
  * strings
161
165
  * @param string
162
166
  * @param separator
163
167
  */
164
- function splitVal(string, separator) {
168
+ function splitVal(string, separator, transform) {
165
169
  var val, i, l;
166
170
  if (string === null || string.length < 1) return [];
167
171
  val = string.split(separator);
168
- for (i = 0, l = val.length; i < l; i = i + 1) val[i] = $.trim(val[i]);
172
+ for (i = 0, l = val.length; i < l; i = i + 1) val[i] = transform(val[i]);
169
173
  return val;
170
174
  }
171
175
 
@@ -189,10 +193,6 @@ the specific language governing permissions and limitations under the Apache Lic
189
193
  });
190
194
  }
191
195
 
192
- $document.on("mousemove", function (e) {
193
- lastMousePosition.x = e.pageX;
194
- lastMousePosition.y = e.pageY;
195
- });
196
196
 
197
197
  /**
198
198
  * filters mouse events so an event is fired only if the mouse moved.
@@ -230,20 +230,6 @@ the specific language governing permissions and limitations under the Apache Lic
230
230
  };
231
231
  }
232
232
 
233
- /**
234
- * A simple implementation of a thunk
235
- * @param formula function used to lazily initialize the thunk
236
- * @return {Function}
237
- */
238
- function thunk(formula) {
239
- var evaluated = false,
240
- value;
241
- return function() {
242
- if (evaluated === false) { value = formula(); evaluated = true; }
243
- return value;
244
- };
245
- };
246
-
247
233
  function installDebouncedScroll(threshold, element) {
248
234
  var notify = debounce(threshold, function (e) { element.trigger("scroll-debounced", e);});
249
235
  element.on("scroll", function (e) {
@@ -264,7 +250,8 @@ the specific language governing permissions and limitations under the Apache Lic
264
250
 
265
251
  /* make sure el received focus so we do not error out when trying to manipulate the caret.
266
252
  sometimes modals or others listeners may steal it after its set */
267
- if ($el.is(":visible") && el === document.activeElement) {
253
+ var isVisible = (el.offsetWidth > 0 || el.offsetHeight > 0);
254
+ if (isVisible && el === document.activeElement) {
268
255
 
269
256
  /* after the focus is set move the caret to the end, necessary when we val()
270
257
  just before setting focus */
@@ -324,7 +311,7 @@ the specific language governing permissions and limitations under the Apache Lic
324
311
  whiteSpace: "nowrap"
325
312
  });
326
313
  sizer.attr("class","select2-sizer");
327
- $("body").append(sizer);
314
+ $(document.body).append(sizer);
328
315
  }
329
316
  sizer.text(e.val());
330
317
  return sizer.width();
@@ -333,27 +320,34 @@ the specific language governing permissions and limitations under the Apache Lic
333
320
  function syncCssClasses(dest, src, adapter) {
334
321
  var classes, replacements = [], adapted;
335
322
 
336
- classes = dest.attr("class");
323
+ classes = $.trim(dest.attr("class"));
324
+
337
325
  if (classes) {
338
326
  classes = '' + classes; // for IE which returns object
339
- $(classes.split(" ")).each2(function() {
327
+
328
+ $(classes.split(/\s+/)).each2(function() {
340
329
  if (this.indexOf("select2-") === 0) {
341
330
  replacements.push(this);
342
331
  }
343
332
  });
344
333
  }
345
- classes = src.attr("class");
334
+
335
+ classes = $.trim(src.attr("class"));
336
+
346
337
  if (classes) {
347
338
  classes = '' + classes; // for IE which returns object
348
- $(classes.split(" ")).each2(function() {
339
+
340
+ $(classes.split(/\s+/)).each2(function() {
349
341
  if (this.indexOf("select2-") !== 0) {
350
342
  adapted = adapter(this);
343
+
351
344
  if (adapted) {
352
345
  replacements.push(adapted);
353
346
  }
354
347
  }
355
348
  });
356
349
  }
350
+
357
351
  dest.attr("class", replacements.join(" "));
358
352
  }
359
353
 
@@ -393,14 +387,14 @@ the specific language governing permissions and limitations under the Apache Lic
393
387
  /**
394
388
  * Produces an ajax-based query function
395
389
  *
396
- * @param options object containing configuration paramters
390
+ * @param options object containing configuration parameters
397
391
  * @param options.params parameter map for the transport ajax call, can contain such options as cache, jsonpCallback, etc. see $.ajax
398
392
  * @param options.transport function that will be used to execute the ajax request. must be compatible with parameters supported by $.ajax
399
393
  * @param options.url url for the data
400
394
  * @param options.data a function(searchTerm, pageNumber, context) that should return an object containing query string parameters for the above url.
401
- * @param options.dataType request data type: ajax, jsonp, other datatatypes supported by jQuery's $.ajax function or the transport function if specified
395
+ * @param options.dataType request data type: ajax, jsonp, other datatypes supported by jQuery's $.ajax function or the transport function if specified
402
396
  * @param options.quietMillis (optional) milliseconds to wait before making the ajaxRequest, helps debounce the ajax function if invoked too often
403
- * @param options.results a function(remoteData, pageNumber) that converts data returned form the remote request to the format expected by Select2.
397
+ * @param options.results a function(remoteData, pageNumber, query) that converts data returned form the remote request to the format expected by Select2.
404
398
  * The expected format is an object containing the following keys:
405
399
  * results array of objects that will be used as choices
406
400
  * more (optional) boolean indicating whether there are more results available
@@ -431,7 +425,7 @@ the specific language governing permissions and limitations under the Apache Lic
431
425
  data = data ? data.call(self, query.term, query.page, query.context) : null;
432
426
  url = (typeof url === 'function') ? url.call(self, query.term, query.page, query.context) : url;
433
427
 
434
- if (handler) { handler.abort(); }
428
+ if (handler && typeof handler.abort === "function") { handler.abort(); }
435
429
 
436
430
  if (options.params) {
437
431
  if ($.isFunction(options.params)) {
@@ -447,7 +441,18 @@ the specific language governing permissions and limitations under the Apache Lic
447
441
  data: data,
448
442
  success: function (data) {
449
443
  // TODO - replace query.page with query so users have access to term, page, etc.
450
- var results = options.results(data, query.page);
444
+ // added query as third paramter to keep backwards compatibility
445
+ var results = options.results(data, query.page, query);
446
+ query.callback(results);
447
+ },
448
+ error: function(jqXHR, textStatus, errorThrown){
449
+ var results = {
450
+ hasError: true,
451
+ jqXHR: jqXHR,
452
+ textStatus: textStatus,
453
+ errorThrown: errorThrown
454
+ };
455
+
451
456
  query.callback(results);
452
457
  }
453
458
  });
@@ -464,7 +469,7 @@ the specific language governing permissions and limitations under the Apache Lic
464
469
  *
465
470
  * If the array form is used it is assumed that it contains objects with 'id' and 'text' keys.
466
471
  *
467
- * If the object form is used ti is assumed that it contains 'data' and 'text' keys. The 'data' key should contain
472
+ * If the object form is used it is assumed that it contains 'data' and 'text' keys. The 'data' key should contain
468
473
  * an array of objects that will be used as choices. These objects must contain at least an 'id' key. The 'text'
469
474
  * key can either be a String in which case it is expected that each element in the 'data' array has a key with the
470
475
  * value of 'text' which will be used to match choices. Alternatively, text can be a function(item) that can extract
@@ -533,14 +538,17 @@ the specific language governing permissions and limitations under the Apache Lic
533
538
  var isFunc = $.isFunction(data);
534
539
  return function (query) {
535
540
  var t = query.term, filtered = {results: []};
536
- $(isFunc ? data() : data).each(function () {
537
- var isObject = this.text !== undefined,
538
- text = isObject ? this.text : this;
539
- if (t === "" || query.matcher(t, text)) {
540
- filtered.results.push(isObject ? this : {id: this, text: this});
541
- }
542
- });
543
- query.callback(filtered);
541
+ var result = isFunc ? data(query) : data;
542
+ if ($.isArray(result)) {
543
+ $(result).each(function () {
544
+ var isObject = this.text !== undefined,
545
+ text = isObject ? this.text : this;
546
+ if (t === "" || query.matcher(t, text)) {
547
+ filtered.results.push(isObject ? this : {id: this, text: this});
548
+ }
549
+ });
550
+ query.callback(filtered);
551
+ }
544
552
  };
545
553
  }
546
554
 
@@ -555,11 +563,24 @@ the specific language governing permissions and limitations under the Apache Lic
555
563
  function checkFormatter(formatter, formatterName) {
556
564
  if ($.isFunction(formatter)) return true;
557
565
  if (!formatter) return false;
558
- throw new Error(formatterName +" must be a function or a falsy value");
566
+ if (typeof(formatter) === 'string') return true;
567
+ throw new Error(formatterName +" must be a string, function, or falsy value");
559
568
  }
560
569
 
561
- function evaluate(val) {
562
- return $.isFunction(val) ? val() : val;
570
+ /**
571
+ * Returns a given value
572
+ * If given a function, returns its output
573
+ *
574
+ * @param val string|function
575
+ * @param context value of "this" to be passed to function
576
+ * @returns {*}
577
+ */
578
+ function evaluate(val, context) {
579
+ if ($.isFunction(val)) {
580
+ var args = Array.prototype.slice.call(arguments, 2);
581
+ return val.apply(context, args);
582
+ }
583
+ return val;
563
584
  }
564
585
 
565
586
  function countResults(results) {
@@ -627,6 +648,15 @@ the specific language governing permissions and limitations under the Apache Lic
627
648
  if (original!==input) return input;
628
649
  }
629
650
 
651
+ function cleanupJQueryElements() {
652
+ var self = this;
653
+
654
+ $.each(arguments, function (i, element) {
655
+ self[element].remove();
656
+ self[element] = null;
657
+ });
658
+ }
659
+
630
660
  /**
631
661
  * Creates a new class
632
662
  *
@@ -669,18 +699,31 @@ the specific language governing permissions and limitations under the Apache Lic
669
699
 
670
700
  this.container = this.createContainer();
671
701
 
702
+ this.liveRegion = $('.select2-hidden-accessible');
703
+ if (this.liveRegion.length == 0) {
704
+ this.liveRegion = $("<span>", {
705
+ role: "status",
706
+ "aria-live": "polite"
707
+ })
708
+ .addClass("select2-hidden-accessible")
709
+ .appendTo(document.body);
710
+ }
711
+
672
712
  this.containerId="s2id_"+(opts.element.attr("id") || "autogen"+nextUid());
673
- this.containerSelector="#"+this.containerId.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1');
713
+ this.containerEventName= this.containerId
714
+ .replace(/([.])/g, '_')
715
+ .replace(/([;&,\-\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1');
674
716
  this.container.attr("id", this.containerId);
675
717
 
676
- // cache the body so future lookups are cheap
677
- this.body = thunk(function() { return opts.element.closest("body"); });
718
+ this.container.attr("title", opts.element.attr("title"));
719
+
720
+ this.body = $(document.body);
678
721
 
679
722
  syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
680
723
 
681
724
  this.container.attr("style", opts.element.attr("style"));
682
- this.container.css(evaluate(opts.containerCss));
683
- this.container.addClass(evaluate(opts.containerCssClass));
725
+ this.container.css(evaluate(opts.containerCss, this.opts.element));
726
+ this.container.addClass(evaluate(opts.containerCssClass, this.opts.element));
684
727
 
685
728
  this.elementTabIndex = this.opts.element.attr("tabindex");
686
729
 
@@ -697,7 +740,7 @@ the specific language governing permissions and limitations under the Apache Lic
697
740
 
698
741
  syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass);
699
742
 
700
- this.dropdown.addClass(evaluate(opts.dropdownCssClass));
743
+ this.dropdown.addClass(evaluate(opts.dropdownCssClass, this.opts.element));
701
744
  this.dropdown.data("select2", this);
702
745
  this.dropdown.on("click", killEvent);
703
746
 
@@ -714,7 +757,23 @@ the specific language governing permissions and limitations under the Apache Lic
714
757
  this.container.on("click", killEvent);
715
758
 
716
759
  installFilteredMouseMove(this.results);
717
- this.dropdown.on("mousemove-filtered touchstart touchmove touchend", resultsSelector, this.bind(this.highlightUnderEvent));
760
+
761
+ this.dropdown.on("mousemove-filtered", resultsSelector, this.bind(this.highlightUnderEvent));
762
+ this.dropdown.on("touchstart touchmove touchend", resultsSelector, this.bind(function (event) {
763
+ this._touchEvent = true;
764
+ this.highlightUnderEvent(event);
765
+ }));
766
+ this.dropdown.on("touchmove", resultsSelector, this.bind(this.touchMoved));
767
+ this.dropdown.on("touchstart touchend", resultsSelector, this.bind(this.clearTouchMoved));
768
+
769
+ // Waiting for a click event on touch devices to select option and hide dropdown
770
+ // otherwise click will be triggered on an underlying element
771
+ this.dropdown.on('click', this.bind(function (event) {
772
+ if (this._touchEvent) {
773
+ this._touchEvent = false;
774
+ this.selectHighlighted();
775
+ }
776
+ }));
718
777
 
719
778
  installDebouncedScroll(80, this.results);
720
779
  this.dropdown.on("scroll-debounced", resultsSelector, this.bind(this.loadMoreIfNeeded));
@@ -752,7 +811,10 @@ the specific language governing permissions and limitations under the Apache Lic
752
811
  // trap all mouse events from leaving the dropdown. sometimes there may be a modal that is listening
753
812
  // for mouse events outside of itself so it can close itself. since the dropdown is now outside the select2's
754
813
  // dom it will trigger the popup close, which is not what we want
755
- this.dropdown.on("click mouseup mousedown", function (e) { e.stopPropagation(); });
814
+ // focusin can cause focus wars between modals and select2 since the dropdown is outside the modal.
815
+ this.dropdown.on("click mouseup mousedown touchstart touchend focusin", function (e) { e.stopPropagation(); });
816
+
817
+ this.lastSearchTerm = undefined;
756
818
 
757
819
  if ($.isFunction(this.opts.initSelection)) {
758
820
  // initialize selection based on the current value of the source element
@@ -782,32 +844,56 @@ the specific language governing permissions and limitations under the Apache Lic
782
844
  opts.element.prop("autofocus", false);
783
845
  if (this.autofocus) this.focus();
784
846
 
785
- this.nextSearchTerm = undefined;
847
+ this.search.attr("placeholder", opts.searchInputPlaceholder);
786
848
  },
787
849
 
788
850
  // abstract
789
851
  destroy: function () {
790
- var element=this.opts.element, select2 = element.data("select2");
852
+ var element=this.opts.element, select2 = element.data("select2"), self = this;
791
853
 
792
854
  this.close();
793
855
 
794
- if (this.propertyObserver) { delete this.propertyObserver; this.propertyObserver = null; }
856
+ if (element.length && element[0].detachEvent && self._sync) {
857
+ element.each(function () {
858
+ if (self._sync) {
859
+ this.detachEvent("onpropertychange", self._sync);
860
+ }
861
+ });
862
+ }
863
+ if (this.propertyObserver) {
864
+ this.propertyObserver.disconnect();
865
+ this.propertyObserver = null;
866
+ }
867
+ this._sync = null;
795
868
 
796
869
  if (select2 !== undefined) {
797
870
  select2.container.remove();
871
+ select2.liveRegion.remove();
798
872
  select2.dropdown.remove();
799
- element
800
- .removeClass("select2-offscreen")
801
- .removeData("select2")
802
- .off(".select2")
803
- .prop("autofocus", this.autofocus || false);
804
- if (this.elementTabIndex) {
805
- element.attr({tabindex: this.elementTabIndex});
873
+ element.removeData("select2")
874
+ .off(".select2");
875
+ if (!element.is("input[type='hidden']")) {
876
+ element
877
+ .show()
878
+ .prop("autofocus", this.autofocus || false);
879
+ if (this.elementTabIndex) {
880
+ element.attr({tabindex: this.elementTabIndex});
881
+ } else {
882
+ element.removeAttr("tabindex");
883
+ }
884
+ element.show();
806
885
  } else {
807
- element.removeAttr("tabindex");
886
+ element.css("display", "");
808
887
  }
809
- element.show();
810
888
  }
889
+
890
+ cleanupJQueryElements.call(this,
891
+ "container",
892
+ "liveRegion",
893
+ "dropdown",
894
+ "results",
895
+ "search"
896
+ );
811
897
  },
812
898
 
813
899
  // abstract
@@ -850,9 +936,158 @@ the specific language governing permissions and limitations under the Apache Lic
850
936
  });
851
937
  }
852
938
 
939
+ opts.debug = opts.debug || $.fn.select2.defaults.debug;
940
+
941
+ // Warnings for options renamed/removed in Select2 4.0.0
942
+ // Only when it's enabled through debug mode
943
+ if (opts.debug && console && console.warn) {
944
+ // id was removed
945
+ if (opts.id != null) {
946
+ console.warn(
947
+ 'Select2: The `id` option has been removed in Select2 4.0.0, ' +
948
+ 'consider renaming your `id` property or mapping the property before your data makes it to Select2. ' +
949
+ 'You can read more at https://select2.github.io/announcements-4.0.html#changed-id'
950
+ );
951
+ }
952
+
953
+ // text was removed
954
+ if (opts.text != null) {
955
+ console.warn(
956
+ 'Select2: The `text` option has been removed in Select2 4.0.0, ' +
957
+ 'consider renaming your `text` property or mapping the property before your data makes it to Select2. ' +
958
+ 'You can read more at https://select2.github.io/announcements-4.0.html#changed-id'
959
+ );
960
+ }
961
+
962
+ // sortResults was renamed to results
963
+ if (opts.sortResults != null) {
964
+ console.warn(
965
+ 'Select2: the `sortResults` option has been renamed to `sorter` in Select2 4.0.0. '
966
+ );
967
+ }
968
+
969
+ // selectOnBlur was renamed to selectOnClose
970
+ if (opts.selectOnBlur != null) {
971
+ console.warn(
972
+ 'Select2: The `selectOnBlur` option has been renamed to `selectOnClose` in Select2 4.0.0.'
973
+ );
974
+ }
975
+
976
+ // ajax.results was renamed to ajax.processResults
977
+ if (opts.ajax != null && opts.ajax.results != null) {
978
+ console.warn(
979
+ 'Select2: The `ajax.results` option has been renamed to `ajax.processResults` in Select2 4.0.0.'
980
+ );
981
+ }
982
+
983
+ // format* options were renamed to language.*
984
+ if (opts.formatNoResults != null) {
985
+ console.warn(
986
+ 'Select2: The `formatNoResults` option has been renamed to `language.noResults` in Select2 4.0.0.'
987
+ );
988
+ }
989
+ if (opts.formatSearching != null) {
990
+ console.warn(
991
+ 'Select2: The `formatSearching` option has been renamed to `language.searching` in Select2 4.0.0.'
992
+ );
993
+ }
994
+ if (opts.formatInputTooShort != null) {
995
+ console.warn(
996
+ 'Select2: The `formatInputTooShort` option has been renamed to `language.inputTooShort` in Select2 4.0.0.'
997
+ );
998
+ }
999
+ if (opts.formatInputTooLong != null) {
1000
+ console.warn(
1001
+ 'Select2: The `formatInputTooLong` option has been renamed to `language.inputTooLong` in Select2 4.0.0.'
1002
+ );
1003
+ }
1004
+ if (opts.formatLoading != null) {
1005
+ console.warn(
1006
+ 'Select2: The `formatLoading` option has been renamed to `language.loadingMore` in Select2 4.0.0.'
1007
+ );
1008
+ }
1009
+ if (opts.formatSelectionTooBig != null) {
1010
+ console.warn(
1011
+ 'Select2: The `formatSelectionTooBig` option has been renamed to `language.maximumSelected` in Select2 4.0.0.'
1012
+ );
1013
+ }
1014
+
1015
+ if (opts.element.data('select2Tags')) {
1016
+ console.warn(
1017
+ 'Select2: The `data-select2-tags` attribute has been renamed to `data-tags` in Select2 4.0.0.'
1018
+ );
1019
+ }
1020
+ }
1021
+
1022
+ // Aliasing options renamed in Select2 4.0.0
1023
+
1024
+ // data-select2-tags -> data-tags
1025
+ if (opts.element.data('tags') != null) {
1026
+ var elemTags = opts.element.data('tags');
1027
+
1028
+ // data-tags should actually be a boolean
1029
+ if (!$.isArray(elemTags)) {
1030
+ elemTags = [];
1031
+ }
1032
+
1033
+ opts.element.data('select2Tags', elemTags);
1034
+ }
1035
+
1036
+ // sortResults -> sorter
1037
+ if (opts.sorter != null) {
1038
+ opts.sortResults = opts.sorter;
1039
+ }
1040
+
1041
+ // selectOnBlur -> selectOnClose
1042
+ if (opts.selectOnClose != null) {
1043
+ opts.selectOnBlur = opts.selectOnClose;
1044
+ }
1045
+
1046
+ // ajax.results -> ajax.processResults
1047
+ if (opts.ajax != null) {
1048
+ if ($.isFunction(opts.ajax.processResults)) {
1049
+ opts.ajax.results = opts.ajax.processResults;
1050
+ }
1051
+ }
1052
+
1053
+ // Formatters/language options
1054
+ if (opts.language != null) {
1055
+ var lang = opts.language;
1056
+
1057
+ // formatNoMatches -> language.noMatches
1058
+ if ($.isFunction(lang.noMatches)) {
1059
+ opts.formatNoMatches = lang.noMatches;
1060
+ }
1061
+
1062
+ // formatSearching -> language.searching
1063
+ if ($.isFunction(lang.searching)) {
1064
+ opts.formatSearching = lang.searching;
1065
+ }
1066
+
1067
+ // formatInputTooShort -> language.inputTooShort
1068
+ if ($.isFunction(lang.inputTooShort)) {
1069
+ opts.formatInputTooShort = lang.inputTooShort;
1070
+ }
1071
+
1072
+ // formatInputTooLong -> language.inputTooLong
1073
+ if ($.isFunction(lang.inputTooLong)) {
1074
+ opts.formatInputTooLong = lang.inputTooLong;
1075
+ }
1076
+
1077
+ // formatLoading -> language.loadingMore
1078
+ if ($.isFunction(lang.loadingMore)) {
1079
+ opts.formatLoading = lang.loadingMore;
1080
+ }
1081
+
1082
+ // formatSelectionTooBig -> language.maximumSelected
1083
+ if ($.isFunction(lang.maximumSelected)) {
1084
+ opts.formatSelectionTooBig = lang.maximumSelected;
1085
+ }
1086
+ }
1087
+
853
1088
  opts = $.extend({}, {
854
1089
  populateResults: function(container, results, query) {
855
- var populate, id=this.opts.id;
1090
+ var populate, id=this.opts.id, liveRegion=this.liveRegion;
856
1091
 
857
1092
  populate=function(results, container, depth) {
858
1093
 
@@ -860,6 +1095,8 @@ the specific language governing permissions and limitations under the Apache Lic
860
1095
 
861
1096
  results = opts.sortResults(results, container, query);
862
1097
 
1098
+ // collect the created nodes for bulk append
1099
+ var nodes = [];
863
1100
  for (i = 0, l = results.length; i < l; i = i + 1) {
864
1101
 
865
1102
  result=results[i];
@@ -876,19 +1113,21 @@ the specific language governing permissions and limitations under the Apache Lic
876
1113
  if (disabled) { node.addClass("select2-disabled"); }
877
1114
  if (compound) { node.addClass("select2-result-with-children"); }
878
1115
  node.addClass(self.opts.formatResultCssClass(result));
1116
+ node.attr("role", "presentation");
879
1117
 
880
1118
  label=$(document.createElement("div"));
881
1119
  label.addClass("select2-result-label");
1120
+ label.attr("id", "select2-result-label-" + nextUid());
1121
+ label.attr("role", "option");
882
1122
 
883
1123
  formatted=opts.formatResult(result, label, query, self.opts.escapeMarkup);
884
1124
  if (formatted!==undefined) {
885
1125
  label.html(formatted);
1126
+ node.append(label);
886
1127
  }
887
1128
 
888
- node.append(label);
889
1129
 
890
1130
  if (compound) {
891
-
892
1131
  innerContainer=$("<ul></ul>");
893
1132
  innerContainer.addClass("select2-result-sub");
894
1133
  populate(result.children, innerContainer, depth+1);
@@ -896,8 +1135,12 @@ the specific language governing permissions and limitations under the Apache Lic
896
1135
  }
897
1136
 
898
1137
  node.data("select2-data", result);
899
- container.append(node);
1138
+ nodes.push(node[0]);
900
1139
  }
1140
+
1141
+ // bulk append the created nodes
1142
+ container.append(nodes);
1143
+ liveRegion.text(opts.formatMatches(results.length));
901
1144
  };
902
1145
 
903
1146
  populate(results, container, 0);
@@ -951,12 +1194,10 @@ the specific language governing permissions and limitations under the Apache Lic
951
1194
 
952
1195
  query.callback(data);
953
1196
  });
954
- // this is needed because inside val() we construct choices from options and there id is hardcoded
1197
+ // this is needed because inside val() we construct choices from options and their id is hardcoded
955
1198
  opts.id=function(e) { return e.id; };
956
- opts.formatResultCssClass = function(data) { return data.css; };
957
1199
  } else {
958
1200
  if (!("query" in opts)) {
959
-
960
1201
  if ("ajax" in opts) {
961
1202
  ajaxUrl = opts.element.data("ajax-url");
962
1203
  if (ajaxUrl && ajaxUrl.length > 0) {
@@ -973,7 +1214,7 @@ the specific language governing permissions and limitations under the Apache Lic
973
1214
  if (opts.initSelection === undefined) {
974
1215
  opts.initSelection = function (element, callback) {
975
1216
  var data = [];
976
- $(splitVal(element.val(), opts.separator)).each(function () {
1217
+ $(splitVal(element.val(), opts.separator, opts.transformVal)).each(function () {
977
1218
  var obj = { id: this, text: this },
978
1219
  tags = opts.tags;
979
1220
  if ($.isFunction(tags)) tags=tags();
@@ -991,6 +1232,16 @@ the specific language governing permissions and limitations under the Apache Lic
991
1232
  throw "query function not defined for Select2 " + opts.element.attr("id");
992
1233
  }
993
1234
 
1235
+ if (opts.createSearchChoicePosition === 'top') {
1236
+ opts.createSearchChoicePosition = function(list, item) { list.unshift(item); };
1237
+ }
1238
+ else if (opts.createSearchChoicePosition === 'bottom') {
1239
+ opts.createSearchChoicePosition = function(list, item) { list.push(item); };
1240
+ }
1241
+ else if (typeof(opts.createSearchChoicePosition) !== "function") {
1242
+ throw "invalid createSearchChoicePosition option must be 'top', 'bottom' or a custom function";
1243
+ }
1244
+
994
1245
  return opts;
995
1246
  },
996
1247
 
@@ -999,7 +1250,7 @@ the specific language governing permissions and limitations under the Apache Lic
999
1250
  */
1000
1251
  // abstract
1001
1252
  monitorSource: function () {
1002
- var el = this.opts.element, sync, observer;
1253
+ var el = this.opts.element, observer, self = this;
1003
1254
 
1004
1255
  el.on("change.select2", this.bind(function (e) {
1005
1256
  if (this.opts.element.data("select2-change-triggered") !== true) {
@@ -1007,7 +1258,7 @@ the specific language governing permissions and limitations under the Apache Lic
1007
1258
  }
1008
1259
  }));
1009
1260
 
1010
- sync = this.bind(function () {
1261
+ this._sync = this.bind(function () {
1011
1262
 
1012
1263
  // sync enabled state
1013
1264
  var disabled = el.prop("disabled");
@@ -1018,36 +1269,39 @@ the specific language governing permissions and limitations under the Apache Lic
1018
1269
  if (readonly === undefined) readonly = false;
1019
1270
  this.readonly(readonly);
1020
1271
 
1021
- syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
1022
- this.container.addClass(evaluate(this.opts.containerCssClass));
1272
+ if (this.container) {
1273
+ syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
1274
+ this.container.addClass(evaluate(this.opts.containerCssClass, this.opts.element));
1275
+ }
1023
1276
 
1024
- syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass);
1025
- this.dropdown.addClass(evaluate(this.opts.dropdownCssClass));
1277
+ if (this.dropdown) {
1278
+ syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass);
1279
+ this.dropdown.addClass(evaluate(this.opts.dropdownCssClass, this.opts.element));
1280
+ }
1026
1281
 
1027
1282
  });
1028
1283
 
1029
- // IE8-10
1030
- el.on("propertychange.select2", sync);
1031
-
1032
- // hold onto a reference of the callback to work around a chromium bug
1033
- if (this.mutationCallback === undefined) {
1034
- this.mutationCallback = function (mutations) {
1035
- mutations.forEach(sync);
1036
- }
1284
+ // IE8-10 (IE9/10 won't fire propertyChange via attachEventListener)
1285
+ if (el.length && el[0].attachEvent) {
1286
+ el.each(function() {
1287
+ this.attachEvent("onpropertychange", self._sync);
1288
+ });
1037
1289
  }
1038
1290
 
1039
1291
  // safari, chrome, firefox, IE11
1040
1292
  observer = window.MutationObserver || window.WebKitMutationObserver|| window.MozMutationObserver;
1041
1293
  if (observer !== undefined) {
1042
1294
  if (this.propertyObserver) { delete this.propertyObserver; this.propertyObserver = null; }
1043
- this.propertyObserver = new observer(this.mutationCallback);
1295
+ this.propertyObserver = new observer(function (mutations) {
1296
+ $.each(mutations, self._sync);
1297
+ });
1044
1298
  this.propertyObserver.observe(el.get(0), { attributes:true, subtree:false });
1045
1299
  }
1046
1300
  },
1047
1301
 
1048
1302
  // abstract
1049
1303
  triggerSelect: function(data) {
1050
- var evt = $.Event("select2-selecting", { val: this.id(data), object: data });
1304
+ var evt = $.Event("select2-selecting", { val: this.id(data), object: data, choice: data });
1051
1305
  this.opts.element.trigger(evt);
1052
1306
  return !evt.isDefaultPrevented();
1053
1307
  },
@@ -1069,7 +1323,7 @@ the specific language governing permissions and limitations under the Apache Lic
1069
1323
  // so here we trigger the click event manually
1070
1324
  this.opts.element.click();
1071
1325
 
1072
- // ValidationEngine ignorea the change event and listens instead to blur
1326
+ // ValidationEngine ignores the change event and listens instead to blur
1073
1327
  // so here we trigger the blur event manually if so desired
1074
1328
  if (this.opts.blurOnChange)
1075
1329
  this.opts.element.blur();
@@ -1113,25 +1367,25 @@ the specific language governing permissions and limitations under the Apache Lic
1113
1367
  // abstract
1114
1368
  readonly: function(enabled) {
1115
1369
  if (enabled === undefined) enabled = false;
1116
- if (this._readonly === enabled) return false;
1370
+ if (this._readonly === enabled) return;
1117
1371
  this._readonly = enabled;
1118
1372
 
1119
1373
  this.opts.element.prop("readonly", enabled);
1120
1374
  this.enableInterface();
1121
- return true;
1122
1375
  },
1123
1376
 
1124
1377
  // abstract
1125
1378
  opened: function () {
1126
- return this.container.hasClass("select2-dropdown-open");
1379
+ return (this.container) ? this.container.hasClass("select2-dropdown-open") : false;
1127
1380
  },
1128
1381
 
1129
1382
  // abstract
1130
1383
  positionDropdown: function() {
1131
1384
  var $dropdown = this.dropdown,
1132
- offset = this.container.offset(),
1133
- height = this.container.outerHeight(false),
1134
- width = this.container.outerWidth(false),
1385
+ container = this.container,
1386
+ offset = container.offset(),
1387
+ height = container.outerHeight(false),
1388
+ width = container.outerWidth(false),
1135
1389
  dropHeight = $dropdown.outerHeight(false),
1136
1390
  $window = $(window),
1137
1391
  windowWidth = $window.width(),
@@ -1141,9 +1395,14 @@ the specific language governing permissions and limitations under the Apache Lic
1141
1395
  dropTop = offset.top + height,
1142
1396
  dropLeft = offset.left,
1143
1397
  enoughRoomBelow = dropTop + dropHeight <= viewportBottom,
1144
- enoughRoomAbove = (offset.top - dropHeight) >= this.body().scrollTop(),
1398
+ enoughRoomAbove = (offset.top - dropHeight) >= $window.scrollTop(),
1145
1399
  dropWidth = $dropdown.outerWidth(false),
1146
- enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight,
1400
+ enoughRoomOnRight = function() {
1401
+ return dropLeft + dropWidth <= viewPortRight;
1402
+ },
1403
+ enoughRoomOnLeft = function() {
1404
+ return offset.left + viewPortRight + container.outerWidth(false) > dropWidth;
1405
+ },
1147
1406
  aboveNow = $dropdown.hasClass("select2-drop-above"),
1148
1407
  bodyOffset,
1149
1408
  above,
@@ -1178,8 +1437,10 @@ the specific language governing permissions and limitations under the Apache Lic
1178
1437
  dropTop = offset.top + height;
1179
1438
  dropLeft = offset.left;
1180
1439
  dropWidth = $dropdown.outerWidth(false);
1181
- enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight;
1182
1440
  $dropdown.show();
1441
+
1442
+ // fix so the cursor does not move to the left within the search-textbox in IE
1443
+ this.focusSearch();
1183
1444
  }
1184
1445
 
1185
1446
  if (this.opts.dropdownAutoWidth) {
@@ -1189,24 +1450,24 @@ the specific language governing permissions and limitations under the Apache Lic
1189
1450
  // Add scrollbar width to dropdown if vertical scrollbar is present
1190
1451
  dropWidth = $dropdown.outerWidth(false) + (resultsListNode.scrollHeight === resultsListNode.clientHeight ? 0 : scrollBarDimensions.width);
1191
1452
  dropWidth > width ? width = dropWidth : dropWidth = width;
1192
- enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight;
1453
+ dropHeight = $dropdown.outerHeight(false);
1193
1454
  }
1194
1455
  else {
1195
1456
  this.container.removeClass('select2-drop-auto-width');
1196
1457
  }
1197
1458
 
1198
1459
  //console.log("below/ droptop:", dropTop, "dropHeight", dropHeight, "sum", (dropTop+dropHeight)+" viewport bottom", viewportBottom, "enough?", enoughRoomBelow);
1199
- //console.log("above/ offset.top", offset.top, "dropHeight", dropHeight, "top", (offset.top-dropHeight), "scrollTop", this.body().scrollTop(), "enough?", enoughRoomAbove);
1460
+ //console.log("above/ offset.top", offset.top, "dropHeight", dropHeight, "top", (offset.top-dropHeight), "scrollTop", this.body.scrollTop(), "enough?", enoughRoomAbove);
1200
1461
 
1201
1462
  // fix positioning when body has an offset and is not position: static
1202
- if (this.body().css('position') !== 'static') {
1203
- bodyOffset = this.body().offset();
1463
+ if (this.body.css('position') !== 'static') {
1464
+ bodyOffset = this.body.offset();
1204
1465
  dropTop -= bodyOffset.top;
1205
1466
  dropLeft -= bodyOffset.left;
1206
1467
  }
1207
1468
 
1208
- if (!enoughRoomOnRight) {
1209
- dropLeft = offset.left + width - dropWidth;
1469
+ if (!enoughRoomOnRight() && enoughRoomOnLeft()) {
1470
+ dropLeft = offset.left + this.container.outerWidth(false) - dropWidth;
1210
1471
  }
1211
1472
 
1212
1473
  css = {
@@ -1215,10 +1476,11 @@ the specific language governing permissions and limitations under the Apache Lic
1215
1476
  };
1216
1477
 
1217
1478
  if (above) {
1218
- css.bottom = windowHeight - offset.top;
1219
- css.top = 'auto';
1220
1479
  this.container.addClass("select2-drop-above");
1221
1480
  $dropdown.addClass("select2-drop-above");
1481
+ dropHeight = $dropdown.outerHeight(false);
1482
+ css.top = offset.top - dropHeight;
1483
+ css.bottom = 'auto';
1222
1484
  }
1223
1485
  else {
1224
1486
  css.top = dropTop;
@@ -1226,7 +1488,7 @@ the specific language governing permissions and limitations under the Apache Lic
1226
1488
  this.container.removeClass("select2-drop-above");
1227
1489
  $dropdown.removeClass("select2-drop-above");
1228
1490
  }
1229
- css = $.extend(css, evaluate(this.opts.dropdownCss));
1491
+ css = $.extend(css, evaluate(this.opts.dropdownCss, this.opts.element));
1230
1492
 
1231
1493
  $dropdown.css(css);
1232
1494
  },
@@ -1264,6 +1526,12 @@ the specific language governing permissions and limitations under the Apache Lic
1264
1526
 
1265
1527
  this.opening();
1266
1528
 
1529
+ // Only bind the document mousemove when the dropdown is visible
1530
+ $document.on("mousemove.select2Event", function (e) {
1531
+ lastMousePosition.x = e.pageX;
1532
+ lastMousePosition.y = e.pageY;
1533
+ });
1534
+
1267
1535
  return true;
1268
1536
  },
1269
1537
 
@@ -1272,7 +1540,7 @@ the specific language governing permissions and limitations under the Apache Lic
1272
1540
  */
1273
1541
  // abstract
1274
1542
  opening: function() {
1275
- var cid = this.containerId,
1543
+ var cid = this.containerEventName,
1276
1544
  scroll = "scroll." + cid,
1277
1545
  resize = "resize."+cid,
1278
1546
  orient = "orientationchange."+cid,
@@ -1282,25 +1550,28 @@ the specific language governing permissions and limitations under the Apache Lic
1282
1550
 
1283
1551
  this.clearDropdownAlignmentPreference();
1284
1552
 
1285
- if(this.dropdown[0] !== this.body().children().last()[0]) {
1286
- this.dropdown.detach().appendTo(this.body());
1553
+ if(this.dropdown[0] !== this.body.children().last()[0]) {
1554
+ this.dropdown.detach().appendTo(this.body);
1287
1555
  }
1288
1556
 
1289
- // create the dropdown mask if doesnt already exist
1557
+ // create the dropdown mask if doesn't already exist
1290
1558
  mask = $("#select2-drop-mask");
1291
- if (mask.length == 0) {
1559
+ if (mask.length === 0) {
1292
1560
  mask = $(document.createElement("div"));
1293
1561
  mask.attr("id","select2-drop-mask").attr("class","select2-drop-mask");
1294
1562
  mask.hide();
1295
- mask.appendTo(this.body());
1563
+ mask.appendTo(this.body);
1296
1564
  mask.on("mousedown touchstart click", function (e) {
1565
+ // Prevent IE from generating a click event on the body
1566
+ reinsertElement(mask);
1567
+
1297
1568
  var dropdown = $("#select2-drop"), self;
1298
1569
  if (dropdown.length > 0) {
1299
1570
  self=dropdown.data("select2");
1300
1571
  if (self.opts.selectOnBlur) {
1301
1572
  self.selectHighlighted({noFocus: true});
1302
1573
  }
1303
- self.close({focus:true});
1574
+ self.close();
1304
1575
  e.preventDefault();
1305
1576
  e.stopPropagation();
1306
1577
  }
@@ -1330,7 +1601,7 @@ the specific language governing permissions and limitations under the Apache Lic
1330
1601
  var that = this;
1331
1602
  this.container.parents().add(window).each(function () {
1332
1603
  $(this).on(resize+" "+scroll+" "+orient, function (e) {
1333
- that.positionDropdown();
1604
+ if (that.opened()) that.positionDropdown();
1334
1605
  });
1335
1606
  });
1336
1607
 
@@ -1341,7 +1612,7 @@ the specific language governing permissions and limitations under the Apache Lic
1341
1612
  close: function () {
1342
1613
  if (!this.opened()) return;
1343
1614
 
1344
- var cid = this.containerId,
1615
+ var cid = this.containerEventName,
1345
1616
  scroll = "scroll." + cid,
1346
1617
  resize = "resize."+cid,
1347
1618
  orient = "orientationchange."+cid;
@@ -1357,9 +1628,14 @@ the specific language governing permissions and limitations under the Apache Lic
1357
1628
  this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active");
1358
1629
  this.results.empty();
1359
1630
 
1631
+ // Now that the dropdown is closed, unbind the global document mousemove event
1632
+ $document.off("mousemove.select2Event");
1360
1633
 
1361
1634
  this.clearSearch();
1362
1635
  this.search.removeClass("select2-active");
1636
+
1637
+ // Remove the aria active descendant for highlighted element
1638
+ this.search.removeAttr("aria-activedescendant");
1363
1639
  this.opts.element.trigger($.Event("select2-close"));
1364
1640
  },
1365
1641
 
@@ -1378,14 +1654,35 @@ the specific language governing permissions and limitations under the Apache Lic
1378
1654
 
1379
1655
  },
1380
1656
 
1657
+ /**
1658
+ * @return {Boolean} Whether or not search value was changed.
1659
+ * @private
1660
+ */
1661
+ prefillNextSearchTerm: function () {
1662
+ // initializes search's value with nextSearchTerm (if defined by user)
1663
+ // ignore nextSearchTerm if the dropdown is opened by the user pressing a letter
1664
+ if(this.search.val() !== "") {
1665
+ return false;
1666
+ }
1667
+
1668
+ var nextSearchTerm = this.opts.nextSearchTerm(this.data(), this.lastSearchTerm);
1669
+ if(nextSearchTerm !== undefined){
1670
+ this.search.val(nextSearchTerm);
1671
+ this.search.select();
1672
+ return true;
1673
+ }
1674
+
1675
+ return false;
1676
+ },
1677
+
1381
1678
  //abstract
1382
1679
  getMaximumSelectionSize: function() {
1383
- return evaluate(this.opts.maximumSelectionSize);
1680
+ return evaluate(this.opts.maximumSelectionSize, this.opts.element);
1384
1681
  },
1385
1682
 
1386
1683
  // abstract
1387
1684
  ensureHighlightVisible: function () {
1388
- var results = this.results, children, index, child, hb, rb, y, more;
1685
+ var results = this.results, children, index, child, hb, rb, y, more, topOffset;
1389
1686
 
1390
1687
  index = this.highlight();
1391
1688
 
@@ -1405,7 +1702,9 @@ the specific language governing permissions and limitations under the Apache Lic
1405
1702
 
1406
1703
  child = $(children[index]);
1407
1704
 
1408
- hb = child.offset().top + child.outerHeight(true);
1705
+ topOffset = (child.offset() || {}).top || 0;
1706
+
1707
+ hb = topOffset + child.outerHeight(true);
1409
1708
 
1410
1709
  // if this is the last child lets also make sure select2-more-results is visible
1411
1710
  if (index === children.length - 1) {
@@ -1415,11 +1714,11 @@ the specific language governing permissions and limitations under the Apache Lic
1415
1714
  }
1416
1715
  }
1417
1716
 
1418
- rb = results.offset().top + results.outerHeight(true);
1717
+ rb = results.offset().top + results.outerHeight(false);
1419
1718
  if (hb > rb) {
1420
1719
  results.scrollTop(results.scrollTop() + (hb - rb));
1421
1720
  }
1422
- y = child.offset().top - results.offset().top;
1721
+ y = topOffset - results.offset().top;
1423
1722
 
1424
1723
  // make sure the top of the element is visible
1425
1724
  if (y < 0 && child.css('display') != 'none' ) {
@@ -1429,7 +1728,7 @@ the specific language governing permissions and limitations under the Apache Lic
1429
1728
 
1430
1729
  // abstract
1431
1730
  findHighlightableChoices: function() {
1432
- return this.results.find(".select2-result-selectable:not(.select2-disabled, .select2-selected)");
1731
+ return this.results.find(".select2-result-selectable:not(.select2-disabled):not(.select2-selected)");
1433
1732
  },
1434
1733
 
1435
1734
  // abstract
@@ -1465,8 +1764,13 @@ the specific language governing permissions and limitations under the Apache Lic
1465
1764
  choice = $(choices[index]);
1466
1765
  choice.addClass("select2-highlighted");
1467
1766
 
1767
+ // ensure assistive technology can determine the active choice
1768
+ this.search.attr("aria-activedescendant", choice.find(".select2-result-label").attr("id"));
1769
+
1468
1770
  this.ensureHighlightVisible();
1469
1771
 
1772
+ this.liveRegion.text(choice.text());
1773
+
1470
1774
  data = choice.data("select2-data");
1471
1775
  if (data) {
1472
1776
  this.opts.element.trigger({ type: "select2-highlight", val: this.id(data), choice: data });
@@ -1477,6 +1781,14 @@ the specific language governing permissions and limitations under the Apache Lic
1477
1781
  this.results.find(".select2-highlighted").removeClass("select2-highlighted");
1478
1782
  },
1479
1783
 
1784
+ touchMoved: function() {
1785
+ this._touchMoved = true;
1786
+ },
1787
+
1788
+ clearTouchMoved: function() {
1789
+ this._touchMoved = false;
1790
+ },
1791
+
1480
1792
  // abstract
1481
1793
  countSelectableResults: function() {
1482
1794
  return this.findHighlightableChoices().length;
@@ -1525,7 +1837,7 @@ the specific language governing permissions and limitations under the Apache Lic
1525
1837
  self.postprocessResults(data, false, false);
1526
1838
 
1527
1839
  if (data.more===true) {
1528
- more.detach().appendTo(results).text(self.opts.formatLoadMore(page+1));
1840
+ more.detach().appendTo(results).html(self.opts.escapeMarkup(evaluate(self.opts.formatLoadMore, self.opts.element, page+1)));
1529
1841
  window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10);
1530
1842
  } else {
1531
1843
  more.remove();
@@ -1574,6 +1886,12 @@ the specific language governing permissions and limitations under the Apache Lic
1574
1886
  function postRender() {
1575
1887
  search.removeClass("select2-active");
1576
1888
  self.positionDropdown();
1889
+ if (results.find('.select2-no-results,.select2-selection-limit,.select2-searching').length) {
1890
+ self.liveRegion.text(results.text());
1891
+ }
1892
+ else {
1893
+ self.liveRegion.text(self.opts.formatMatches(results.find('.select2-result-selectable:not(".select2-selected")').length));
1894
+ }
1577
1895
  }
1578
1896
 
1579
1897
  function render(html) {
@@ -1587,14 +1905,14 @@ the specific language governing permissions and limitations under the Apache Lic
1587
1905
  if (maxSelSize >=1) {
1588
1906
  data = this.data();
1589
1907
  if ($.isArray(data) && data.length >= maxSelSize && checkFormatter(opts.formatSelectionTooBig, "formatSelectionTooBig")) {
1590
- render("<li class='select2-selection-limit'>" + opts.formatSelectionTooBig(maxSelSize) + "</li>");
1908
+ render("<li class='select2-selection-limit'>" + evaluate(opts.formatSelectionTooBig, opts.element, maxSelSize) + "</li>");
1591
1909
  return;
1592
1910
  }
1593
1911
  }
1594
1912
 
1595
1913
  if (search.val().length < opts.minimumInputLength) {
1596
1914
  if (checkFormatter(opts.formatInputTooShort, "formatInputTooShort")) {
1597
- render("<li class='select2-no-results'>" + opts.formatInputTooShort(search.val(), opts.minimumInputLength) + "</li>");
1915
+ render("<li class='select2-no-results'>" + evaluate(opts.formatInputTooShort, opts.element, search.val(), opts.minimumInputLength) + "</li>");
1598
1916
  } else {
1599
1917
  render("");
1600
1918
  }
@@ -1604,7 +1922,7 @@ the specific language governing permissions and limitations under the Apache Lic
1604
1922
 
1605
1923
  if (opts.maximumInputLength && search.val().length > opts.maximumInputLength) {
1606
1924
  if (checkFormatter(opts.formatInputTooLong, "formatInputTooLong")) {
1607
- render("<li class='select2-no-results'>" + opts.formatInputTooLong(search.val(), opts.maximumInputLength) + "</li>");
1925
+ render("<li class='select2-no-results'>" + evaluate(opts.formatInputTooLong, opts.element, search.val(), opts.maximumInputLength) + "</li>");
1608
1926
  } else {
1609
1927
  render("");
1610
1928
  }
@@ -1612,7 +1930,7 @@ the specific language governing permissions and limitations under the Apache Lic
1612
1930
  }
1613
1931
 
1614
1932
  if (opts.formatSearching && this.findHighlightableChoices().length === 0) {
1615
- render("<li class='select2-searching'>" + opts.formatSearching() + "</li>");
1933
+ render("<li class='select2-searching'>" + evaluate(opts.formatSearching, opts.element) + "</li>");
1616
1934
  }
1617
1935
 
1618
1936
  search.addClass("select2-active");
@@ -1647,6 +1965,12 @@ the specific language governing permissions and limitations under the Apache Lic
1647
1965
  return;
1648
1966
  }
1649
1967
 
1968
+ // handle ajax error
1969
+ if(data.hasError !== undefined && checkFormatter(opts.formatAjaxError, "formatAjaxError")) {
1970
+ render("<li class='select2-ajax-error'>" + evaluate(opts.formatAjaxError, opts.element, data.jqXHR, data.textStatus, data.errorThrown) + "</li>");
1971
+ return;
1972
+ }
1973
+
1650
1974
  // save context, if any
1651
1975
  this.context = (data.context===undefined) ? null : data.context;
1652
1976
  // create a default choice and prepend it to the list
@@ -1657,13 +1981,16 @@ the specific language governing permissions and limitations under the Apache Lic
1657
1981
  function () {
1658
1982
  return equal(self.id(this), self.id(def));
1659
1983
  }).length === 0) {
1660
- data.results.unshift(def);
1984
+ this.opts.createSearchChoicePosition(data.results, def);
1661
1985
  }
1662
1986
  }
1663
1987
  }
1664
1988
 
1665
1989
  if (data.results.length === 0 && checkFormatter(opts.formatNoMatches, "formatNoMatches")) {
1666
- render("<li class='select2-no-results'>" + opts.formatNoMatches(search.val()) + "</li>");
1990
+ render("<li class='select2-no-results'>" + evaluate(opts.formatNoMatches, opts.element, search.val()) + "</li>");
1991
+ if(this.showSearch){
1992
+ this.showSearch(search.val());
1993
+ }
1667
1994
  return;
1668
1995
  }
1669
1996
 
@@ -1671,7 +1998,7 @@ the specific language governing permissions and limitations under the Apache Lic
1671
1998
  self.opts.populateResults.call(this, results, data.results, {term: search.val(), page: this.resultsPage, context:null});
1672
1999
 
1673
2000
  if (data.more === true && checkFormatter(opts.formatLoadMore, "formatLoadMore")) {
1674
- results.append("<li class='select2-more-results'>" + self.opts.escapeMarkup(opts.formatLoadMore(this.resultsPage)) + "</li>");
2001
+ results.append("<li class='select2-more-results'>" + opts.escapeMarkup(evaluate(opts.formatLoadMore, opts.element, this.resultsPage)) + "</li>");
1675
2002
  window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10);
1676
2003
  }
1677
2004
 
@@ -1709,6 +2036,10 @@ the specific language governing permissions and limitations under the Apache Lic
1709
2036
 
1710
2037
  // abstract
1711
2038
  selectHighlighted: function (options) {
2039
+ if (this._touchMoved) {
2040
+ this.clearTouchMoved();
2041
+ return;
2042
+ }
1712
2043
  var index=this.highlight(),
1713
2044
  highlighted=this.results.find(".select2-highlighted"),
1714
2045
  data = highlighted.closest('.select2-result').data("select2-data");
@@ -1739,7 +2070,7 @@ the specific language governing permissions and limitations under the Apache Lic
1739
2070
  //Determine the placeholder option based on the specified placeholderOption setting
1740
2071
  return (this.opts.placeholderOption === "first" && firstOption) ||
1741
2072
  (typeof this.opts.placeholderOption === "function" && this.opts.placeholderOption(this.select));
1742
- } else if (firstOption.text() === "" && firstOption.val() === "") {
2073
+ } else if ($.trim(firstOption.text()) === "" && firstOption.val() === "") {
1743
2074
  //No explicit placeholder option specified, use the first if it's blank
1744
2075
  return firstOption;
1745
2076
  }
@@ -1764,7 +2095,7 @@ the specific language governing permissions and limitations under the Apache Lic
1764
2095
  } else if (this.opts.width === "copy" || this.opts.width === "resolve") {
1765
2096
  // check if there is inline style on the element that contains width
1766
2097
  style = this.opts.element.attr('style');
1767
- if (style !== undefined) {
2098
+ if (typeof(style) === "string") {
1768
2099
  attrs = style.split(';');
1769
2100
  for (i = 0, l = attrs.length; i < l; i = i + 1) {
1770
2101
  attr = attrs[i].replace(/\s/g, '');
@@ -1807,16 +2138,19 @@ the specific language governing permissions and limitations under the Apache Lic
1807
2138
  var container = $(document.createElement("div")).attr({
1808
2139
  "class": "select2-container"
1809
2140
  }).html([
1810
- "<a href='javascript:void(0)' onclick='return false;' class='select2-choice' tabindex='-1'>",
1811
- " <span class='select2-chosen'>&nbsp;</span><abbr class='select2-search-choice-close'></abbr>",
1812
- " <span class='select2-arrow'><b></b></span>",
2141
+ "<a href='javascript:void(0)' class='select2-choice' tabindex='-1'>",
2142
+ " <span class='select2-chosen'>&#160;</span><abbr class='select2-search-choice-close'></abbr>",
2143
+ " <span class='select2-arrow' role='presentation'><b role='presentation'></b></span>",
1813
2144
  "</a>",
1814
- "<input class='select2-focusser select2-offscreen' type='text'/>",
2145
+ "<label for='' class='select2-offscreen'></label>",
2146
+ "<input class='select2-focusser select2-offscreen' type='text' aria-haspopup='true' role='button' />",
1815
2147
  "<div class='select2-drop select2-display-none'>",
1816
2148
  " <div class='select2-search'>",
1817
- " <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'/>",
2149
+ " <label for='' class='select2-offscreen'></label>",
2150
+ " <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input' role='combobox' aria-expanded='true'",
2151
+ " aria-autocomplete='list' />",
1818
2152
  " </div>",
1819
- " <ul class='select2-results'>",
2153
+ " <ul class='select2-results' role='listbox'>",
1820
2154
  " </ul>",
1821
2155
  "</div>"].join(""));
1822
2156
  return container;
@@ -1845,42 +2179,36 @@ the specific language governing permissions and limitations under the Apache Lic
1845
2179
 
1846
2180
  this.search.val(this.focusser.val());
1847
2181
  }
1848
- this.search.focus();
1849
- // move the cursor to the end after focussing, otherwise it will be at the beginning and
1850
- // new text will appear *before* focusser.val()
1851
- el = this.search.get(0);
1852
- if (el.createTextRange) {
1853
- range = el.createTextRange();
1854
- range.collapse(false);
1855
- range.select();
1856
- } else if (el.setSelectionRange) {
1857
- len = this.search.val().length;
1858
- el.setSelectionRange(len, len);
1859
- }
1860
-
1861
- // initializes search's value with nextSearchTerm (if defined by user)
1862
- // ignore nextSearchTerm if the dropdown is opened by the user pressing a letter
1863
- if(this.search.val() === "") {
1864
- if(this.nextSearchTerm != undefined){
1865
- this.search.val(this.nextSearchTerm);
1866
- this.search.select();
2182
+ if (this.opts.shouldFocusInput(this)) {
2183
+ this.search.focus();
2184
+ // move the cursor to the end after focussing, otherwise it will be at the beginning and
2185
+ // new text will appear *before* focusser.val()
2186
+ el = this.search.get(0);
2187
+ if (el.createTextRange) {
2188
+ range = el.createTextRange();
2189
+ range.collapse(false);
2190
+ range.select();
2191
+ } else if (el.setSelectionRange) {
2192
+ len = this.search.val().length;
2193
+ el.setSelectionRange(len, len);
1867
2194
  }
1868
2195
  }
1869
2196
 
2197
+ this.prefillNextSearchTerm();
2198
+
1870
2199
  this.focusser.prop("disabled", true).val("");
1871
2200
  this.updateResults(true);
1872
2201
  this.opts.element.trigger($.Event("select2-open"));
1873
2202
  },
1874
2203
 
1875
2204
  // single
1876
- close: function (params) {
2205
+ close: function () {
1877
2206
  if (!this.opened()) return;
1878
2207
  this.parent.close.apply(this, arguments);
1879
2208
 
1880
- params = params || {focus: true};
1881
- this.focusser.removeAttr("disabled");
2209
+ this.focusser.prop("disabled", false);
1882
2210
 
1883
- if (params.focus) {
2211
+ if (this.opts.shouldFocusInput(this)) {
1884
2212
  this.focusser.focus();
1885
2213
  }
1886
2214
  },
@@ -1890,8 +2218,10 @@ the specific language governing permissions and limitations under the Apache Lic
1890
2218
  if (this.opened()) {
1891
2219
  this.close();
1892
2220
  } else {
1893
- this.focusser.removeAttr("disabled");
1894
- this.focusser.focus();
2221
+ this.focusser.prop("disabled", false);
2222
+ if (this.opts.shouldFocusInput(this)) {
2223
+ this.focusser.focus();
2224
+ }
1895
2225
  }
1896
2226
  },
1897
2227
 
@@ -1903,8 +2233,11 @@ the specific language governing permissions and limitations under the Apache Lic
1903
2233
  // single
1904
2234
  cancel: function () {
1905
2235
  this.parent.cancel.apply(this, arguments);
1906
- this.focusser.removeAttr("disabled");
1907
- this.focusser.focus();
2236
+ this.focusser.prop("disabled", false);
2237
+
2238
+ if (this.opts.shouldFocusInput(this)) {
2239
+ this.focusser.focus();
2240
+ }
1908
2241
  },
1909
2242
 
1910
2243
  // single
@@ -1912,6 +2245,11 @@ the specific language governing permissions and limitations under the Apache Lic
1912
2245
  $("label[for='" + this.focusser.attr('id') + "']")
1913
2246
  .attr('for', this.opts.element.attr("id"));
1914
2247
  this.parent.destroy.apply(this, arguments);
2248
+
2249
+ cleanupJQueryElements.call(this,
2250
+ "selection",
2251
+ "focusser"
2252
+ );
1915
2253
  },
1916
2254
 
1917
2255
  // single
@@ -1919,7 +2257,9 @@ the specific language governing permissions and limitations under the Apache Lic
1919
2257
 
1920
2258
  var selection,
1921
2259
  container = this.container,
1922
- dropdown = this.dropdown;
2260
+ dropdown = this.dropdown,
2261
+ idSuffix = nextUid(),
2262
+ elementLabel;
1923
2263
 
1924
2264
  if (this.opts.minimumResultsForSearch < 0) {
1925
2265
  this.showSearch(false);
@@ -1931,17 +2271,41 @@ the specific language governing permissions and limitations under the Apache Lic
1931
2271
 
1932
2272
  this.focusser = container.find(".select2-focusser");
1933
2273
 
2274
+ // add aria associations
2275
+ selection.find(".select2-chosen").attr("id", "select2-chosen-"+idSuffix);
2276
+ this.focusser.attr("aria-labelledby", "select2-chosen-"+idSuffix);
2277
+ this.results.attr("id", "select2-results-"+idSuffix);
2278
+ this.search.attr("aria-owns", "select2-results-"+idSuffix);
2279
+
1934
2280
  // rewrite labels from original element to focusser
1935
- this.focusser.attr("id", "s2id_autogen"+nextUid());
2281
+ this.focusser.attr("id", "s2id_autogen"+idSuffix);
1936
2282
 
1937
- $("label[for='" + this.opts.element.attr("id") + "']")
2283
+ elementLabel = $("label[for='" + this.opts.element.attr("id") + "']");
2284
+ this.opts.element.on('focus.select2', this.bind(function () { this.focus(); }));
2285
+
2286
+ this.focusser.prev()
2287
+ .text(elementLabel.text())
1938
2288
  .attr('for', this.focusser.attr('id'));
1939
2289
 
2290
+ // Ensure the original element retains an accessible name
2291
+ var originalTitle = this.opts.element.attr("title");
2292
+ this.opts.element.attr("title", (originalTitle || elementLabel.text()));
2293
+
1940
2294
  this.focusser.attr("tabindex", this.elementTabIndex);
1941
2295
 
2296
+ // write label for search field using the label from the focusser element
2297
+ this.search.attr("id", this.focusser.attr('id') + '_search');
2298
+
2299
+ this.search.prev()
2300
+ .text($("label[for='" + this.focusser.attr('id') + "']").text())
2301
+ .attr('for', this.search.attr('id'));
2302
+
1942
2303
  this.search.on("keydown", this.bind(function (e) {
1943
2304
  if (!this.isInterfaceEnabled()) return;
1944
2305
 
2306
+ // filter 229 keyCodes (input method editor is processing key input)
2307
+ if (229 == e.keyCode) return;
2308
+
1945
2309
  if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) {
1946
2310
  // prevent the page from scrolling
1947
2311
  killEvent(e);
@@ -1971,9 +2335,11 @@ the specific language governing permissions and limitations under the Apache Lic
1971
2335
  this.search.on("blur", this.bind(function(e) {
1972
2336
  // a workaround for chrome to keep the search field focussed when the scroll bar is used to scroll the dropdown.
1973
2337
  // without this the search field loses focus which is annoying
1974
- if (document.activeElement === this.body().get(0)) {
2338
+ if (document.activeElement === this.body.get(0)) {
1975
2339
  window.setTimeout(this.bind(function() {
1976
- this.search.focus();
2340
+ if (this.opened() && this.results && this.results.length > 1) {
2341
+ this.search.focus();
2342
+ }
1977
2343
  }), 0);
1978
2344
  }
1979
2345
  }));
@@ -2019,15 +2385,23 @@ the specific language governing permissions and limitations under the Apache Lic
2019
2385
  }
2020
2386
  }));
2021
2387
 
2022
- selection.on("mousedown", "abbr", this.bind(function (e) {
2023
- if (!this.isInterfaceEnabled()) return;
2388
+ selection.on("mousedown touchstart", "abbr", this.bind(function (e) {
2389
+ if (!this.isInterfaceEnabled()) {
2390
+ return;
2391
+ }
2392
+
2024
2393
  this.clear();
2025
2394
  killEventImmediately(e);
2026
2395
  this.close();
2027
- this.selection.focus();
2396
+
2397
+ if (this.selection) {
2398
+ this.selection.focus();
2399
+ }
2028
2400
  }));
2029
2401
 
2030
- selection.on("mousedown", this.bind(function (e) {
2402
+ selection.on("mousedown touchstart", this.bind(function (e) {
2403
+ // Prevent IE from generating a click event on the body
2404
+ reinsertElement(selection);
2031
2405
 
2032
2406
  if (!this.container.hasClass("select2-container-active")) {
2033
2407
  this.opts.element.trigger($.Event("select2-focus"));
@@ -2042,7 +2416,11 @@ the specific language governing permissions and limitations under the Apache Lic
2042
2416
  killEvent(e);
2043
2417
  }));
2044
2418
 
2045
- dropdown.on("mousedown", this.bind(function() { this.search.focus(); }));
2419
+ dropdown.on("mousedown touchstart", this.bind(function() {
2420
+ if (this.opts.shouldFocusInput(this)) {
2421
+ this.search.focus();
2422
+ }
2423
+ }));
2046
2424
 
2047
2425
  selection.on("focus", this.bind(function(e) {
2048
2426
  killEvent(e);
@@ -2067,7 +2445,7 @@ the specific language governing permissions and limitations under the Apache Lic
2067
2445
  }));
2068
2446
 
2069
2447
  this.initContainerWidth();
2070
- this.opts.element.addClass("select2-offscreen");
2448
+ this.opts.element.hide();
2071
2449
  this.setPlaceholder();
2072
2450
 
2073
2451
  },
@@ -2111,6 +2489,7 @@ the specific language governing permissions and limitations under the Apache Lic
2111
2489
  self.updateSelection(selected);
2112
2490
  self.close();
2113
2491
  self.setPlaceholder();
2492
+ self.lastSearchTerm = self.search.val();
2114
2493
  }
2115
2494
  });
2116
2495
  }
@@ -2118,7 +2497,7 @@ the specific language governing permissions and limitations under the Apache Lic
2118
2497
 
2119
2498
  isPlaceholderOptionSelected: function() {
2120
2499
  var placeholderOption;
2121
- if (!this.getPlaceholder()) return false; // no placeholder specified so no option should be considered
2500
+ if (this.getPlaceholder() === undefined) return false; // no placeholder specified so no option should be considered
2122
2501
  return ((placeholderOption = this.getPlaceholderOption()) !== undefined && placeholderOption.prop("selected"))
2123
2502
  || (this.opts.element.val() === "")
2124
2503
  || (this.opts.element.val() === undefined)
@@ -2133,7 +2512,7 @@ the specific language governing permissions and limitations under the Apache Lic
2133
2512
  if (opts.element.get(0).tagName.toLowerCase() === "select") {
2134
2513
  // install the selection initializer
2135
2514
  opts.initSelection = function (element, callback) {
2136
- var selected = element.find("option").filter(function() { return this.selected });
2515
+ var selected = element.find("option").filter(function() { return this.selected && !this.disabled });
2137
2516
  // a single select box always has a value, no need to null check 'selected'
2138
2517
  callback(self.optionToData(selected));
2139
2518
  };
@@ -2247,13 +2626,16 @@ the specific language governing permissions and limitations under the Apache Lic
2247
2626
 
2248
2627
  this.opts.element.trigger({ type: "select2-selected", val: this.id(data), choice: data });
2249
2628
 
2250
- this.nextSearchTerm = this.opts.nextSearchTerm(data, this.search.val());
2629
+ this.lastSearchTerm = this.search.val();
2251
2630
  this.close();
2252
2631
 
2253
- if (!options || !options.noFocus)
2632
+ if ((!options || !options.noFocus) && this.opts.shouldFocusInput(this)) {
2254
2633
  this.focusser.focus();
2634
+ }
2255
2635
 
2256
- if (!equal(old, this.id(data))) { this.triggerChange({added:data,removed:oldData}); }
2636
+ if (!equal(old, this.id(data))) {
2637
+ this.triggerChange({ added: data, removed: oldData });
2638
+ }
2257
2639
  },
2258
2640
 
2259
2641
  // single
@@ -2298,9 +2680,23 @@ the specific language governing permissions and limitations under the Apache Lic
2298
2680
 
2299
2681
  if (arguments.length > 1) {
2300
2682
  triggerChange = arguments[1];
2683
+
2684
+ if (this.opts.debug && console && console.warn) {
2685
+ console.warn(
2686
+ 'Select2: The second option to `select2("val")` is not supported in Select2 4.0.0. ' +
2687
+ 'The `change` event will always be triggered in 4.0.0.'
2688
+ );
2689
+ }
2301
2690
  }
2302
2691
 
2303
2692
  if (this.select) {
2693
+ if (this.opts.debug && console && console.warn) {
2694
+ console.warn(
2695
+ 'Select2: Setting the value on a <select> using `select2("val")` is no longer supported in 4.0.0. ' +
2696
+ 'You can use the `.val(newValue).trigger("change")` method provided by jQuery instead.'
2697
+ );
2698
+ }
2699
+
2304
2700
  this.select
2305
2701
  .val(val)
2306
2702
  .find("option").filter(function() { return this.selected }).each2(function (i, elm) {
@@ -2349,6 +2745,13 @@ the specific language governing permissions and limitations under the Apache Lic
2349
2745
  if (data == undefined) data = null;
2350
2746
  return data;
2351
2747
  } else {
2748
+ if (this.opts.debug && console && console.warn) {
2749
+ console.warn(
2750
+ 'Select2: The `select2("data")` method can no longer set selected values in 4.0.0, ' +
2751
+ 'consider using the `.val()` method instead.'
2752
+ );
2753
+ }
2754
+
2352
2755
  if (arguments.length > 1) {
2353
2756
  triggerChange = arguments[1];
2354
2757
  }
@@ -2375,6 +2778,7 @@ the specific language governing permissions and limitations under the Apache Lic
2375
2778
  }).html([
2376
2779
  "<ul class='select2-choices'>",
2377
2780
  " <li class='select2-search-field'>",
2781
+ " <label for='' class='select2-offscreen'></label>",
2378
2782
  " <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'>",
2379
2783
  " </li>",
2380
2784
  "</ul>",
@@ -2391,14 +2795,13 @@ the specific language governing permissions and limitations under the Apache Lic
2391
2795
  self=this;
2392
2796
 
2393
2797
  // TODO validate placeholder is a string if specified
2394
-
2395
2798
  if (opts.element.get(0).tagName.toLowerCase() === "select") {
2396
- // install sthe selection initializer
2799
+ // install the selection initializer
2397
2800
  opts.initSelection = function (element, callback) {
2398
2801
 
2399
2802
  var data = [];
2400
2803
 
2401
- element.find("option").filter(function() { return this.selected }).each2(function (i, elm) {
2804
+ element.find("option").filter(function() { return this.selected && !this.disabled }).each2(function (i, elm) {
2402
2805
  data.push(self.optionToData(elm));
2403
2806
  });
2404
2807
  callback(data);
@@ -2406,7 +2809,7 @@ the specific language governing permissions and limitations under the Apache Lic
2406
2809
  } else if ("data" in opts) {
2407
2810
  // install default initSelection when applied to hidden input and data is local
2408
2811
  opts.initSelection = opts.initSelection || function (element, callback) {
2409
- var ids = splitVal(element.val(), opts.separator);
2812
+ var ids = splitVal(element.val(), opts.separator, opts.transformVal);
2410
2813
  //search in data by array of ids, storing matching items in a list
2411
2814
  var matches = [];
2412
2815
  opts.query({
@@ -2467,6 +2870,11 @@ the specific language governing permissions and limitations under the Apache Lic
2467
2870
  $("label[for='" + this.search.attr('id') + "']")
2468
2871
  .attr('for', this.opts.element.attr("id"));
2469
2872
  this.parent.destroy.apply(this, arguments);
2873
+
2874
+ cleanupJQueryElements.call(this,
2875
+ "searchContainer",
2876
+ "selection"
2877
+ );
2470
2878
  },
2471
2879
 
2472
2880
  // multi
@@ -2478,18 +2886,21 @@ the specific language governing permissions and limitations under the Apache Lic
2478
2886
  this.selection = selection = this.container.find(selector);
2479
2887
 
2480
2888
  var _this = this;
2481
- this.selection.on("click", ".select2-search-choice:not(.select2-locked)", function (e) {
2482
- //killEvent(e);
2889
+ this.selection.on("click", ".select2-container:not(.select2-container-disabled) .select2-search-choice:not(.select2-locked)", function (e) {
2483
2890
  _this.search[0].focus();
2484
2891
  _this.selectChoice($(this));
2485
2892
  });
2486
2893
 
2487
2894
  // rewrite labels from original element to focusser
2488
2895
  this.search.attr("id", "s2id_autogen"+nextUid());
2489
- $("label[for='" + this.opts.element.attr("id") + "']")
2896
+
2897
+ this.search.prev()
2898
+ .text($("label[for='" + this.opts.element.attr("id") + "']").text())
2490
2899
  .attr('for', this.search.attr('id'));
2900
+ this.opts.element.on('focus.select2', this.bind(function () { this.focus(); }));
2491
2901
 
2492
2902
  this.search.on("input paste", this.bind(function() {
2903
+ if (this.search.attr('placeholder') && this.search.val().length == 0) return;
2493
2904
  if (!this.isInterfaceEnabled()) return;
2494
2905
  if (!this.opened()) {
2495
2906
  this.open();
@@ -2518,13 +2929,15 @@ the specific language governing permissions and limitations under the Apache Lic
2518
2929
  selectedChoice = next.length ? next : null;
2519
2930
  }
2520
2931
  else if (e.which === KEY.BACKSPACE) {
2521
- this.unselect(selected.first());
2522
- this.search.width(10);
2523
- selectedChoice = prev.length ? prev : next;
2932
+ if (this.unselect(selected.first())) {
2933
+ this.search.width(10);
2934
+ selectedChoice = prev.length ? prev : next;
2935
+ }
2524
2936
  } else if (e.which == KEY.DELETE) {
2525
- this.unselect(selected.first());
2526
- this.search.width(10);
2527
- selectedChoice = next.length ? next : null;
2937
+ if (this.unselect(selected.first())) {
2938
+ this.search.width(10);
2939
+ selectedChoice = next.length ? next : null;
2940
+ }
2528
2941
  } else if (e.which == KEY.ENTER) {
2529
2942
  selectedChoice = null;
2530
2943
  }
@@ -2636,7 +3049,7 @@ the specific language governing permissions and limitations under the Apache Lic
2636
3049
  }));
2637
3050
 
2638
3051
  this.initContainerWidth();
2639
- this.opts.element.addClass("select2-offscreen");
3052
+ this.opts.element.hide();
2640
3053
 
2641
3054
  // set the placeholder if necessary
2642
3055
  this.clearSearch();
@@ -2702,8 +3115,12 @@ the specific language governing permissions and limitations under the Apache Lic
2702
3115
 
2703
3116
  this.focusSearch();
2704
3117
 
3118
+ this.prefillNextSearchTerm();
2705
3119
  this.updateResults(true);
2706
- this.search.focus();
3120
+
3121
+ if (this.opts.shouldFocusInput(this)) {
3122
+ this.search.focus();
3123
+ }
2707
3124
  this.opts.element.trigger($.Event("select2-open"));
2708
3125
  },
2709
3126
 
@@ -2726,21 +3143,18 @@ the specific language governing permissions and limitations under the Apache Lic
2726
3143
 
2727
3144
  // multi
2728
3145
  updateSelection: function (data) {
2729
- var ids = [], filtered = [], self = this;
3146
+ var ids = {}, filtered = [], self = this;
2730
3147
 
2731
3148
  // filter out duplicates
2732
3149
  $(data).each(function () {
2733
- if (indexOf(self.id(this), ids) < 0) {
2734
- ids.push(self.id(this));
3150
+ if (!(self.id(this) in ids)) {
3151
+ ids[self.id(this)] = 0;
2735
3152
  filtered.push(this);
2736
3153
  }
2737
3154
  });
2738
- data = filtered;
2739
3155
 
2740
3156
  this.selection.find(".select2-search-choice").remove();
2741
- $(data).each(function () {
2742
- self.addSelectedChoice(this);
2743
- });
3157
+ this.addSelectedChoice(filtered);
2744
3158
  self.postprocessResults();
2745
3159
  },
2746
3160
 
@@ -2760,12 +3174,18 @@ the specific language governing permissions and limitations under the Apache Lic
2760
3174
  // multi
2761
3175
  onSelect: function (data, options) {
2762
3176
 
2763
- if (!this.triggerSelect(data)) { return; }
3177
+ if (!this.triggerSelect(data) || data.text === "") { return; }
2764
3178
 
2765
3179
  this.addSelectedChoice(data);
2766
3180
 
2767
3181
  this.opts.element.trigger({ type: "selected", val: this.id(data), choice: data });
2768
3182
 
3183
+ // keep track of the search's value before it gets cleared
3184
+ this.lastSearchTerm = this.search.val();
3185
+
3186
+ this.clearSearch();
3187
+ this.updateResults();
3188
+
2769
3189
  if (this.select || !this.opts.closeOnSelect) this.postprocessResults(data, false, this.opts.closeOnSelect===true);
2770
3190
 
2771
3191
  if (this.opts.closeOnSelect) {
@@ -2779,6 +3199,11 @@ the specific language governing permissions and limitations under the Apache Lic
2779
3199
  // if we reached max selection size repaint the results so choices
2780
3200
  // are replaced with the max selection reached message
2781
3201
  this.updateResults(true);
3202
+ } else {
3203
+ // initializes search's value with nextSearchTerm and update search result
3204
+ if (this.prefillNextSearchTerm()) {
3205
+ this.updateResults();
3206
+ }
2782
3207
  }
2783
3208
  this.positionDropdown();
2784
3209
  } else {
@@ -2803,11 +3228,19 @@ the specific language governing permissions and limitations under the Apache Lic
2803
3228
  },
2804
3229
 
2805
3230
  addSelectedChoice: function (data) {
3231
+ var val = this.getVal(), self = this;
3232
+ $(data).each(function () {
3233
+ val.push(self.createChoice(this));
3234
+ });
3235
+ this.setVal(val);
3236
+ },
3237
+
3238
+ createChoice: function (data) {
2806
3239
  var enableChoice = !data.locked,
2807
3240
  enabledItem = $(
2808
3241
  "<li class='select2-search-choice'>" +
2809
3242
  " <div></div>" +
2810
- " <a href='#' onclick='return false;' class='select2-search-choice-close' tabindex='-1'></a>" +
3243
+ " <a href='#' class='select2-search-choice-close' tabindex='-1'></a>" +
2811
3244
  "</li>"),
2812
3245
  disabledItem = $(
2813
3246
  "<li class='select2-search-choice select2-locked'>" +
@@ -2815,13 +3248,12 @@ the specific language governing permissions and limitations under the Apache Lic
2815
3248
  "</li>");
2816
3249
  var choice = enableChoice ? enabledItem : disabledItem,
2817
3250
  id = this.id(data),
2818
- val = this.getVal(),
2819
3251
  formatted,
2820
3252
  cssClass;
2821
3253
 
2822
3254
  formatted=this.opts.formatSelection(data, choice.find("div"), this.opts.escapeMarkup);
2823
3255
  if (formatted != undefined) {
2824
- choice.find("div").replaceWith("<div>"+formatted+"</div>");
3256
+ choice.find("div").replaceWith($("<div></div>").html(formatted));
2825
3257
  }
2826
3258
  cssClass=this.opts.formatSelectionCssClass(data, choice.find("div"));
2827
3259
  if (cssClass != undefined) {
@@ -2834,13 +3266,11 @@ the specific language governing permissions and limitations under the Apache Lic
2834
3266
  .on("click dblclick", this.bind(function (e) {
2835
3267
  if (!this.isInterfaceEnabled()) return;
2836
3268
 
2837
- $(e.target).closest(".select2-search-choice").fadeOut('fast', this.bind(function(){
2838
- this.unselect($(e.target));
2839
- this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
2840
- this.close();
2841
- this.focusSearch();
2842
- })).dequeue();
3269
+ this.unselect($(e.target));
3270
+ this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
2843
3271
  killEvent(e);
3272
+ this.close();
3273
+ this.focusSearch();
2844
3274
  })).on("focus", this.bind(function () {
2845
3275
  if (!this.isInterfaceEnabled()) return;
2846
3276
  this.container.addClass("select2-container-active");
@@ -2851,8 +3281,7 @@ the specific language governing permissions and limitations under the Apache Lic
2851
3281
  choice.data("select2-data", data);
2852
3282
  choice.insertBefore(this.searchContainer);
2853
3283
 
2854
- val.push(id);
2855
- this.setVal(val);
3284
+ return id;
2856
3285
  },
2857
3286
 
2858
3287
  // multi
@@ -2874,25 +3303,27 @@ the specific language governing permissions and limitations under the Apache Lic
2874
3303
  return;
2875
3304
  }
2876
3305
 
2877
- while((index = indexOf(this.id(data), val)) >= 0) {
2878
- val.splice(index, 1);
2879
- this.setVal(val);
2880
- if (this.select) this.postprocessResults();
2881
- }
2882
-
2883
3306
  var evt = $.Event("select2-removing");
2884
3307
  evt.val = this.id(data);
2885
3308
  evt.choice = data;
2886
3309
  this.opts.element.trigger(evt);
2887
3310
 
2888
3311
  if (evt.isDefaultPrevented()) {
2889
- return;
3312
+ return false;
3313
+ }
3314
+
3315
+ while((index = indexOf(this.id(data), val)) >= 0) {
3316
+ val.splice(index, 1);
3317
+ this.setVal(val);
3318
+ if (this.select) this.postprocessResults();
2890
3319
  }
2891
3320
 
2892
3321
  selected.remove();
2893
3322
 
2894
3323
  this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data });
2895
3324
  this.triggerChange({ removed: data });
3325
+
3326
+ return true;
2896
3327
  },
2897
3328
 
2898
3329
  // multi
@@ -2912,22 +3343,22 @@ the specific language governing permissions and limitations under the Apache Lic
2912
3343
  });
2913
3344
 
2914
3345
  compound.each2(function(i, choice) {
2915
- // hide an optgroup if it doesnt have any selectable children
3346
+ // hide an optgroup if it doesn't have any selectable children
2916
3347
  if (!choice.is('.select2-result-selectable')
2917
3348
  && choice.find(".select2-result-selectable:not(.select2-selected)").length === 0) {
2918
3349
  choice.addClass("select2-selected");
2919
3350
  }
2920
3351
  });
2921
3352
 
2922
- if (this.highlight() == -1 && noHighlightUpdate !== false){
3353
+ if (this.highlight() == -1 && noHighlightUpdate !== false && this.opts.closeOnSelect === true){
2923
3354
  self.highlight(0);
2924
3355
  }
2925
3356
 
2926
- //If all results are chosen render formatNoMAtches
3357
+ //If all results are chosen render formatNoMatches
2927
3358
  if(!this.opts.createSearchChoice && !choices.filter('.select2-result:not(.select2-selected)').length > 0){
2928
3359
  if(!data || data && !data.more && this.results.find(".select2-no-results").length === 0) {
2929
3360
  if (checkFormatter(self.opts.formatNoMatches, "formatNoMatches")) {
2930
- this.results.append("<li class='select2-no-results'>" + self.opts.formatNoMatches(self.search.val()) + "</li>");
3361
+ this.results.append("<li class='select2-no-results'>" + evaluate(self.opts.formatNoMatches, self.opts.element, self.search.val()) + "</li>");
2931
3362
  }
2932
3363
  }
2933
3364
  }
@@ -2976,20 +3407,22 @@ the specific language governing permissions and limitations under the Apache Lic
2976
3407
  return val === null ? [] : val;
2977
3408
  } else {
2978
3409
  val = this.opts.element.val();
2979
- return splitVal(val, this.opts.separator);
3410
+ return splitVal(val, this.opts.separator, this.opts.transformVal);
2980
3411
  }
2981
3412
  },
2982
3413
 
2983
3414
  // multi
2984
3415
  setVal: function (val) {
2985
- var unique;
2986
3416
  if (this.select) {
2987
3417
  this.select.val(val);
2988
3418
  } else {
2989
- unique = [];
3419
+ var unique = [], valMap = {};
2990
3420
  // filter out duplicates
2991
3421
  $(val).each(function () {
2992
- if (indexOf(this, unique) < 0) unique.push(this);
3422
+ if (!(this in valMap)) {
3423
+ unique.push(this);
3424
+ valMap[this] = 0;
3425
+ }
2993
3426
  });
2994
3427
  this.opts.element.val(unique.length === 0 ? "" : unique.join(this.opts.separator));
2995
3428
  }
@@ -3005,11 +3438,9 @@ the specific language governing permissions and limitations under the Apache Lic
3005
3438
  for (var j = 0; j < old.length; j++) {
3006
3439
  if (equal(this.opts.id(current[i]), this.opts.id(old[j]))) {
3007
3440
  current.splice(i, 1);
3008
- if(i>0){
3009
- i--;
3010
- }
3441
+ i--;
3011
3442
  old.splice(j, 1);
3012
- j--;
3443
+ break;
3013
3444
  }
3014
3445
  }
3015
3446
  }
@@ -3103,7 +3534,7 @@ the specific language governing permissions and limitations under the Apache Lic
3103
3534
  var self=this, ids, old;
3104
3535
  if (arguments.length === 0) {
3105
3536
  return this.selection
3106
- .find(".select2-search-choice")
3537
+ .children(".select2-search-choice")
3107
3538
  .map(function() { return $(this).data("select2-data"); })
3108
3539
  .get();
3109
3540
  } else {
@@ -3143,7 +3574,7 @@ the specific language governing permissions and limitations under the Apache Lic
3143
3574
  if ("tags" in opts) {opts.multiple = multiple = true;}
3144
3575
  }
3145
3576
 
3146
- select2 = multiple ? new MultiSelect2() : new SingleSelect2();
3577
+ select2 = multiple ? new window.Select2["class"].multi() : new window.Select2["class"].single();
3147
3578
  select2.init(opts);
3148
3579
  } else if (typeof(args[0]) === "string") {
3149
3580
 
@@ -3167,7 +3598,7 @@ the specific language governing permissions and limitations under the Apache Lic
3167
3598
  value = select2[method].apply(select2, args.slice(1));
3168
3599
  }
3169
3600
  if (indexOf(args[0], valueMethods) >= 0
3170
- || (indexOf(args[0], propertyMethods) && args.length == 1)) {
3601
+ || (indexOf(args[0], propertyMethods) >= 0 && args.length == 1)) {
3171
3602
  return false; // abort the iteration, ready to return first matched value
3172
3603
  }
3173
3604
  } else {
@@ -3179,6 +3610,7 @@ the specific language governing permissions and limitations under the Apache Lic
3179
3610
 
3180
3611
  // plugin defaults, accessible to users
3181
3612
  $.fn.select2.defaults = {
3613
+ debug: false,
3182
3614
  width: "copy",
3183
3615
  loadMorePadding: 0,
3184
3616
  closeOnSelect: true,
@@ -3189,28 +3621,36 @@ the specific language governing permissions and limitations under the Apache Lic
3189
3621
  dropdownCssClass: "",
3190
3622
  formatResult: function(result, container, query, escapeMarkup) {
3191
3623
  var markup=[];
3192
- markMatch(result.text, query.term, markup, escapeMarkup);
3624
+ markMatch(this.text(result), query.term, markup, escapeMarkup);
3193
3625
  return markup.join("");
3194
3626
  },
3627
+ transformVal: function(val) {
3628
+ return $.trim(val);
3629
+ },
3195
3630
  formatSelection: function (data, container, escapeMarkup) {
3196
- return data ? escapeMarkup(data.text) : undefined;
3631
+ return data ? escapeMarkup(this.text(data)) : undefined;
3197
3632
  },
3198
3633
  sortResults: function (results, container, query) {
3199
3634
  return results;
3200
3635
  },
3201
- formatResultCssClass: function(data) {return undefined;},
3636
+ formatResultCssClass: function(data) {return data.css;},
3202
3637
  formatSelectionCssClass: function(data, container) {return undefined;},
3203
- formatNoMatches: function () { return "No matches found"; },
3204
- formatInputTooShort: function (input, min) { var n = min - input.length; return "Please enter " + n + " more character" + (n == 1? "" : "s"); },
3205
- formatInputTooLong: function (input, max) { var n = input.length - max; return "Please delete " + n + " character" + (n == 1? "" : "s"); },
3206
- formatSelectionTooBig: function (limit) { return "You can only select " + limit + " item" + (limit == 1 ? "" : "s"); },
3207
- formatLoadMore: function (pageNumber) { return "Loading more results..."; },
3208
- formatSearching: function () { return "Searching..."; },
3209
3638
  minimumResultsForSearch: 0,
3210
3639
  minimumInputLength: 0,
3211
3640
  maximumInputLength: null,
3212
3641
  maximumSelectionSize: 0,
3213
- id: function (e) { return e.id; },
3642
+ id: function (e) { return e == undefined ? null : e.id; },
3643
+ text: function (e) {
3644
+ if (e && this.data && this.data.text) {
3645
+ if ($.isFunction(this.data.text)) {
3646
+ return this.data.text(e);
3647
+ } else {
3648
+ return e[this.data.text];
3649
+ }
3650
+ } else {
3651
+ return e.text;
3652
+ }
3653
+ },
3214
3654
  matcher: function(term, text) {
3215
3655
  return stripDiacritics(''+text).toUpperCase().indexOf(stripDiacritics(''+term).toUpperCase()) >= 0;
3216
3656
  },
@@ -3222,9 +3662,43 @@ the specific language governing permissions and limitations under the Apache Lic
3222
3662
  selectOnBlur: false,
3223
3663
  adaptContainerCssClass: function(c) { return c; },
3224
3664
  adaptDropdownCssClass: function(c) { return null; },
3225
- nextSearchTerm: function(selectedObject, currentSearchTerm) { return undefined; }
3665
+ nextSearchTerm: function(selectedObject, currentSearchTerm) { return undefined; },
3666
+ searchInputPlaceholder: '',
3667
+ createSearchChoicePosition: 'top',
3668
+ shouldFocusInput: function (instance) {
3669
+ // Attempt to detect touch devices
3670
+ var supportsTouchEvents = (('ontouchstart' in window) ||
3671
+ (navigator.msMaxTouchPoints > 0));
3672
+
3673
+ // Only devices which support touch events should be special cased
3674
+ if (!supportsTouchEvents) {
3675
+ return true;
3676
+ }
3677
+
3678
+ // Never focus the input if search is disabled
3679
+ if (instance.opts.minimumResultsForSearch < 0) {
3680
+ return false;
3681
+ }
3682
+
3683
+ return true;
3684
+ }
3226
3685
  };
3227
3686
 
3687
+ $.fn.select2.locales = [];
3688
+
3689
+ $.fn.select2.locales['en'] = {
3690
+ formatMatches: function (matches) { if (matches === 1) { return "One result is available, press enter to select it."; } return matches + " results are available, use up and down arrow keys to navigate."; },
3691
+ formatNoMatches: function () { return "No matches found"; },
3692
+ formatAjaxError: function (jqXHR, textStatus, errorThrown) { return "Loading failed"; },
3693
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Please enter " + n + " or more character" + (n == 1 ? "" : "s"); },
3694
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Please delete " + n + " character" + (n == 1 ? "" : "s"); },
3695
+ formatSelectionTooBig: function (limit) { return "You can only select " + limit + " item" + (limit == 1 ? "" : "s"); },
3696
+ formatLoadMore: function (pageNumber) { return "Loading more results…"; },
3697
+ formatSearching: function () { return "Searching…"; }
3698
+ };
3699
+
3700
+ $.extend($.fn.select2.defaults, $.fn.select2.locales['en']);
3701
+
3228
3702
  $.fn.select2.ajaxDefaults = {
3229
3703
  transport: $.ajax,
3230
3704
  params: {