select2-rails 3.5.9.1 → 3.5.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -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']);