select2-rails 4.0.8 → 4.0.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/lib/select2-rails/version.rb +1 -1
  3. data/vendor/assets/javascripts/select2-full.js +338 -121
  4. data/vendor/assets/javascripts/select2.js +335 -118
  5. data/vendor/assets/javascripts/select2_locale_af.js +1 -1
  6. data/vendor/assets/javascripts/select2_locale_ar.js +1 -1
  7. data/vendor/assets/javascripts/select2_locale_az.js +1 -1
  8. data/vendor/assets/javascripts/select2_locale_bg.js +1 -1
  9. data/vendor/assets/javascripts/select2_locale_bn.js +1 -1
  10. data/vendor/assets/javascripts/select2_locale_bs.js +1 -1
  11. data/vendor/assets/javascripts/select2_locale_ca.js +1 -1
  12. data/vendor/assets/javascripts/select2_locale_cs.js +1 -1
  13. data/vendor/assets/javascripts/select2_locale_da.js +1 -1
  14. data/vendor/assets/javascripts/select2_locale_de.js +2 -2
  15. data/vendor/assets/javascripts/select2_locale_dsb.js +1 -1
  16. data/vendor/assets/javascripts/select2_locale_el.js +1 -1
  17. data/vendor/assets/javascripts/select2_locale_en.js +1 -1
  18. data/vendor/assets/javascripts/select2_locale_es.js +1 -1
  19. data/vendor/assets/javascripts/select2_locale_et.js +1 -1
  20. data/vendor/assets/javascripts/select2_locale_eu.js +1 -1
  21. data/vendor/assets/javascripts/select2_locale_fa.js +1 -1
  22. data/vendor/assets/javascripts/select2_locale_fi.js +1 -1
  23. data/vendor/assets/javascripts/select2_locale_fr.js +1 -1
  24. data/vendor/assets/javascripts/select2_locale_gl.js +1 -1
  25. data/vendor/assets/javascripts/select2_locale_he.js +1 -1
  26. data/vendor/assets/javascripts/select2_locale_hi.js +1 -1
  27. data/vendor/assets/javascripts/select2_locale_hr.js +1 -1
  28. data/vendor/assets/javascripts/select2_locale_hsb.js +1 -1
  29. data/vendor/assets/javascripts/select2_locale_hu.js +1 -1
  30. data/vendor/assets/javascripts/select2_locale_hy.js +1 -1
  31. data/vendor/assets/javascripts/select2_locale_id.js +1 -1
  32. data/vendor/assets/javascripts/select2_locale_is.js +1 -1
  33. data/vendor/assets/javascripts/select2_locale_it.js +1 -1
  34. data/vendor/assets/javascripts/select2_locale_ja.js +1 -1
  35. data/vendor/assets/javascripts/select2_locale_ka.js +1 -1
  36. data/vendor/assets/javascripts/select2_locale_km.js +1 -1
  37. data/vendor/assets/javascripts/select2_locale_ko.js +1 -1
  38. data/vendor/assets/javascripts/select2_locale_lt.js +1 -1
  39. data/vendor/assets/javascripts/select2_locale_lv.js +1 -1
  40. data/vendor/assets/javascripts/select2_locale_mk.js +1 -1
  41. data/vendor/assets/javascripts/select2_locale_ms.js +1 -1
  42. data/vendor/assets/javascripts/select2_locale_nb.js +1 -1
  43. data/vendor/assets/javascripts/select2_locale_ne.js +1 -1
  44. data/vendor/assets/javascripts/select2_locale_nl.js +1 -1
  45. data/vendor/assets/javascripts/select2_locale_pl.js +1 -1
  46. data/vendor/assets/javascripts/select2_locale_ps.js +1 -1
  47. data/vendor/assets/javascripts/select2_locale_pt-BR.js +1 -1
  48. data/vendor/assets/javascripts/select2_locale_pt.js +1 -1
  49. data/vendor/assets/javascripts/select2_locale_ro.js +1 -1
  50. data/vendor/assets/javascripts/select2_locale_ru.js +1 -1
  51. data/vendor/assets/javascripts/select2_locale_sk.js +1 -1
  52. data/vendor/assets/javascripts/select2_locale_sl.js +1 -1
  53. data/vendor/assets/javascripts/select2_locale_sq.js +1 -1
  54. data/vendor/assets/javascripts/select2_locale_sr-Cyrl.js +1 -1
  55. data/vendor/assets/javascripts/select2_locale_sr.js +1 -1
  56. data/vendor/assets/javascripts/select2_locale_sv.js +1 -1
  57. data/vendor/assets/javascripts/select2_locale_th.js +1 -1
  58. data/vendor/assets/javascripts/select2_locale_tk.js +1 -1
  59. data/vendor/assets/javascripts/select2_locale_tr.js +1 -1
  60. data/vendor/assets/javascripts/select2_locale_uk.js +1 -1
  61. data/vendor/assets/javascripts/select2_locale_vi.js +1 -1
  62. data/vendor/assets/javascripts/select2_locale_zh-CN.js +1 -1
  63. data/vendor/assets/javascripts/select2_locale_zh-TW.js +1 -1
  64. data/vendor/assets/stylesheets/select2.css +2 -1
  65. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e62325c4b81af2fab18f200949ff8e4df173d9d95e34fa4c988bfb5e1afef5e
4
- data.tar.gz: cb301034bc178d7a151fa2c5c8d63b9d1cec33581c8df44c6ce2825fb87c5101
3
+ metadata.gz: c74819abcc9a780c3221badc68cc4d2bc999e016c8d3a412c6c197545451126c
4
+ data.tar.gz: 1b22502c83b69ebbe348018e3e069aa640f160fd0e99c385c6d18064bd662ffa
5
5
  SHA512:
6
- metadata.gz: 6c4d09f316619c53667e77ec1c7ae37b2fda4b3d9d9b112befb70982db33783ae52636bb53ad0d5805991e9aa4c310e37a3c09ffeb037f15ad9616ed24ccccfc
7
- data.tar.gz: 957a70bf102744fc67255486c8a6c0a6de8be278932d542f95b149b79fed2774ed46ebca23265acaeb614ac6405b04929573d3592dbcb5dfc76cac2c3888d9fe
6
+ metadata.gz: 044aca6303e13dee71f8e2532db1369fd757fb58cda8945e9f7d20a1244205a75c8a72e4fed02a4e768ff7379a9a0579ed0735baa9fb421c11a5c2722481ed4b
7
+ data.tar.gz: 2fc02500109a54e3d47fddccfe6d477741e4f3e9bb6b2a937cffc658c4eec2777940ba3ee66bc436645eb7bcb6d6e11e580460c15abf2b982bc86c9575bdbcce
@@ -1,5 +1,5 @@
1
1
  module Select2
2
2
  module Rails
3
- VERSION = '4.0.8'
3
+ VERSION = '4.0.13'
4
4
  end
5
5
  end
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Select2 4.0.8
2
+ * Select2 4.0.13
3
3
  * https://select2.github.io
4
4
  *
5
5
  * Released under the MIT license
@@ -832,6 +832,8 @@ S2.define('select2/utils',[
832
832
  if (Utils.__cache[id] != null) {
833
833
  delete Utils.__cache[id];
834
834
  }
835
+
836
+ element.removeAttribute('data-select2-id');
835
837
  };
836
838
 
837
839
  return Utils;
@@ -853,7 +855,7 @@ S2.define('select2/results',[
853
855
 
854
856
  Results.prototype.render = function () {
855
857
  var $results = $(
856
- '<ul class="select2-results__options" role="tree"></ul>'
858
+ '<ul class="select2-results__options" role="listbox"></ul>'
857
859
  );
858
860
 
859
861
  if (this.options.get('multiple')) {
@@ -876,7 +878,7 @@ S2.define('select2/results',[
876
878
  this.hideLoading();
877
879
 
878
880
  var $message = $(
879
- '<li role="treeitem" aria-live="assertive"' +
881
+ '<li role="alert" aria-live="assertive"' +
880
882
  ' class="select2-results__option"></li>'
881
883
  );
882
884
 
@@ -1010,7 +1012,7 @@ S2.define('select2/results',[
1010
1012
  option.className = 'select2-results__option';
1011
1013
 
1012
1014
  var attrs = {
1013
- 'role': 'treeitem',
1015
+ 'role': 'option',
1014
1016
  'aria-selected': 'false'
1015
1017
  };
1016
1018
 
@@ -1430,6 +1432,7 @@ S2.define('select2/selection/base',[
1430
1432
 
1431
1433
  $selection.attr('title', this.$element.attr('title'));
1432
1434
  $selection.attr('tabindex', this._tabindex);
1435
+ $selection.attr('aria-disabled', 'false');
1433
1436
 
1434
1437
  this.$selection = $selection;
1435
1438
 
@@ -1439,7 +1442,6 @@ S2.define('select2/selection/base',[
1439
1442
  BaseSelection.prototype.bind = function (container, $container) {
1440
1443
  var self = this;
1441
1444
 
1442
- var id = container.id + '-container';
1443
1445
  var resultsId = container.id + '-results';
1444
1446
 
1445
1447
  this.container = container;
@@ -1489,10 +1491,12 @@ S2.define('select2/selection/base',[
1489
1491
 
1490
1492
  container.on('enable', function () {
1491
1493
  self.$selection.attr('tabindex', self._tabindex);
1494
+ self.$selection.attr('aria-disabled', 'false');
1492
1495
  });
1493
1496
 
1494
1497
  container.on('disable', function () {
1495
1498
  self.$selection.attr('tabindex', '-1');
1499
+ self.$selection.attr('aria-disabled', 'true');
1496
1500
  });
1497
1501
  };
1498
1502
 
@@ -1515,7 +1519,6 @@ S2.define('select2/selection/base',[
1515
1519
  };
1516
1520
 
1517
1521
  BaseSelection.prototype._attachCloseHandler = function (container) {
1518
- var self = this;
1519
1522
 
1520
1523
  $(document.body).on('mousedown.select2.' + container.id, function (e) {
1521
1524
  var $target = $(e.target);
@@ -1525,8 +1528,6 @@ S2.define('select2/selection/base',[
1525
1528
  var $all = $('.select2.select2-container--open');
1526
1529
 
1527
1530
  $all.each(function () {
1528
- var $this = $(this);
1529
-
1530
1531
  if (this == $select[0]) {
1531
1532
  return;
1532
1533
  }
@@ -1555,6 +1556,27 @@ S2.define('select2/selection/base',[
1555
1556
  throw new Error('The `update` method must be defined in child classes.');
1556
1557
  };
1557
1558
 
1559
+ /**
1560
+ * Helper method to abstract the "enabled" (not "disabled") state of this
1561
+ * object.
1562
+ *
1563
+ * @return {true} if the instance is not disabled.
1564
+ * @return {false} if the instance is disabled.
1565
+ */
1566
+ BaseSelection.prototype.isEnabled = function () {
1567
+ return !this.isDisabled();
1568
+ };
1569
+
1570
+ /**
1571
+ * Helper method to abstract the "disabled" state of this object.
1572
+ *
1573
+ * @return {true} if the disabled option is true.
1574
+ * @return {false} if the disabled option is false.
1575
+ */
1576
+ BaseSelection.prototype.isDisabled = function () {
1577
+ return this.options.get('disabled');
1578
+ };
1579
+
1558
1580
  return BaseSelection;
1559
1581
  });
1560
1582
 
@@ -1653,7 +1675,14 @@ S2.define('select2/selection/single',[
1653
1675
  var formatted = this.display(selection, $rendered);
1654
1676
 
1655
1677
  $rendered.empty().append(formatted);
1656
- $rendered.attr('title', selection.title || selection.text);
1678
+
1679
+ var title = selection.title || selection.text;
1680
+
1681
+ if (title) {
1682
+ $rendered.attr('title', title);
1683
+ } else {
1684
+ $rendered.removeAttr('title');
1685
+ }
1657
1686
  };
1658
1687
 
1659
1688
  return SingleSelection;
@@ -1698,7 +1727,7 @@ S2.define('select2/selection/multiple',[
1698
1727
  '.select2-selection__choice__remove',
1699
1728
  function (evt) {
1700
1729
  // Ignore the event if it is disabled
1701
- if (self.options.get('disabled')) {
1730
+ if (self.isDisabled()) {
1702
1731
  return;
1703
1732
  }
1704
1733
 
@@ -1756,7 +1785,12 @@ S2.define('select2/selection/multiple',[
1756
1785
  var formatted = this.display(selection, $selection);
1757
1786
 
1758
1787
  $selection.append(formatted);
1759
- $selection.attr('title', selection.title || selection.text);
1788
+
1789
+ var title = selection.title || selection.text;
1790
+
1791
+ if (title) {
1792
+ $selection.attr('title', title);
1793
+ }
1760
1794
 
1761
1795
  Utils.StoreData($selection[0], 'data', selection);
1762
1796
 
@@ -1854,7 +1888,7 @@ S2.define('select2/selection/allowClear',[
1854
1888
 
1855
1889
  AllowClear.prototype._handleClear = function (_, evt) {
1856
1890
  // Ignore the event if it is disabled
1857
- if (this.options.get('disabled')) {
1891
+ if (this.isDisabled()) {
1858
1892
  return;
1859
1893
  }
1860
1894
 
@@ -1897,7 +1931,7 @@ S2.define('select2/selection/allowClear',[
1897
1931
  }
1898
1932
  }
1899
1933
 
1900
- this.$element.trigger('change');
1934
+ this.$element.trigger('input').trigger('change');
1901
1935
 
1902
1936
  this.trigger('toggle', {});
1903
1937
  };
@@ -1920,7 +1954,7 @@ S2.define('select2/selection/allowClear',[
1920
1954
  return;
1921
1955
  }
1922
1956
 
1923
- var removeAll = this.options.get('translations').get('removeAllItems');
1957
+ var removeAll = this.options.get('translations').get('removeAllItems');
1924
1958
 
1925
1959
  var $remove = $(
1926
1960
  '<span class="select2-selection__clear" title="' + removeAll() +'">' +
@@ -1949,7 +1983,7 @@ S2.define('select2/selection/search',[
1949
1983
  '<li class="select2-search select2-search--inline">' +
1950
1984
  '<input class="select2-search__field" type="search" tabindex="-1"' +
1951
1985
  ' autocomplete="off" autocorrect="off" autocapitalize="none"' +
1952
- ' spellcheck="false" role="textbox" aria-autocomplete="list" />' +
1986
+ ' spellcheck="false" role="searchbox" aria-autocomplete="list" />' +
1953
1987
  '</li>'
1954
1988
  );
1955
1989
 
@@ -1966,14 +2000,18 @@ S2.define('select2/selection/search',[
1966
2000
  Search.prototype.bind = function (decorated, container, $container) {
1967
2001
  var self = this;
1968
2002
 
2003
+ var resultsId = container.id + '-results';
2004
+
1969
2005
  decorated.call(this, container, $container);
1970
2006
 
1971
2007
  container.on('open', function () {
2008
+ self.$search.attr('aria-controls', resultsId);
1972
2009
  self.$search.trigger('focus');
1973
2010
  });
1974
2011
 
1975
2012
  container.on('close', function () {
1976
2013
  self.$search.val('');
2014
+ self.$search.removeAttr('aria-controls');
1977
2015
  self.$search.removeAttr('aria-activedescendant');
1978
2016
  self.$search.trigger('focus');
1979
2017
  });
@@ -1993,7 +2031,11 @@ S2.define('select2/selection/search',[
1993
2031
  });
1994
2032
 
1995
2033
  container.on('results:focus', function (params) {
1996
- self.$search.attr('aria-activedescendant', params.id);
2034
+ if (params.data._resultId) {
2035
+ self.$search.attr('aria-activedescendant', params.data._resultId);
2036
+ } else {
2037
+ self.$search.removeAttr('aria-activedescendant');
2038
+ }
1997
2039
  });
1998
2040
 
1999
2041
  this.$selection.on('focusin', '.select2-search--inline', function (evt) {
@@ -2027,6 +2069,12 @@ S2.define('select2/selection/search',[
2027
2069
  }
2028
2070
  });
2029
2071
 
2072
+ this.$selection.on('click', '.select2-search--inline', function (evt) {
2073
+ if (self.$search.val()) {
2074
+ evt.stopPropagation();
2075
+ }
2076
+ });
2077
+
2030
2078
  // Try to detect the IE version should the `documentMode` property that
2031
2079
  // is stored on the document. This is only implemented in IE and is
2032
2080
  // slightly cleaner than doing a user agent check.
@@ -2145,7 +2193,7 @@ S2.define('select2/selection/search',[
2145
2193
  var width = '';
2146
2194
 
2147
2195
  if (this.$search.attr('placeholder') !== '') {
2148
- width = this.$selection.find('.select2-selection__rendered').innerWidth();
2196
+ width = this.$selection.find('.select2-selection__rendered').width();
2149
2197
  } else {
2150
2198
  var minimumWidth = this.$search.val().length + 1;
2151
2199
 
@@ -3174,7 +3222,7 @@ S2.define('select2/data/select',[
3174
3222
  if ($(data.element).is('option')) {
3175
3223
  data.element.selected = true;
3176
3224
 
3177
- this.$element.trigger('change');
3225
+ this.$element.trigger('input').trigger('change');
3178
3226
 
3179
3227
  return;
3180
3228
  }
@@ -3195,13 +3243,13 @@ S2.define('select2/data/select',[
3195
3243
  }
3196
3244
 
3197
3245
  self.$element.val(val);
3198
- self.$element.trigger('change');
3246
+ self.$element.trigger('input').trigger('change');
3199
3247
  });
3200
3248
  } else {
3201
3249
  var val = data.id;
3202
3250
 
3203
3251
  this.$element.val(val);
3204
- this.$element.trigger('change');
3252
+ this.$element.trigger('input').trigger('change');
3205
3253
  }
3206
3254
  };
3207
3255
 
@@ -3217,7 +3265,7 @@ S2.define('select2/data/select',[
3217
3265
  if ($(data.element).is('option')) {
3218
3266
  data.element.selected = false;
3219
3267
 
3220
- this.$element.trigger('change');
3268
+ this.$element.trigger('input').trigger('change');
3221
3269
 
3222
3270
  return;
3223
3271
  }
@@ -3235,7 +3283,7 @@ S2.define('select2/data/select',[
3235
3283
 
3236
3284
  self.$element.val(val);
3237
3285
 
3238
- self.$element.trigger('change');
3286
+ self.$element.trigger('input').trigger('change');
3239
3287
  });
3240
3288
  };
3241
3289
 
@@ -3428,15 +3476,19 @@ S2.define('select2/data/array',[
3428
3476
  'jquery'
3429
3477
  ], function (SelectAdapter, Utils, $) {
3430
3478
  function ArrayAdapter ($element, options) {
3431
- var data = options.get('data') || [];
3479
+ this._dataToConvert = options.get('data') || [];
3432
3480
 
3433
3481
  ArrayAdapter.__super__.constructor.call(this, $element, options);
3434
-
3435
- this.addOptions(this.convertToOptions(data));
3436
3482
  }
3437
3483
 
3438
3484
  Utils.Extend(ArrayAdapter, SelectAdapter);
3439
3485
 
3486
+ ArrayAdapter.prototype.bind = function (container, $container) {
3487
+ ArrayAdapter.__super__.bind.call(this, container, $container);
3488
+
3489
+ this.addOptions(this.convertToOptions(this._dataToConvert));
3490
+ };
3491
+
3440
3492
  ArrayAdapter.prototype.select = function (data) {
3441
3493
  var $option = this.$element.find('option').filter(function (i, elm) {
3442
3494
  return elm.value == data.id.toString();
@@ -3726,8 +3778,6 @@ S2.define('select2/data/tags',[
3726
3778
  };
3727
3779
 
3728
3780
  Tags.prototype._removeOldTags = function (_) {
3729
- var tag = this._lastTag;
3730
-
3731
3781
  var $options = this.$element.find('option[data-select2-tag]');
3732
3782
 
3733
3783
  $options.each(function () {
@@ -3931,10 +3981,30 @@ S2.define('select2/data/maximumSelectionLength',[
3931
3981
  decorated.call(this, $e, options);
3932
3982
  }
3933
3983
 
3984
+ MaximumSelectionLength.prototype.bind =
3985
+ function (decorated, container, $container) {
3986
+ var self = this;
3987
+
3988
+ decorated.call(this, container, $container);
3989
+
3990
+ container.on('select', function () {
3991
+ self._checkIfMaximumSelected();
3992
+ });
3993
+ };
3994
+
3934
3995
  MaximumSelectionLength.prototype.query =
3935
3996
  function (decorated, params, callback) {
3936
3997
  var self = this;
3937
3998
 
3999
+ this._checkIfMaximumSelected(function () {
4000
+ decorated.call(self, params, callback);
4001
+ });
4002
+ };
4003
+
4004
+ MaximumSelectionLength.prototype._checkIfMaximumSelected =
4005
+ function (_, successCallback) {
4006
+ var self = this;
4007
+
3938
4008
  this.current(function (currentData) {
3939
4009
  var count = currentData != null ? currentData.length : 0;
3940
4010
  if (self.maximumSelectionLength > 0 &&
@@ -3947,7 +4017,10 @@ S2.define('select2/data/maximumSelectionLength',[
3947
4017
  });
3948
4018
  return;
3949
4019
  }
3950
- decorated.call(self, params, callback);
4020
+
4021
+ if (successCallback) {
4022
+ successCallback();
4023
+ }
3951
4024
  });
3952
4025
  };
3953
4026
 
@@ -4010,7 +4083,7 @@ S2.define('select2/dropdown/search',[
4010
4083
  '<span class="select2-search select2-search--dropdown">' +
4011
4084
  '<input class="select2-search__field" type="search" tabindex="-1"' +
4012
4085
  ' autocomplete="off" autocorrect="off" autocapitalize="none"' +
4013
- ' spellcheck="false" role="textbox" />' +
4086
+ ' spellcheck="false" role="searchbox" aria-autocomplete="list" />' +
4014
4087
  '</span>'
4015
4088
  );
4016
4089
 
@@ -4025,6 +4098,8 @@ S2.define('select2/dropdown/search',[
4025
4098
  Search.prototype.bind = function (decorated, container, $container) {
4026
4099
  var self = this;
4027
4100
 
4101
+ var resultsId = container.id + '-results';
4102
+
4028
4103
  decorated.call(this, container, $container);
4029
4104
 
4030
4105
  this.$search.on('keydown', function (evt) {
@@ -4047,6 +4122,7 @@ S2.define('select2/dropdown/search',[
4047
4122
 
4048
4123
  container.on('open', function () {
4049
4124
  self.$search.attr('tabindex', 0);
4125
+ self.$search.attr('aria-controls', resultsId);
4050
4126
 
4051
4127
  self.$search.trigger('focus');
4052
4128
 
@@ -4057,6 +4133,8 @@ S2.define('select2/dropdown/search',[
4057
4133
 
4058
4134
  container.on('close', function () {
4059
4135
  self.$search.attr('tabindex', -1);
4136
+ self.$search.removeAttr('aria-controls');
4137
+ self.$search.removeAttr('aria-activedescendant');
4060
4138
 
4061
4139
  self.$search.val('');
4062
4140
  self.$search.trigger('blur');
@@ -4079,6 +4157,14 @@ S2.define('select2/dropdown/search',[
4079
4157
  }
4080
4158
  }
4081
4159
  });
4160
+
4161
+ container.on('results:focus', function (params) {
4162
+ if (params.data._resultId) {
4163
+ self.$search.attr('aria-activedescendant', params.data._resultId);
4164
+ } else {
4165
+ self.$search.removeAttr('aria-activedescendant');
4166
+ }
4167
+ });
4082
4168
  };
4083
4169
 
4084
4170
  Search.prototype.handleSearch = function (evt) {
@@ -4223,7 +4309,7 @@ S2.define('select2/dropdown/infiniteScroll',[
4223
4309
  var $option = $(
4224
4310
  '<li ' +
4225
4311
  'class="select2-results__option select2-results__option--load-more"' +
4226
- 'role="treeitem" aria-disabled="true"></li>'
4312
+ 'role="option" aria-disabled="true"></li>'
4227
4313
  );
4228
4314
 
4229
4315
  var message = this.options.get('translations').get('loadingMore');
@@ -4241,7 +4327,7 @@ S2.define('select2/dropdown/attachBody',[
4241
4327
  '../utils'
4242
4328
  ], function ($, Utils) {
4243
4329
  function AttachBody (decorated, $element, options) {
4244
- this.$dropdownParent = options.get('dropdownParent') || $(document.body);
4330
+ this.$dropdownParent = $(options.get('dropdownParent') || document.body);
4245
4331
 
4246
4332
  decorated.call(this, $element, options);
4247
4333
  }
@@ -4249,27 +4335,14 @@ S2.define('select2/dropdown/attachBody',[
4249
4335
  AttachBody.prototype.bind = function (decorated, container, $container) {
4250
4336
  var self = this;
4251
4337
 
4252
- var setupResultsEvents = false;
4253
-
4254
4338
  decorated.call(this, container, $container);
4255
4339
 
4256
4340
  container.on('open', function () {
4257
4341
  self._showDropdown();
4258
4342
  self._attachPositioningHandler(container);
4259
4343
 
4260
- if (!setupResultsEvents) {
4261
- setupResultsEvents = true;
4262
-
4263
- container.on('results:all', function () {
4264
- self._positionDropdown();
4265
- self._resizeDropdown();
4266
- });
4267
-
4268
- container.on('results:append', function () {
4269
- self._positionDropdown();
4270
- self._resizeDropdown();
4271
- });
4272
- }
4344
+ // Must bind after the results handlers to ensure correct sizing
4345
+ self._bindContainerResultHandlers(container);
4273
4346
  });
4274
4347
 
4275
4348
  container.on('close', function () {
@@ -4318,6 +4391,44 @@ S2.define('select2/dropdown/attachBody',[
4318
4391
  this.$dropdownContainer.detach();
4319
4392
  };
4320
4393
 
4394
+ AttachBody.prototype._bindContainerResultHandlers =
4395
+ function (decorated, container) {
4396
+
4397
+ // These should only be bound once
4398
+ if (this._containerResultsHandlersBound) {
4399
+ return;
4400
+ }
4401
+
4402
+ var self = this;
4403
+
4404
+ container.on('results:all', function () {
4405
+ self._positionDropdown();
4406
+ self._resizeDropdown();
4407
+ });
4408
+
4409
+ container.on('results:append', function () {
4410
+ self._positionDropdown();
4411
+ self._resizeDropdown();
4412
+ });
4413
+
4414
+ container.on('results:message', function () {
4415
+ self._positionDropdown();
4416
+ self._resizeDropdown();
4417
+ });
4418
+
4419
+ container.on('select', function () {
4420
+ self._positionDropdown();
4421
+ self._resizeDropdown();
4422
+ });
4423
+
4424
+ container.on('unselect', function () {
4425
+ self._positionDropdown();
4426
+ self._resizeDropdown();
4427
+ });
4428
+
4429
+ this._containerResultsHandlersBound = true;
4430
+ };
4431
+
4321
4432
  AttachBody.prototype._attachPositioningHandler =
4322
4433
  function (decorated, container) {
4323
4434
  var self = this;
@@ -4403,7 +4514,17 @@ S2.define('select2/dropdown/attachBody',[
4403
4514
  $offsetParent = $offsetParent.offsetParent();
4404
4515
  }
4405
4516
 
4406
- var parentOffset = $offsetParent.offset();
4517
+ var parentOffset = {
4518
+ top: 0,
4519
+ left: 0
4520
+ };
4521
+
4522
+ if (
4523
+ $.contains(document.body, $offsetParent[0]) ||
4524
+ $offsetParent[0].isConnected
4525
+ ) {
4526
+ parentOffset = $offsetParent.offset();
4527
+ }
4407
4528
 
4408
4529
  css.top -= parentOffset.top;
4409
4530
  css.left -= parentOffset.left;
@@ -4868,66 +4989,29 @@ S2.define('select2/defaults',[
4868
4989
  );
4869
4990
  }
4870
4991
 
4871
- if (typeof options.language === 'string') {
4872
- // Check if the language is specified with a region
4873
- if (options.language.indexOf('-') > 0) {
4874
- // Extract the region information if it is included
4875
- var languageParts = options.language.split('-');
4876
- var baseLanguage = languageParts[0];
4877
-
4878
- options.language = [options.language, baseLanguage];
4879
- } else {
4880
- options.language = [options.language];
4881
- }
4882
- }
4883
-
4884
- if ($.isArray(options.language)) {
4885
- var languages = new Translation();
4886
- options.language.push('en');
4992
+ // If the defaults were not previously applied from an element, it is
4993
+ // possible for the language option to have not been resolved
4994
+ options.language = this._resolveLanguage(options.language);
4887
4995
 
4888
- var languageNames = options.language;
4996
+ // Always fall back to English since it will always be complete
4997
+ options.language.push('en');
4889
4998
 
4890
- for (var l = 0; l < languageNames.length; l++) {
4891
- var name = languageNames[l];
4892
- var language = {};
4893
-
4894
- try {
4895
- // Try to load it with the original name
4896
- language = Translation.loadPath(name);
4897
- } catch (e) {
4898
- try {
4899
- // If we couldn't load it, check if it wasn't the full path
4900
- name = this.defaults.amdLanguageBase + name;
4901
- language = Translation.loadPath(name);
4902
- } catch (ex) {
4903
- // The translation could not be loaded at all. Sometimes this is
4904
- // because of a configuration problem, other times this can be
4905
- // because of how Select2 helps load all possible translation files.
4906
- if (options.debug && window.console && console.warn) {
4907
- console.warn(
4908
- 'Select2: The language file for "' + name + '" could not be ' +
4909
- 'automatically loaded. A fallback will be used instead.'
4910
- );
4911
- }
4999
+ var uniqueLanguages = [];
4912
5000
 
4913
- continue;
4914
- }
4915
- }
5001
+ for (var l = 0; l < options.language.length; l++) {
5002
+ var language = options.language[l];
4916
5003
 
4917
- languages.extend(language);
5004
+ if (uniqueLanguages.indexOf(language) === -1) {
5005
+ uniqueLanguages.push(language);
4918
5006
  }
5007
+ }
4919
5008
 
4920
- options.translations = languages;
4921
- } else {
4922
- var baseTranslation = Translation.loadPath(
4923
- this.defaults.amdLanguageBase + 'en'
4924
- );
4925
- var customTranslation = new Translation(options.language);
4926
-
4927
- customTranslation.extend(baseTranslation);
5009
+ options.language = uniqueLanguages;
4928
5010
 
4929
- options.translations = customTranslation;
4930
- }
5011
+ options.translations = this._processTranslations(
5012
+ options.language,
5013
+ options.debug
5014
+ );
4931
5015
 
4932
5016
  return options;
4933
5017
  };
@@ -4994,7 +5078,7 @@ S2.define('select2/defaults',[
4994
5078
  debug: false,
4995
5079
  dropdownAutoWidth: false,
4996
5080
  escapeMarkup: Utils.escapeMarkup,
4997
- language: EnglishTranslation,
5081
+ language: {},
4998
5082
  matcher: matcher,
4999
5083
  minimumInputLength: 0,
5000
5084
  maximumInputLength: 0,
@@ -5016,6 +5100,103 @@ S2.define('select2/defaults',[
5016
5100
  };
5017
5101
  };
5018
5102
 
5103
+ Defaults.prototype.applyFromElement = function (options, $element) {
5104
+ var optionLanguage = options.language;
5105
+ var defaultLanguage = this.defaults.language;
5106
+ var elementLanguage = $element.prop('lang');
5107
+ var parentLanguage = $element.closest('[lang]').prop('lang');
5108
+
5109
+ var languages = Array.prototype.concat.call(
5110
+ this._resolveLanguage(elementLanguage),
5111
+ this._resolveLanguage(optionLanguage),
5112
+ this._resolveLanguage(defaultLanguage),
5113
+ this._resolveLanguage(parentLanguage)
5114
+ );
5115
+
5116
+ options.language = languages;
5117
+
5118
+ return options;
5119
+ };
5120
+
5121
+ Defaults.prototype._resolveLanguage = function (language) {
5122
+ if (!language) {
5123
+ return [];
5124
+ }
5125
+
5126
+ if ($.isEmptyObject(language)) {
5127
+ return [];
5128
+ }
5129
+
5130
+ if ($.isPlainObject(language)) {
5131
+ return [language];
5132
+ }
5133
+
5134
+ var languages;
5135
+
5136
+ if (!$.isArray(language)) {
5137
+ languages = [language];
5138
+ } else {
5139
+ languages = language;
5140
+ }
5141
+
5142
+ var resolvedLanguages = [];
5143
+
5144
+ for (var l = 0; l < languages.length; l++) {
5145
+ resolvedLanguages.push(languages[l]);
5146
+
5147
+ if (typeof languages[l] === 'string' && languages[l].indexOf('-') > 0) {
5148
+ // Extract the region information if it is included
5149
+ var languageParts = languages[l].split('-');
5150
+ var baseLanguage = languageParts[0];
5151
+
5152
+ resolvedLanguages.push(baseLanguage);
5153
+ }
5154
+ }
5155
+
5156
+ return resolvedLanguages;
5157
+ };
5158
+
5159
+ Defaults.prototype._processTranslations = function (languages, debug) {
5160
+ var translations = new Translation();
5161
+
5162
+ for (var l = 0; l < languages.length; l++) {
5163
+ var languageData = new Translation();
5164
+
5165
+ var language = languages[l];
5166
+
5167
+ if (typeof language === 'string') {
5168
+ try {
5169
+ // Try to load it with the original name
5170
+ languageData = Translation.loadPath(language);
5171
+ } catch (e) {
5172
+ try {
5173
+ // If we couldn't load it, check if it wasn't the full path
5174
+ language = this.defaults.amdLanguageBase + language;
5175
+ languageData = Translation.loadPath(language);
5176
+ } catch (ex) {
5177
+ // The translation could not be loaded at all. Sometimes this is
5178
+ // because of a configuration problem, other times this can be
5179
+ // because of how Select2 helps load all possible translation files
5180
+ if (debug && window.console && console.warn) {
5181
+ console.warn(
5182
+ 'Select2: The language file for "' + language + '" could ' +
5183
+ 'not be automatically loaded. A fallback will be used instead.'
5184
+ );
5185
+ }
5186
+ }
5187
+ }
5188
+ } else if ($.isPlainObject(language)) {
5189
+ languageData = new Translation(language);
5190
+ } else {
5191
+ languageData = language;
5192
+ }
5193
+
5194
+ translations.extend(languageData);
5195
+ }
5196
+
5197
+ return translations;
5198
+ };
5199
+
5019
5200
  Defaults.prototype.set = function (key, value) {
5020
5201
  var camelKey = $.camelCase(key);
5021
5202
 
@@ -5045,6 +5226,10 @@ S2.define('select2/options',[
5045
5226
  this.fromElement($element);
5046
5227
  }
5047
5228
 
5229
+ if ($element != null) {
5230
+ this.options = Defaults.applyFromElement(this.options, $element);
5231
+ }
5232
+
5048
5233
  this.options = Defaults.apply(this.options);
5049
5234
 
5050
5235
  if ($element && $element.is('input')) {
@@ -5068,14 +5253,6 @@ S2.define('select2/options',[
5068
5253
  this.options.disabled = $e.prop('disabled');
5069
5254
  }
5070
5255
 
5071
- if (this.options.language == null) {
5072
- if ($e.prop('lang')) {
5073
- this.options.language = $e.prop('lang').toLowerCase();
5074
- } else if ($e.closest('[lang]').prop('lang')) {
5075
- this.options.language = $e.closest('[lang]').prop('lang');
5076
- }
5077
- }
5078
-
5079
5256
  if (this.options.dir == null) {
5080
5257
  if ($e.prop('dir')) {
5081
5258
  this.options.dir = $e.prop('dir');
@@ -5389,8 +5566,8 @@ S2.define('select2/core',[
5389
5566
 
5390
5567
  if (observer != null) {
5391
5568
  this._observer = new observer(function (mutations) {
5392
- $.each(mutations, self._syncA);
5393
- $.each(mutations, self._syncS);
5569
+ self._syncA();
5570
+ self._syncS(null, mutations);
5394
5571
  });
5395
5572
  this._observer.observe(this.$element[0], {
5396
5573
  attributes: true,
@@ -5512,7 +5689,7 @@ S2.define('select2/core',[
5512
5689
  if (self.isOpen()) {
5513
5690
  if (key === KEYS.ESC || key === KEYS.TAB ||
5514
5691
  (key === KEYS.UP && evt.altKey)) {
5515
- self.close();
5692
+ self.close(evt);
5516
5693
 
5517
5694
  evt.preventDefault();
5518
5695
  } else if (key === KEYS.ENTER) {
@@ -5546,7 +5723,7 @@ S2.define('select2/core',[
5546
5723
  Select2.prototype._syncAttributes = function () {
5547
5724
  this.options.set('disabled', this.$element.prop('disabled'));
5548
5725
 
5549
- if (this.options.get('disabled')) {
5726
+ if (this.isDisabled()) {
5550
5727
  if (this.isOpen()) {
5551
5728
  this.close();
5552
5729
  }
@@ -5557,7 +5734,7 @@ S2.define('select2/core',[
5557
5734
  }
5558
5735
  };
5559
5736
 
5560
- Select2.prototype._syncSubtree = function (evt, mutations) {
5737
+ Select2.prototype._isChangeMutation = function (evt, mutations) {
5561
5738
  var changed = false;
5562
5739
  var self = this;
5563
5740
 
@@ -5585,7 +5762,22 @@ S2.define('select2/core',[
5585
5762
  }
5586
5763
  } else if (mutations.removedNodes && mutations.removedNodes.length > 0) {
5587
5764
  changed = true;
5765
+ } else if ($.isArray(mutations)) {
5766
+ $.each(mutations, function(evt, mutation) {
5767
+ if (self._isChangeMutation(evt, mutation)) {
5768
+ // We've found a change mutation.
5769
+ // Let's escape from the loop and continue
5770
+ changed = true;
5771
+ return false;
5772
+ }
5773
+ });
5588
5774
  }
5775
+ return changed;
5776
+ };
5777
+
5778
+ Select2.prototype._syncSubtree = function (evt, mutations) {
5779
+ var changed = this._isChangeMutation(evt, mutations);
5780
+ var self = this;
5589
5781
 
5590
5782
  // Only re-pull the data if we think there is a change
5591
5783
  if (changed) {
@@ -5636,7 +5828,7 @@ S2.define('select2/core',[
5636
5828
  };
5637
5829
 
5638
5830
  Select2.prototype.toggleDropdown = function () {
5639
- if (this.options.get('disabled')) {
5831
+ if (this.isDisabled()) {
5640
5832
  return;
5641
5833
  }
5642
5834
 
@@ -5652,15 +5844,40 @@ S2.define('select2/core',[
5652
5844
  return;
5653
5845
  }
5654
5846
 
5847
+ if (this.isDisabled()) {
5848
+ return;
5849
+ }
5850
+
5655
5851
  this.trigger('query', {});
5656
5852
  };
5657
5853
 
5658
- Select2.prototype.close = function () {
5854
+ Select2.prototype.close = function (evt) {
5659
5855
  if (!this.isOpen()) {
5660
5856
  return;
5661
5857
  }
5662
5858
 
5663
- this.trigger('close', {});
5859
+ this.trigger('close', { originalEvent : evt });
5860
+ };
5861
+
5862
+ /**
5863
+ * Helper method to abstract the "enabled" (not "disabled") state of this
5864
+ * object.
5865
+ *
5866
+ * @return {true} if the instance is not disabled.
5867
+ * @return {false} if the instance is disabled.
5868
+ */
5869
+ Select2.prototype.isEnabled = function () {
5870
+ return !this.isDisabled();
5871
+ };
5872
+
5873
+ /**
5874
+ * Helper method to abstract the "disabled" state of this object.
5875
+ *
5876
+ * @return {true} if the disabled option is true.
5877
+ * @return {false} if the disabled option is false.
5878
+ */
5879
+ Select2.prototype.isDisabled = function () {
5880
+ return this.options.get('disabled');
5664
5881
  };
5665
5882
 
5666
5883
  Select2.prototype.isOpen = function () {
@@ -5737,7 +5954,7 @@ S2.define('select2/core',[
5737
5954
  });
5738
5955
  }
5739
5956
 
5740
- this.$element.val(newVal).trigger('change');
5957
+ this.$element.val(newVal).trigger('input').trigger('change');
5741
5958
  };
5742
5959
 
5743
5960
  Select2.prototype.destroy = function () {
@@ -6072,13 +6289,13 @@ S2.define('select2/compat/inputData',[
6072
6289
  });
6073
6290
 
6074
6291
  this.$element.val(data.id);
6075
- this.$element.trigger('change');
6292
+ this.$element.trigger('input').trigger('change');
6076
6293
  } else {
6077
6294
  var value = this.$element.val();
6078
6295
  value += this._valueSeparator + data.id;
6079
6296
 
6080
6297
  this.$element.val(value);
6081
- this.$element.trigger('change');
6298
+ this.$element.trigger('input').trigger('change');
6082
6299
  }
6083
6300
  };
6084
6301
 
@@ -6101,7 +6318,7 @@ S2.define('select2/compat/inputData',[
6101
6318
  }
6102
6319
 
6103
6320
  self.$element.val(values.join(self._valueSeparator));
6104
- self.$element.trigger('change');
6321
+ self.$element.trigger('input').trigger('change');
6105
6322
  });
6106
6323
  };
6107
6324