select2-rails 3.5.9.1 → 3.5.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  Copyright 2012 Igor Vaynberg
3
3
 
4
- Version: 3.5.1
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
@@ -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 = {
@@ -132,7 +132,7 @@ the specific language governing permissions and limitations under the Apache Lic
132
132
 
133
133
  function measureScrollbar () {
134
134
  var $template = $( MEASURE_SCROLLBAR_TEMPLATE );
135
- $template.appendTo('body');
135
+ $template.appendTo(document.body);
136
136
 
137
137
  var dim = {
138
138
  width: $template.width() - $template[0].clientWidth,
@@ -160,16 +160,16 @@ the specific language governing permissions and limitations under the Apache Lic
160
160
  }
161
161
 
162
162
  /**
163
- * 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
164
164
  * strings
165
165
  * @param string
166
166
  * @param separator
167
167
  */
168
- function splitVal(string, separator) {
168
+ function splitVal(string, separator, transform) {
169
169
  var val, i, l;
170
170
  if (string === null || string.length < 1) return [];
171
171
  val = string.split(separator);
172
- 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]);
173
173
  return val;
174
174
  }
175
175
 
@@ -311,7 +311,7 @@ the specific language governing permissions and limitations under the Apache Lic
311
311
  whiteSpace: "nowrap"
312
312
  });
313
313
  sizer.attr("class","select2-sizer");
314
- $("body").append(sizer);
314
+ $(document.body).append(sizer);
315
315
  }
316
316
  sizer.text(e.val());
317
317
  return sizer.width();
@@ -450,7 +450,7 @@ the specific language governing permissions and limitations under the Apache Lic
450
450
  hasError: true,
451
451
  jqXHR: jqXHR,
452
452
  textStatus: textStatus,
453
- errorThrown: errorThrown,
453
+ errorThrown: errorThrown
454
454
  };
455
455
 
456
456
  query.callback(results);
@@ -699,12 +699,15 @@ the specific language governing permissions and limitations under the Apache Lic
699
699
 
700
700
  this.container = this.createContainer();
701
701
 
702
- this.liveRegion = $("<span>", {
703
- role: "status",
704
- "aria-live": "polite"
705
- })
706
- .addClass("select2-hidden-accessible")
707
- .appendTo(document.body);
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
+ }
708
711
 
709
712
  this.containerId="s2id_"+(opts.element.attr("id") || "autogen"+nextUid());
710
713
  this.containerEventName= this.containerId
@@ -714,7 +717,7 @@ the specific language governing permissions and limitations under the Apache Lic
714
717
 
715
718
  this.container.attr("title", opts.element.attr("title"));
716
719
 
717
- this.body = $("body");
720
+ this.body = $(document.body);
718
721
 
719
722
  syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
720
723
 
@@ -811,7 +814,7 @@ the specific language governing permissions and limitations under the Apache Lic
811
814
  // focusin can cause focus wars between modals and select2 since the dropdown is outside the modal.
812
815
  this.dropdown.on("click mouseup mousedown touchstart touchend focusin", function (e) { e.stopPropagation(); });
813
816
 
814
- this.nextSearchTerm = undefined;
817
+ this.lastSearchTerm = undefined;
815
818
 
816
819
  if ($.isFunction(this.opts.initSelection)) {
817
820
  // initialize selection based on the current value of the source element
@@ -850,9 +853,11 @@ the specific language governing permissions and limitations under the Apache Lic
850
853
 
851
854
  this.close();
852
855
 
853
- if (element.length && element[0].detachEvent) {
856
+ if (element.length && element[0].detachEvent && self._sync) {
854
857
  element.each(function () {
855
- this.detachEvent("onpropertychange", self._sync);
858
+ if (self._sync) {
859
+ this.detachEvent("onpropertychange", self._sync);
860
+ }
856
861
  });
857
862
  }
858
863
  if (this.propertyObserver) {
@@ -865,17 +870,21 @@ the specific language governing permissions and limitations under the Apache Lic
865
870
  select2.container.remove();
866
871
  select2.liveRegion.remove();
867
872
  select2.dropdown.remove();
868
- element
869
- .removeClass("select2-offscreen")
870
- .removeData("select2")
871
- .off(".select2")
872
- .prop("autofocus", this.autofocus || false);
873
- if (this.elementTabIndex) {
874
- 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();
875
885
  } else {
876
- element.removeAttr("tabindex");
886
+ element.css("display", "");
877
887
  }
878
- element.show();
879
888
  }
880
889
 
881
890
  cleanupJQueryElements.call(this,
@@ -927,6 +936,155 @@ the specific language governing permissions and limitations under the Apache Lic
927
936
  });
928
937
  }
929
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
+
930
1088
  opts = $.extend({}, {
931
1089
  populateResults: function(container, results, query) {
932
1090
  var populate, id=this.opts.id, liveRegion=this.liveRegion;
@@ -970,7 +1128,6 @@ the specific language governing permissions and limitations under the Apache Lic
970
1128
 
971
1129
 
972
1130
  if (compound) {
973
-
974
1131
  innerContainer=$("<ul></ul>");
975
1132
  innerContainer.addClass("select2-result-sub");
976
1133
  populate(result.children, innerContainer, depth+1);
@@ -1041,7 +1198,6 @@ the specific language governing permissions and limitations under the Apache Lic
1041
1198
  opts.id=function(e) { return e.id; };
1042
1199
  } else {
1043
1200
  if (!("query" in opts)) {
1044
-
1045
1201
  if ("ajax" in opts) {
1046
1202
  ajaxUrl = opts.element.data("ajax-url");
1047
1203
  if (ajaxUrl && ajaxUrl.length > 0) {
@@ -1058,7 +1214,7 @@ the specific language governing permissions and limitations under the Apache Lic
1058
1214
  if (opts.initSelection === undefined) {
1059
1215
  opts.initSelection = function (element, callback) {
1060
1216
  var data = [];
1061
- $(splitVal(element.val(), opts.separator)).each(function () {
1217
+ $(splitVal(element.val(), opts.separator, opts.transformVal)).each(function () {
1062
1218
  var obj = { id: this, text: this },
1063
1219
  tags = opts.tags;
1064
1220
  if ($.isFunction(tags)) tags=tags();
@@ -1113,11 +1269,15 @@ the specific language governing permissions and limitations under the Apache Lic
1113
1269
  if (readonly === undefined) readonly = false;
1114
1270
  this.readonly(readonly);
1115
1271
 
1116
- syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
1117
- this.container.addClass(evaluate(this.opts.containerCssClass, this.opts.element));
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
+ }
1118
1276
 
1119
- syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass);
1120
- this.dropdown.addClass(evaluate(this.opts.dropdownCssClass, this.opts.element));
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
+ }
1121
1281
 
1122
1282
  });
1123
1283
 
@@ -1222,9 +1382,10 @@ the specific language governing permissions and limitations under the Apache Lic
1222
1382
  // abstract
1223
1383
  positionDropdown: function() {
1224
1384
  var $dropdown = this.dropdown,
1225
- offset = this.container.offset(),
1226
- height = this.container.outerHeight(false),
1227
- width = this.container.outerWidth(false),
1385
+ container = this.container,
1386
+ offset = container.offset(),
1387
+ height = container.outerHeight(false),
1388
+ width = container.outerWidth(false),
1228
1389
  dropHeight = $dropdown.outerHeight(false),
1229
1390
  $window = $(window),
1230
1391
  windowWidth = $window.width(),
@@ -1236,7 +1397,12 @@ the specific language governing permissions and limitations under the Apache Lic
1236
1397
  enoughRoomBelow = dropTop + dropHeight <= viewportBottom,
1237
1398
  enoughRoomAbove = (offset.top - dropHeight) >= $window.scrollTop(),
1238
1399
  dropWidth = $dropdown.outerWidth(false),
1239
- 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
+ },
1240
1406
  aboveNow = $dropdown.hasClass("select2-drop-above"),
1241
1407
  bodyOffset,
1242
1408
  above,
@@ -1271,7 +1437,6 @@ the specific language governing permissions and limitations under the Apache Lic
1271
1437
  dropTop = offset.top + height;
1272
1438
  dropLeft = offset.left;
1273
1439
  dropWidth = $dropdown.outerWidth(false);
1274
- enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight;
1275
1440
  $dropdown.show();
1276
1441
 
1277
1442
  // fix so the cursor does not move to the left within the search-textbox in IE
@@ -1286,7 +1451,6 @@ the specific language governing permissions and limitations under the Apache Lic
1286
1451
  dropWidth = $dropdown.outerWidth(false) + (resultsListNode.scrollHeight === resultsListNode.clientHeight ? 0 : scrollBarDimensions.width);
1287
1452
  dropWidth > width ? width = dropWidth : dropWidth = width;
1288
1453
  dropHeight = $dropdown.outerHeight(false);
1289
- enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight;
1290
1454
  }
1291
1455
  else {
1292
1456
  this.container.removeClass('select2-drop-auto-width');
@@ -1302,7 +1466,7 @@ the specific language governing permissions and limitations under the Apache Lic
1302
1466
  dropLeft -= bodyOffset.left;
1303
1467
  }
1304
1468
 
1305
- if (!enoughRoomOnRight) {
1469
+ if (!enoughRoomOnRight() && enoughRoomOnLeft()) {
1306
1470
  dropLeft = offset.left + this.container.outerWidth(false) - dropWidth;
1307
1471
  }
1308
1472
 
@@ -1312,10 +1476,11 @@ the specific language governing permissions and limitations under the Apache Lic
1312
1476
  };
1313
1477
 
1314
1478
  if (above) {
1315
- css.top = offset.top - dropHeight;
1316
- css.bottom = 'auto';
1317
1479
  this.container.addClass("select2-drop-above");
1318
1480
  $dropdown.addClass("select2-drop-above");
1481
+ dropHeight = $dropdown.outerHeight(false);
1482
+ css.top = offset.top - dropHeight;
1483
+ css.bottom = 'auto';
1319
1484
  }
1320
1485
  else {
1321
1486
  css.top = dropTop;
@@ -1391,7 +1556,7 @@ the specific language governing permissions and limitations under the Apache Lic
1391
1556
 
1392
1557
  // create the dropdown mask if doesn't already exist
1393
1558
  mask = $("#select2-drop-mask");
1394
- if (mask.length == 0) {
1559
+ if (mask.length === 0) {
1395
1560
  mask = $(document.createElement("div"));
1396
1561
  mask.attr("id","select2-drop-mask").attr("class","select2-drop-mask");
1397
1562
  mask.hide();
@@ -1468,6 +1633,9 @@ the specific language governing permissions and limitations under the Apache Lic
1468
1633
 
1469
1634
  this.clearSearch();
1470
1635
  this.search.removeClass("select2-active");
1636
+
1637
+ // Remove the aria active descendant for highlighted element
1638
+ this.search.removeAttr("aria-activedescendant");
1471
1639
  this.opts.element.trigger($.Event("select2-close"));
1472
1640
  },
1473
1641
 
@@ -1486,6 +1654,27 @@ the specific language governing permissions and limitations under the Apache Lic
1486
1654
 
1487
1655
  },
1488
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
+
1489
1678
  //abstract
1490
1679
  getMaximumSelectionSize: function() {
1491
1680
  return evaluate(this.opts.maximumSelectionSize, this.opts.element);
@@ -1525,7 +1714,7 @@ the specific language governing permissions and limitations under the Apache Lic
1525
1714
  }
1526
1715
  }
1527
1716
 
1528
- rb = results.offset().top + results.outerHeight(true);
1717
+ rb = results.offset().top + results.outerHeight(false);
1529
1718
  if (hb > rb) {
1530
1719
  results.scrollTop(results.scrollTop() + (hb - rb));
1531
1720
  }
@@ -1648,7 +1837,7 @@ the specific language governing permissions and limitations under the Apache Lic
1648
1837
  self.postprocessResults(data, false, false);
1649
1838
 
1650
1839
  if (data.more===true) {
1651
- more.detach().appendTo(results).text(evaluate(self.opts.formatLoadMore, self.opts.element, page+1));
1840
+ more.detach().appendTo(results).html(self.opts.escapeMarkup(evaluate(self.opts.formatLoadMore, self.opts.element, page+1)));
1652
1841
  window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10);
1653
1842
  } else {
1654
1843
  more.remove();
@@ -1701,7 +1890,7 @@ the specific language governing permissions and limitations under the Apache Lic
1701
1890
  self.liveRegion.text(results.text());
1702
1891
  }
1703
1892
  else {
1704
- self.liveRegion.text(self.opts.formatMatches(results.find('.select2-result-selectable').length));
1893
+ self.liveRegion.text(self.opts.formatMatches(results.find('.select2-result-selectable:not(".select2-selected")').length));
1705
1894
  }
1706
1895
  }
1707
1896
 
@@ -1799,6 +1988,9 @@ the specific language governing permissions and limitations under the Apache Lic
1799
1988
 
1800
1989
  if (data.results.length === 0 && checkFormatter(opts.formatNoMatches, "formatNoMatches")) {
1801
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
+ }
1802
1994
  return;
1803
1995
  }
1804
1996
 
@@ -1903,7 +2095,7 @@ the specific language governing permissions and limitations under the Apache Lic
1903
2095
  } else if (this.opts.width === "copy" || this.opts.width === "resolve") {
1904
2096
  // check if there is inline style on the element that contains width
1905
2097
  style = this.opts.element.attr('style');
1906
- if (style !== undefined) {
2098
+ if (typeof(style) === "string") {
1907
2099
  attrs = style.split(';');
1908
2100
  for (i = 0, l = attrs.length; i < l; i = i + 1) {
1909
2101
  attr = attrs[i].replace(/\s/g, '');
@@ -2002,14 +2194,7 @@ the specific language governing permissions and limitations under the Apache Lic
2002
2194
  }
2003
2195
  }
2004
2196
 
2005
- // initializes search's value with nextSearchTerm (if defined by user)
2006
- // ignore nextSearchTerm if the dropdown is opened by the user pressing a letter
2007
- if(this.search.val() === "") {
2008
- if(this.nextSearchTerm != undefined){
2009
- this.search.val(this.nextSearchTerm);
2010
- this.search.select();
2011
- }
2012
- }
2197
+ this.prefillNextSearchTerm();
2013
2198
 
2014
2199
  this.focusser.prop("disabled", true).val("");
2015
2200
  this.updateResults(true);
@@ -2096,6 +2281,7 @@ the specific language governing permissions and limitations under the Apache Lic
2096
2281
  this.focusser.attr("id", "s2id_autogen"+idSuffix);
2097
2282
 
2098
2283
  elementLabel = $("label[for='" + this.opts.element.attr("id") + "']");
2284
+ this.opts.element.on('focus.select2', this.bind(function () { this.focus(); }));
2099
2285
 
2100
2286
  this.focusser.prev()
2101
2287
  .text(elementLabel.text())
@@ -2151,7 +2337,7 @@ the specific language governing permissions and limitations under the Apache Lic
2151
2337
  // without this the search field loses focus which is annoying
2152
2338
  if (document.activeElement === this.body.get(0)) {
2153
2339
  window.setTimeout(this.bind(function() {
2154
- if (this.opened()) {
2340
+ if (this.opened() && this.results && this.results.length > 1) {
2155
2341
  this.search.focus();
2156
2342
  }
2157
2343
  }), 0);
@@ -2200,11 +2386,17 @@ the specific language governing permissions and limitations under the Apache Lic
2200
2386
  }));
2201
2387
 
2202
2388
  selection.on("mousedown touchstart", "abbr", this.bind(function (e) {
2203
- if (!this.isInterfaceEnabled()) return;
2389
+ if (!this.isInterfaceEnabled()) {
2390
+ return;
2391
+ }
2392
+
2204
2393
  this.clear();
2205
2394
  killEventImmediately(e);
2206
2395
  this.close();
2207
- this.selection.focus();
2396
+
2397
+ if (this.selection) {
2398
+ this.selection.focus();
2399
+ }
2208
2400
  }));
2209
2401
 
2210
2402
  selection.on("mousedown touchstart", this.bind(function (e) {
@@ -2253,7 +2445,7 @@ the specific language governing permissions and limitations under the Apache Lic
2253
2445
  }));
2254
2446
 
2255
2447
  this.initContainerWidth();
2256
- this.opts.element.addClass("select2-offscreen");
2448
+ this.opts.element.hide();
2257
2449
  this.setPlaceholder();
2258
2450
 
2259
2451
  },
@@ -2297,7 +2489,7 @@ the specific language governing permissions and limitations under the Apache Lic
2297
2489
  self.updateSelection(selected);
2298
2490
  self.close();
2299
2491
  self.setPlaceholder();
2300
- self.nextSearchTerm = self.opts.nextSearchTerm(selected, self.search.val());
2492
+ self.lastSearchTerm = self.search.val();
2301
2493
  }
2302
2494
  });
2303
2495
  }
@@ -2434,7 +2626,7 @@ the specific language governing permissions and limitations under the Apache Lic
2434
2626
 
2435
2627
  this.opts.element.trigger({ type: "select2-selected", val: this.id(data), choice: data });
2436
2628
 
2437
- this.nextSearchTerm = this.opts.nextSearchTerm(data, this.search.val());
2629
+ this.lastSearchTerm = this.search.val();
2438
2630
  this.close();
2439
2631
 
2440
2632
  if ((!options || !options.noFocus) && this.opts.shouldFocusInput(this)) {
@@ -2488,9 +2680,23 @@ the specific language governing permissions and limitations under the Apache Lic
2488
2680
 
2489
2681
  if (arguments.length > 1) {
2490
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
+ }
2491
2690
  }
2492
2691
 
2493
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
+
2494
2700
  this.select
2495
2701
  .val(val)
2496
2702
  .find("option").filter(function() { return this.selected }).each2(function (i, elm) {
@@ -2539,6 +2745,13 @@ the specific language governing permissions and limitations under the Apache Lic
2539
2745
  if (data == undefined) data = null;
2540
2746
  return data;
2541
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
+
2542
2755
  if (arguments.length > 1) {
2543
2756
  triggerChange = arguments[1];
2544
2757
  }
@@ -2582,7 +2795,6 @@ the specific language governing permissions and limitations under the Apache Lic
2582
2795
  self=this;
2583
2796
 
2584
2797
  // TODO validate placeholder is a string if specified
2585
-
2586
2798
  if (opts.element.get(0).tagName.toLowerCase() === "select") {
2587
2799
  // install the selection initializer
2588
2800
  opts.initSelection = function (element, callback) {
@@ -2597,7 +2809,7 @@ the specific language governing permissions and limitations under the Apache Lic
2597
2809
  } else if ("data" in opts) {
2598
2810
  // install default initSelection when applied to hidden input and data is local
2599
2811
  opts.initSelection = opts.initSelection || function (element, callback) {
2600
- var ids = splitVal(element.val(), opts.separator);
2812
+ var ids = splitVal(element.val(), opts.separator, opts.transformVal);
2601
2813
  //search in data by array of ids, storing matching items in a list
2602
2814
  var matches = [];
2603
2815
  opts.query({
@@ -2674,8 +2886,7 @@ the specific language governing permissions and limitations under the Apache Lic
2674
2886
  this.selection = selection = this.container.find(selector);
2675
2887
 
2676
2888
  var _this = this;
2677
- this.selection.on("click", ".select2-search-choice:not(.select2-locked)", function (e) {
2678
- //killEvent(e);
2889
+ this.selection.on("click", ".select2-container:not(.select2-container-disabled) .select2-search-choice:not(.select2-locked)", function (e) {
2679
2890
  _this.search[0].focus();
2680
2891
  _this.selectChoice($(this));
2681
2892
  });
@@ -2686,6 +2897,7 @@ the specific language governing permissions and limitations under the Apache Lic
2686
2897
  this.search.prev()
2687
2898
  .text($("label[for='" + this.opts.element.attr("id") + "']").text())
2688
2899
  .attr('for', this.search.attr('id'));
2900
+ this.opts.element.on('focus.select2', this.bind(function () { this.focus(); }));
2689
2901
 
2690
2902
  this.search.on("input paste", this.bind(function() {
2691
2903
  if (this.search.attr('placeholder') && this.search.val().length == 0) return;
@@ -2837,7 +3049,7 @@ the specific language governing permissions and limitations under the Apache Lic
2837
3049
  }));
2838
3050
 
2839
3051
  this.initContainerWidth();
2840
- this.opts.element.addClass("select2-offscreen");
3052
+ this.opts.element.hide();
2841
3053
 
2842
3054
  // set the placeholder if necessary
2843
3055
  this.clearSearch();
@@ -2903,16 +3115,9 @@ the specific language governing permissions and limitations under the Apache Lic
2903
3115
 
2904
3116
  this.focusSearch();
2905
3117
 
2906
- // initializes search's value with nextSearchTerm (if defined by user)
2907
- // ignore nextSearchTerm if the dropdown is opened by the user pressing a letter
2908
- if(this.search.val() === "") {
2909
- if(this.nextSearchTerm != undefined){
2910
- this.search.val(this.nextSearchTerm);
2911
- this.search.select();
2912
- }
2913
- }
2914
-
3118
+ this.prefillNextSearchTerm();
2915
3119
  this.updateResults(true);
3120
+
2916
3121
  if (this.opts.shouldFocusInput(this)) {
2917
3122
  this.search.focus();
2918
3123
  }
@@ -2938,21 +3143,18 @@ the specific language governing permissions and limitations under the Apache Lic
2938
3143
 
2939
3144
  // multi
2940
3145
  updateSelection: function (data) {
2941
- var ids = [], filtered = [], self = this;
3146
+ var ids = {}, filtered = [], self = this;
2942
3147
 
2943
3148
  // filter out duplicates
2944
3149
  $(data).each(function () {
2945
- if (indexOf(self.id(this), ids) < 0) {
2946
- ids.push(self.id(this));
3150
+ if (!(self.id(this) in ids)) {
3151
+ ids[self.id(this)] = 0;
2947
3152
  filtered.push(this);
2948
3153
  }
2949
3154
  });
2950
- data = filtered;
2951
3155
 
2952
3156
  this.selection.find(".select2-search-choice").remove();
2953
- $(data).each(function () {
2954
- self.addSelectedChoice(this);
2955
- });
3157
+ this.addSelectedChoice(filtered);
2956
3158
  self.postprocessResults();
2957
3159
  },
2958
3160
 
@@ -2979,7 +3181,7 @@ the specific language governing permissions and limitations under the Apache Lic
2979
3181
  this.opts.element.trigger({ type: "selected", val: this.id(data), choice: data });
2980
3182
 
2981
3183
  // keep track of the search's value before it gets cleared
2982
- this.nextSearchTerm = this.opts.nextSearchTerm(data, this.search.val());
3184
+ this.lastSearchTerm = this.search.val();
2983
3185
 
2984
3186
  this.clearSearch();
2985
3187
  this.updateResults();
@@ -2999,10 +3201,8 @@ the specific language governing permissions and limitations under the Apache Lic
2999
3201
  this.updateResults(true);
3000
3202
  } else {
3001
3203
  // initializes search's value with nextSearchTerm and update search result
3002
- if(this.nextSearchTerm != undefined){
3003
- this.search.val(this.nextSearchTerm);
3204
+ if (this.prefillNextSearchTerm()) {
3004
3205
  this.updateResults();
3005
- this.search.select();
3006
3206
  }
3007
3207
  }
3008
3208
  this.positionDropdown();
@@ -3028,6 +3228,14 @@ the specific language governing permissions and limitations under the Apache Lic
3028
3228
  },
3029
3229
 
3030
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) {
3031
3239
  var enableChoice = !data.locked,
3032
3240
  enabledItem = $(
3033
3241
  "<li class='select2-search-choice'>" +
@@ -3040,13 +3248,12 @@ the specific language governing permissions and limitations under the Apache Lic
3040
3248
  "</li>");
3041
3249
  var choice = enableChoice ? enabledItem : disabledItem,
3042
3250
  id = this.id(data),
3043
- val = this.getVal(),
3044
3251
  formatted,
3045
3252
  cssClass;
3046
3253
 
3047
3254
  formatted=this.opts.formatSelection(data, choice.find("div"), this.opts.escapeMarkup);
3048
3255
  if (formatted != undefined) {
3049
- choice.find("div").replaceWith("<div>"+formatted+"</div>");
3256
+ choice.find("div").replaceWith($("<div></div>").html(formatted));
3050
3257
  }
3051
3258
  cssClass=this.opts.formatSelectionCssClass(data, choice.find("div"));
3052
3259
  if (cssClass != undefined) {
@@ -3074,8 +3281,7 @@ the specific language governing permissions and limitations under the Apache Lic
3074
3281
  choice.data("select2-data", data);
3075
3282
  choice.insertBefore(this.searchContainer);
3076
3283
 
3077
- val.push(id);
3078
- this.setVal(val);
3284
+ return id;
3079
3285
  },
3080
3286
 
3081
3287
  // multi
@@ -3144,7 +3350,7 @@ the specific language governing permissions and limitations under the Apache Lic
3144
3350
  }
3145
3351
  });
3146
3352
 
3147
- if (this.highlight() == -1 && noHighlightUpdate !== false){
3353
+ if (this.highlight() == -1 && noHighlightUpdate !== false && this.opts.closeOnSelect === true){
3148
3354
  self.highlight(0);
3149
3355
  }
3150
3356
 
@@ -3201,20 +3407,22 @@ the specific language governing permissions and limitations under the Apache Lic
3201
3407
  return val === null ? [] : val;
3202
3408
  } else {
3203
3409
  val = this.opts.element.val();
3204
- return splitVal(val, this.opts.separator);
3410
+ return splitVal(val, this.opts.separator, this.opts.transformVal);
3205
3411
  }
3206
3412
  },
3207
3413
 
3208
3414
  // multi
3209
3415
  setVal: function (val) {
3210
- var unique;
3211
3416
  if (this.select) {
3212
3417
  this.select.val(val);
3213
3418
  } else {
3214
- unique = [];
3419
+ var unique = [], valMap = {};
3215
3420
  // filter out duplicates
3216
3421
  $(val).each(function () {
3217
- if (indexOf(this, unique) < 0) unique.push(this);
3422
+ if (!(this in valMap)) {
3423
+ unique.push(this);
3424
+ valMap[this] = 0;
3425
+ }
3218
3426
  });
3219
3427
  this.opts.element.val(unique.length === 0 ? "" : unique.join(this.opts.separator));
3220
3428
  }
@@ -3230,11 +3438,9 @@ the specific language governing permissions and limitations under the Apache Lic
3230
3438
  for (var j = 0; j < old.length; j++) {
3231
3439
  if (equal(this.opts.id(current[i]), this.opts.id(old[j]))) {
3232
3440
  current.splice(i, 1);
3233
- if(i>0){
3234
- i--;
3235
- }
3441
+ i--;
3236
3442
  old.splice(j, 1);
3237
- j--;
3443
+ break;
3238
3444
  }
3239
3445
  }
3240
3446
  }
@@ -3404,6 +3610,7 @@ the specific language governing permissions and limitations under the Apache Lic
3404
3610
 
3405
3611
  // plugin defaults, accessible to users
3406
3612
  $.fn.select2.defaults = {
3613
+ debug: false,
3407
3614
  width: "copy",
3408
3615
  loadMorePadding: 0,
3409
3616
  closeOnSelect: true,
@@ -3414,11 +3621,14 @@ the specific language governing permissions and limitations under the Apache Lic
3414
3621
  dropdownCssClass: "",
3415
3622
  formatResult: function(result, container, query, escapeMarkup) {
3416
3623
  var markup=[];
3417
- markMatch(result.text, query.term, markup, escapeMarkup);
3624
+ markMatch(this.text(result), query.term, markup, escapeMarkup);
3418
3625
  return markup.join("");
3419
3626
  },
3627
+ transformVal: function(val) {
3628
+ return $.trim(val);
3629
+ },
3420
3630
  formatSelection: function (data, container, escapeMarkup) {
3421
- return data ? escapeMarkup(data.text) : undefined;
3631
+ return data ? escapeMarkup(this.text(data)) : undefined;
3422
3632
  },
3423
3633
  sortResults: function (results, container, query) {
3424
3634
  return results;
@@ -3430,6 +3640,17 @@ the specific language governing permissions and limitations under the Apache Lic
3430
3640
  maximumInputLength: null,
3431
3641
  maximumSelectionSize: 0,
3432
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
+ },
3433
3654
  matcher: function(term, text) {
3434
3655
  return stripDiacritics(''+text).toUpperCase().indexOf(stripDiacritics(''+term).toUpperCase()) >= 0;
3435
3656
  },
@@ -3473,7 +3694,7 @@ the specific language governing permissions and limitations under the Apache Lic
3473
3694
  formatInputTooLong: function (input, max) { var n = input.length - max; return "Please delete " + n + " character" + (n == 1 ? "" : "s"); },
3474
3695
  formatSelectionTooBig: function (limit) { return "You can only select " + limit + " item" + (limit == 1 ? "" : "s"); },
3475
3696
  formatLoadMore: function (pageNumber) { return "Loading more results…"; },
3476
- formatSearching: function () { return "Searching…"; },
3697
+ formatSearching: function () { return "Searching…"; }
3477
3698
  };
3478
3699
 
3479
3700
  $.extend($.fn.select2.defaults, $.fn.select2.locales['en']);