select2-rails 3.0.0 → 3.1.0

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.
data/README.md CHANGED
@@ -26,7 +26,7 @@ Add to your `app/assets/stylesheets/application.css`:
26
26
  *= require select2
27
27
 
28
28
  ## Version
29
- From `v2.1.0` on, `select2-rails`'s version will match the version of `Select2` it uses. Currently, `select2-rails` uses `Select2 v2.1`.
29
+ From `v2.1.0` on, `select2-rails`'s version will match the version of `Select2` it uses. Currently, `select2-rails` uses `Select2 v3.1`.
30
30
 
31
31
  The last number of the version is the patch version specific to the gem. For example, for a version of the form `2.x.y`, `2.x` is the release of `Select2` we should be compatible with, and y is the patch version specific to the gem (ie. to resolve any gem-specific issues that crop up).
32
32
 
@@ -1,5 +1,5 @@
1
1
  module Select2
2
2
  module Rails
3
- VERSION = "3.0.0"
3
+ VERSION = "3.1.0"
4
4
  end
5
5
  end
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  Copyright 2012 Igor Vaynberg
3
3
 
4
- Version: 3.0 Timestamp: Tue Jul 31 21:09:16 PDT 2012
4
+ Version: 3.1 Timestamp: Tue Aug 14 09:05:17 PDT 2012
5
5
 
6
6
  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in
7
7
  compliance with the License. You may obtain a copy of the License in the LICENSE file, or at:
@@ -13,23 +13,23 @@
13
13
  See the License for the specific language governing permissions and limitations under the License.
14
14
  */
15
15
  (function ($) {
16
- if(typeof $.fn.each2 == "undefined"){
17
- $.fn.extend({
18
- /*
19
- * 4-10 times faster .each replacement
20
- * use it carefully, as it overrides jQuery context of element on each iteration
21
- */
22
- each2 : function (c) {
23
- var j = $([0]), i = -1, l = this.length;
24
- while (
25
- ++i < l
26
- && (j.context = j[0] = this[i])
27
- && c.call(j[0], i, j) !== false //"this"=DOM, i=index, j=jQuery object
28
- );
29
- return this;
30
- }
31
- });
32
- }
16
+ if(typeof $.fn.each2 == "undefined"){
17
+ $.fn.extend({
18
+ /*
19
+ * 4-10 times faster .each replacement
20
+ * use it carefully, as it overrides jQuery context of element on each iteration
21
+ */
22
+ each2 : function (c) {
23
+ var j = $([0]), i = -1, l = this.length;
24
+ while (
25
+ ++i < l
26
+ && (j.context = j[0] = this[i])
27
+ && c.call(j[0], i, j) !== false //"this"=DOM, i=index, j=jQuery object
28
+ );
29
+ return this;
30
+ }
31
+ });
32
+ }
33
33
  })(jQuery);
34
34
 
35
35
  (function ($, undefined) {
@@ -71,8 +71,8 @@
71
71
  }
72
72
  return false;
73
73
  },
74
- isControl: function (k) {
75
- k = k.which ? k.which : k;
74
+ isControl: function (e) {
75
+ var k = e.which;
76
76
  switch (k) {
77
77
  case KEY.SHIFT:
78
78
  case KEY.CTRL:
@@ -80,7 +80,7 @@
80
80
  return true;
81
81
  }
82
82
 
83
- if (k.metaKey) return true;
83
+ if (e.metaKey) return true;
84
84
 
85
85
  return false;
86
86
  },
@@ -94,7 +94,7 @@
94
94
 
95
95
  function escapeMarkup(markup) {
96
96
  if (markup && typeof(markup) === "string") {
97
- return markup.replace("&", "&amp;");
97
+ return markup.replace(/&/g, "&amp;");
98
98
  } else {
99
99
  return markup;
100
100
  }
@@ -181,7 +181,7 @@
181
181
  * the elements under the pointer are scrolled.
182
182
  */
183
183
  function installFilteredMouseMove(element) {
184
- element.bind("mousemove", function (e) {
184
+ element.bind("mousemove", function (e) {
185
185
  var lastpos = $.data(document, "select2-lastpos");
186
186
  if (lastpos === undefined || lastpos.x !== e.pageX || lastpos.y !== e.pageY) {
187
187
  $(e.target).trigger("mousemove-filtered", e);
@@ -233,21 +233,21 @@
233
233
 
234
234
  function measureTextWidth(e) {
235
235
  if (!sizer){
236
- var style = e[0].currentStyle || window.getComputedStyle(e[0], null);
237
- sizer = $("<div></div>").css({
238
- position: "absolute",
239
- left: "-10000px",
240
- top: "-10000px",
241
- display: "none",
242
- fontSize: style.fontSize,
243
- fontFamily: style.fontFamily,
244
- fontStyle: style.fontStyle,
245
- fontWeight: style.fontWeight,
246
- letterSpacing: style.letterSpacing,
247
- textTransform: style.textTransform,
248
- whiteSpace: "nowrap"
249
- });
250
- $("body").append(sizer);
236
+ var style = e[0].currentStyle || window.getComputedStyle(e[0], null);
237
+ sizer = $("<div></div>").css({
238
+ position: "absolute",
239
+ left: "-10000px",
240
+ top: "-10000px",
241
+ display: "none",
242
+ fontSize: style.fontSize,
243
+ fontFamily: style.fontFamily,
244
+ fontStyle: style.fontStyle,
245
+ fontWeight: style.fontWeight,
246
+ letterSpacing: style.letterSpacing,
247
+ textTransform: style.textTransform,
248
+ whiteSpace: "nowrap"
249
+ });
250
+ $("body").append(sizer);
251
251
  }
252
252
  sizer.text(e.val());
253
253
  return sizer.width();
@@ -277,6 +277,7 @@
277
277
  * @param options.url url for the data
278
278
  * @param options.data a function(searchTerm, pageNumber, context) that should return an object containing query string parameters for the above url.
279
279
  * @param options.dataType request data type: ajax, jsonp, other datatatypes supported by jQuery's $.ajax function or the transport function if specified
280
+ * @param options.traditional a boolean flag that should be true if you wish to use the traditional style of param serialization for the ajax request
280
281
  * @param options.quietMillis (optional) milliseconds to wait before making the ajaxRequest, helps debounce the ajax function if invoked too often
281
282
  * @param options.results a function(remoteData, pageNumber) that converts data returned form the remote request to the format expected by Select2.
282
283
  * The expected format is an object containing the following keys:
@@ -297,6 +298,7 @@
297
298
  var requestNumber = requestSequence, // this request's sequence number
298
299
  data = options.data, // ajax data function
299
300
  transport = options.transport || $.ajax,
301
+ traditional = options.traditional || false,
300
302
  type = options.type || 'GET'; // set type of request (GET or POST)
301
303
 
302
304
  data = data.call(this, query.term, query.page, query.context);
@@ -308,6 +310,7 @@
308
310
  dataType: options.dataType,
309
311
  data: data,
310
312
  type: type,
313
+ traditional: traditional,
311
314
  success: function (data) {
312
315
  if (requestNumber < requestSequence) {
313
316
  return;
@@ -396,10 +399,79 @@
396
399
  */
397
400
  function checkFormatter(formatter, formatterName) {
398
401
  if ($.isFunction(formatter)) return true;
399
- if (!formatter) return fasle;
402
+ if (!formatter) return false;
400
403
  throw new Error("formatterName must be a function or a falsy value");
401
404
  }
402
405
 
406
+ function evaluate(val) {
407
+ return $.isFunction(val) ? val() : val;
408
+ }
409
+
410
+ function countResults(results) {
411
+ var count = 0;
412
+ $.each(results, function(i, item) {
413
+ if (item.children) {
414
+ count += countResults(item.children);
415
+ } else {
416
+ count++;
417
+ }
418
+ });
419
+ return count;
420
+ }
421
+
422
+ /**
423
+ * Default tokenizer. This function uses breaks the input on substring match of any string from the
424
+ * opts.tokenSeparators array and uses opts.createSearchChoice to create the choice object. Both of those
425
+ * two options have to be defined in order for the tokenizer to work.
426
+ *
427
+ * @param input text user has typed so far or pasted into the search field
428
+ * @param selection currently selected choices
429
+ * @param selectCallback function(choice) callback tho add the choice to selection
430
+ * @param opts select2's opts
431
+ * @return undefined/null to leave the current input unchanged, or a string to change the input to the returned value
432
+ */
433
+ function defaultTokenizer(input, selection, selectCallback, opts) {
434
+ var original = input, // store the original so we can compare and know if we need to tell the search to update its text
435
+ dupe = false, // check for whether a token we extracted represents a duplicate selected choice
436
+ token, // token
437
+ index, // position at which the separator was found
438
+ i, l, // looping variables
439
+ separator; // the matched separator
440
+
441
+ if (!opts.createSearchChoice || !opts.tokenSeparators || opts.tokenSeparators.length < 1) return undefined;
442
+
443
+ while (true) {
444
+ index = -1;
445
+
446
+ for (i = 0, l = opts.tokenSeparators.length; i < l; i++) {
447
+ separator = opts.tokenSeparators[i];
448
+ index = input.indexOf(separator);
449
+ if (index >= 0) break;
450
+ }
451
+
452
+ if (index < 0) break; // did not find any token separator in the input string, bail
453
+
454
+ token = input.substring(0, index);
455
+ input = input.substring(index + separator.length);
456
+
457
+ if (token.length > 0) {
458
+ token = opts.createSearchChoice(token, selection);
459
+ if (token !== undefined && token !== null && opts.id(token) !== undefined && opts.id(token) !== null) {
460
+ dupe = false;
461
+ for (i = 0, l = selection.length; i < l; i++) {
462
+ if (equal(opts.id(token), opts.id(selection[i]))) {
463
+ dupe = true; break;
464
+ }
465
+ }
466
+
467
+ if (!dupe) selectCallback(token);
468
+ }
469
+ }
470
+ }
471
+
472
+ if (original.localeCompare(input) != 0) return input;
473
+ }
474
+
403
475
  /**
404
476
  * blurs any Select2 container that has focus when an element outside them was clicked or received focus
405
477
  *
@@ -429,10 +501,6 @@
429
501
  });
430
502
  });
431
503
 
432
- function evaluate(val) {
433
- return $.isFunction(val) ? val() : val;
434
- }
435
-
436
504
  /**
437
505
  * Creates a new class
438
506
  *
@@ -476,6 +544,9 @@
476
544
  this.enabled=true;
477
545
  this.container = this.createContainer();
478
546
 
547
+ this.containerId="s2id"+nextUid();
548
+ this.container.attr("id", this.containerId);
549
+
479
550
  // cache the body so future lookups are cheap
480
551
  this.body = thunk(function() { return opts.element.closest("body"); });
481
552
 
@@ -490,11 +561,10 @@
490
561
  this.opts.element
491
562
  .data("select2", this)
492
563
  .hide()
493
- .after(this.container);
564
+ .before(this.container);
494
565
  this.container.data("select2", this);
495
566
 
496
567
  this.dropdown = this.container.find(".select2-drop");
497
- this.dropdown.css(evaluate(opts.dropdownCss));
498
568
  this.dropdown.addClass(evaluate(opts.dropdownCssClass));
499
569
  this.dropdown.data("select2", this);
500
570
 
@@ -559,7 +629,7 @@
559
629
  this.monitorSource();
560
630
  }
561
631
 
562
- if (opts.element.is(":disabled")) this.disable();
632
+ if (opts.element.is(":disabled") || opts.element.is("[readonly='readonly']")) this.disable();
563
633
  },
564
634
 
565
635
  // abstract
@@ -585,9 +655,6 @@
585
655
  this.select = select = opts.element;
586
656
  }
587
657
 
588
- //Custom tags separator.
589
- opts.separator = opts.separator || ",";
590
-
591
658
  if (select) {
592
659
  // these options are not allowed when attached to a select because they are picked up off the element itself
593
660
  $.each(["id", "multiple", "ajax", "query", "createSearchChoice", "initSelection", "data", "tags"], function () {
@@ -599,7 +666,7 @@
599
666
 
600
667
  opts = $.extend({}, {
601
668
  populateResults: function(container, results, query) {
602
- var populate, data, result, children, id=this.opts.id;
669
+ var populate, data, result, children, id=this.opts.id, self=this;
603
670
 
604
671
  populate=function(results, container, depth) {
605
672
 
@@ -615,6 +682,7 @@
615
682
  node.addClass("select2-result");
616
683
  node.addClass(selectable ? "select2-result-selectable" : "select2-result-unselectable");
617
684
  if (compound) { node.addClass("select2-result-with-children"); }
685
+ node.addClass(self.opts.formatResultCssClass(result));
618
686
 
619
687
  label=$("<div></div>");
620
688
  label.addClass("select2-result-label");
@@ -658,10 +726,10 @@
658
726
  var group;
659
727
  if (element.is("option")) {
660
728
  if (query.matcher(term, element.text(), element)) {
661
- collection.push({id:element.attr("value"), text:element.text(), element: element.get()});
729
+ collection.push({id:element.attr("value"), text:element.text(), element: element.get(), css: element.attr("class")});
662
730
  }
663
731
  } else if (element.is("optgroup")) {
664
- group={text:element.attr("label"), children:[], element: element.get()};
732
+ group={text:element.attr("label"), children:[], element: element.get(), css: element.attr("class")};
665
733
  element.children().each2(function(i, elm) { process(elm, group.children); });
666
734
  if (group.children.length>0) {
667
735
  collection.push(group);
@@ -685,6 +753,7 @@
685
753
  });
686
754
  // this is needed because inside val() we construct choices from options and there id is hardcoded
687
755
  opts.id=function(e) { return e.id; };
756
+ opts.formatResultCssClass = function(data) { return data.css; }
688
757
  } else {
689
758
  if (!("query" in opts)) {
690
759
  if ("ajax" in opts) {
@@ -858,10 +927,32 @@
858
927
  */
859
928
  // abstract
860
929
  opening: function() {
930
+ var cid = this.containerId, selector = "#"+ cid,
931
+ scroll = "scroll." + cid, resize = "resize." + cid;
932
+
933
+ this.container.parents().each(function() {
934
+ $(this).bind(scroll, function() {
935
+ var s2 = $(selector);
936
+ if (s2.length == 0) {
937
+ $(this).unbind(scroll);
938
+ }
939
+ s2.select2("close");
940
+ });
941
+ });
942
+
943
+ $(window).bind(resize, function() {
944
+ var s2 = $(selector);
945
+ if (s2.length == 0) {
946
+ $(window).unbind(resize);
947
+ }
948
+ s2.select2("close");
949
+ });
950
+
861
951
  this.clearDropdownAlignmentPreference();
862
952
 
863
953
  if (this.search.val() === " ") { this.search.val(""); }
864
954
 
955
+ this.dropdown.css(evaluate(this.opts.dropdownCss));
865
956
  this.dropdown.addClass("select2-drop-active");
866
957
  this.container.addClass("select2-dropdown-open").addClass("select2-container-active");
867
958
 
@@ -883,6 +974,13 @@
883
974
  close: function () {
884
975
  if (!this.opened()) return;
885
976
 
977
+ var self = this;
978
+
979
+ this.container.parents().each(function() {
980
+ $(this).unbind("scroll." + self.containerId);
981
+ });
982
+ $(window).unbind("resize." + this.containerId);
983
+
886
984
  this.clearDropdownAlignmentPreference();
887
985
 
888
986
  this.dropdown.hide();
@@ -984,7 +1082,7 @@
984
1082
  highlightUnderEvent: function (event) {
985
1083
  var el = $(event.target).closest(".select2-result-selectable");
986
1084
  if (el.length > 0 && !el.is(".select2-highlighted")) {
987
- var choices = this.results.find('.select2-result-selectable');
1085
+ var choices = this.results.find('.select2-result-selectable');
988
1086
  this.highlight(choices.index(el));
989
1087
  } else if (el.length == 0) {
990
1088
  // if we are over an unselectable item remove al highlights
@@ -1018,7 +1116,7 @@
1018
1116
  self.opts.populateResults.call(this, results, data.results, {term: term, page: page, context:context});
1019
1117
 
1020
1118
  if (data.more===true) {
1021
- more.detach().appendTo(results.children(":last")).text(self.opts.formatLoadMore(page+1));
1119
+ more.detach().appendTo(results).text(self.opts.formatLoadMore(page+1));
1022
1120
  window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10);
1023
1121
  } else {
1024
1122
  more.remove();
@@ -1029,12 +1127,19 @@
1029
1127
  }
1030
1128
  },
1031
1129
 
1130
+ /**
1131
+ * Default tokenizer function which does nothing
1132
+ */
1133
+ tokenize: function() {
1134
+
1135
+ },
1136
+
1032
1137
  /**
1033
1138
  * @param initial whether or not this is the call to this method right after the dropdown has been opened
1034
1139
  */
1035
1140
  // abstract
1036
1141
  updateResults: function (initial) {
1037
- var search = this.search, results = this.results, opts = this.opts, data, self=this;
1142
+ var search = this.search, results = this.results, opts = this.opts, data, self=this, input;
1038
1143
 
1039
1144
  // if the search is currently hidden we do not alter the results
1040
1145
  if (initial !== true && (this.showSearchInput === false || !this.opened())) {
@@ -1057,8 +1162,8 @@
1057
1162
  if (opts.maximumSelectionSize >=1) {
1058
1163
  data = this.data();
1059
1164
  if ($.isArray(data) && data.length >= opts.maximumSelectionSize && checkFormatter(opts.formatSelectionTooBig, "formatSelectionTooBig")) {
1060
- render("<li class='select2-selection-limit'>" + opts.formatSelectionTooBig(opts.maximumSelectionSize) + "</li>");
1061
- return;
1165
+ render("<li class='select2-selection-limit'>" + opts.formatSelectionTooBig(opts.maximumSelectionSize) + "</li>");
1166
+ return;
1062
1167
  }
1063
1168
  }
1064
1169
 
@@ -1066,6 +1171,15 @@
1066
1171
  render("<li class='select2-no-results'>" + opts.formatInputTooShort(search.val(), opts.minimumInputLength) + "</li>");
1067
1172
  return;
1068
1173
  }
1174
+ else {
1175
+ render("<li class='select2-searching'>" + opts.formatSearching() + "</li>");
1176
+ }
1177
+
1178
+ // give the tokenizer a chance to pre-process the input
1179
+ input = this.tokenize();
1180
+ if (input != undefined && input != null) {
1181
+ search.val(input);
1182
+ }
1069
1183
 
1070
1184
  this.resultsPage = 1;
1071
1185
  opts.query({
@@ -1101,7 +1215,7 @@
1101
1215
  self.opts.populateResults.call(this, results, data.results, {term: search.val(), page: this.resultsPage, context:null});
1102
1216
 
1103
1217
  if (data.more === true && checkFormatter(opts.formatLoadMore, "formatLoadMore")) {
1104
- results.children().filter(":last").append("<li class='select2-more-results'>" + escapeMarkup(opts.formatLoadMore(this.resultsPage)) + "</li>");
1218
+ results.append("<li class='select2-more-results'>" + escapeMarkup(opts.formatLoadMore(this.resultsPage)) + "</li>");
1105
1219
  window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10);
1106
1220
  }
1107
1221
 
@@ -1215,7 +1329,7 @@
1215
1329
 
1216
1330
  // single
1217
1331
 
1218
- createContainer: function () {
1332
+ createContainer: function () {
1219
1333
  var container = $("<div></div>", {
1220
1334
  "class": "select2-container"
1221
1335
  }).html([
@@ -1306,6 +1420,10 @@
1306
1420
  return;
1307
1421
  }
1308
1422
 
1423
+ if (this.opts.openOnEnter === false && e.which === KEY.ENTER) {
1424
+ return;
1425
+ }
1426
+
1309
1427
  this.open();
1310
1428
 
1311
1429
  if (e.which === KEY.ENTER) {
@@ -1332,7 +1450,6 @@
1332
1450
  } else if (this.enabled) {
1333
1451
  this.open();
1334
1452
  }
1335
- killEvent(e);
1336
1453
 
1337
1454
  clickingInside = false;
1338
1455
  }));
@@ -1346,7 +1463,9 @@
1346
1463
  }));
1347
1464
 
1348
1465
  selection.bind("blur", this.bind(function() {
1349
- this.container.removeClass("select2-container-active");
1466
+ if (!this.opened()) {
1467
+ this.container.removeClass("select2-container-active");
1468
+ }
1350
1469
  window.setTimeout(this.bind(function() { this.search.attr("tabIndex", this.opts.element.attr("tabIndex")); }), 10);
1351
1470
  }));
1352
1471
 
@@ -1359,7 +1478,19 @@
1359
1478
  return;
1360
1479
  }
1361
1480
 
1362
- if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) {
1481
+ if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e)
1482
+ || e.which === KEY.ESC) {
1483
+ return;
1484
+ }
1485
+
1486
+ if (this.opts.openOnEnter === false && e.which === KEY.ENTER) {
1487
+ return;
1488
+ }
1489
+
1490
+ if (e.which == KEY.DELETE) {
1491
+ if (this.opts.allowClear) {
1492
+ this.clear();
1493
+ }
1363
1494
  return;
1364
1495
  }
1365
1496
 
@@ -1384,6 +1515,8 @@
1384
1515
  keyWritten = keyWritten.toUpperCase();
1385
1516
  }
1386
1517
 
1518
+ // focus the field before calling val so the cursor ends up after the value instead of before
1519
+ this.search.focus();
1387
1520
  this.search.val(keyWritten);
1388
1521
 
1389
1522
  // prevent event propagation so it doesnt replay on the now focussed search field and result in double key entry
@@ -1489,9 +1622,7 @@
1489
1622
  // hide the search box if this is the first we got the results and there are a few of them
1490
1623
 
1491
1624
  if (initial === true) {
1492
- // TODO below we use data.results.length, but what we really need is something recursive to calc the length
1493
- // TODO in case there are optgroups
1494
- showSearchInput = this.showSearchInput = data.results.length >= this.opts.minimumResultsForSearch;
1625
+ showSearchInput = this.showSearchInput = countResults(data.results) >= this.opts.minimumResultsForSearch;
1495
1626
  this.dropdown.find(".select2-search")[showSearchInput ? "removeClass" : "addClass"]("select2-search-hidden");
1496
1627
 
1497
1628
  //add "select2-with-searchbox" to the container if search box is shown
@@ -1602,14 +1733,14 @@
1602
1733
  " <ul class='select2-choices'>",
1603
1734
  //"<li class='select2-search-choice'><span>California</span><a href="javascript:void(0)" class="select2-search-choice-close"></a></li>" ,
1604
1735
  " <li class='select2-search-field'>" ,
1605
- " <input type='text' autocomplete='off' style='width: 25px;' class='select2-input'>" ,
1736
+ " <input type='text' autocomplete='off' class='select2-input'>" ,
1606
1737
  " </li>" ,
1607
1738
  "</ul>" ,
1608
1739
  "<div class='select2-drop select2-drop-multi' style='display:none;'>" ,
1609
1740
  " <ul class='select2-results'>" ,
1610
1741
  " </ul>" ,
1611
1742
  "</div>"].join(""));
1612
- return container;
1743
+ return container;
1613
1744
  },
1614
1745
 
1615
1746
  // multi
@@ -1685,7 +1816,12 @@
1685
1816
  }
1686
1817
  }
1687
1818
 
1688
- if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.BACKSPACE || e.which === KEY.ESC) {
1819
+ if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e)
1820
+ || e.which === KEY.BACKSPACE || e.which === KEY.ESC) {
1821
+ return;
1822
+ }
1823
+
1824
+ if (this.opts.openOnEnter === false && e.which === KEY.ENTER) {
1689
1825
  return;
1690
1826
  }
1691
1827
 
@@ -1792,7 +1928,7 @@
1792
1928
  this.parent.opening.apply(this, arguments);
1793
1929
 
1794
1930
  this.clearPlaceholder();
1795
- this.resizeSearch();
1931
+ this.resizeSearch();
1796
1932
  this.focusSearch();
1797
1933
  },
1798
1934
 
@@ -1833,6 +1969,18 @@
1833
1969
  self.postprocessResults();
1834
1970
  },
1835
1971
 
1972
+ tokenize: function() {
1973
+ var input = this.search.val();
1974
+ input = this.opts.tokenizer(input, this.data(), this.bind(this.onSelect), this.opts);
1975
+ if (input != null && input != undefined) {
1976
+ this.search.val(input);
1977
+ if (input.length > 0) {
1978
+ this.open();
1979
+ }
1980
+ }
1981
+
1982
+ },
1983
+
1836
1984
  // multi
1837
1985
  onSelect: function (data) {
1838
1986
  this.addSelectedChoice(data);
@@ -1842,10 +1990,9 @@
1842
1990
  this.close();
1843
1991
  this.search.width(10);
1844
1992
  } else {
1845
- this.search.width(10);
1846
- this.resizeSearch();
1847
-
1848
1993
  if (this.countSelectableResults()>0) {
1994
+ this.search.width(10);
1995
+ this.resizeSearch();
1849
1996
  this.positionDropdown();
1850
1997
  } else {
1851
1998
  // if nothing left to select close
@@ -1880,6 +2027,7 @@
1880
2027
  formatted=this.opts.formatSelection(data, choice);
1881
2028
  choice.find("div").replaceWith("<div>"+escapeMarkup(formatted)+"</div>");
1882
2029
  choice.find(".select2-search-choice-close")
2030
+ .bind("mousedown", killEvent)
1883
2031
  .bind("click dblclick", this.bind(function (e) {
1884
2032
  if (!this.enabled) return;
1885
2033
 
@@ -1965,7 +2113,7 @@
1965
2113
  resizeSearch: function () {
1966
2114
 
1967
2115
  var minimumWidth, left, maxWidth, containerLeft, searchWidth,
1968
- sideBorderPadding = getSideBorderPadding(this.search);
2116
+ sideBorderPadding = getSideBorderPadding(this.search);
1969
2117
 
1970
2118
  minimumWidth = measureTextWidth(this.search) + 10;
1971
2119
 
@@ -1975,7 +2123,6 @@
1975
2123
  containerLeft = this.selection.offset().left;
1976
2124
 
1977
2125
  searchWidth = maxWidth - (left - containerLeft) - sideBorderPadding;
1978
-
1979
2126
  if (searchWidth < minimumWidth) {
1980
2127
  searchWidth = maxWidth - sideBorderPadding;
1981
2128
  }
@@ -2109,7 +2256,7 @@
2109
2256
  var args = Array.prototype.slice.call(arguments, 0),
2110
2257
  opts,
2111
2258
  select2,
2112
- value, multiple, allowedMethods = ["val", "destroy", "open", "close", "focus", "isFocused", "container", "onSortStart", "onSortEnd", "enable", "disable", "positionDropdown", "data"];
2259
+ value, multiple, allowedMethods = ["val", "destroy", "opened", "open", "close", "focus", "isFocused", "container", "onSortStart", "onSortEnd", "enable", "disable", "positionDropdown", "data"];
2113
2260
 
2114
2261
  this.each(function () {
2115
2262
  if (args.length === 0 || typeof(args[0]) === "object") {
@@ -2151,6 +2298,7 @@
2151
2298
  $.fn.select2.defaults = {
2152
2299
  width: "copy",
2153
2300
  closeOnSelect: true,
2301
+ openOnEnter: true,
2154
2302
  containerCss: {},
2155
2303
  dropdownCss: {},
2156
2304
  containerCssClass: "",
@@ -2163,17 +2311,22 @@
2163
2311
  formatSelection: function (data, container) {
2164
2312
  return data.text;
2165
2313
  },
2314
+ formatResultCssClass: function(data) {return undefined;},
2166
2315
  formatNoMatches: function () { return "No matches found"; },
2167
2316
  formatInputTooShort: function (input, min) { return "Please enter " + (min - input.length) + " more characters"; },
2168
2317
  formatSelectionTooBig: function (limit) { return "You can only select " + limit + " items"; },
2169
2318
  formatLoadMore: function (pageNumber) { return "Loading more results..."; },
2319
+ formatSearching: function () { return "Searching..."; },
2170
2320
  minimumResultsForSearch: 0,
2171
2321
  minimumInputLength: 0,
2172
2322
  maximumSelectionSize: 0,
2173
2323
  id: function (e) { return e.id; },
2174
2324
  matcher: function(term, text) {
2175
2325
  return text.toUpperCase().indexOf(term.toUpperCase()) >= 0;
2176
- }
2326
+ },
2327
+ separator: ",",
2328
+ tokenSeparators: [],
2329
+ tokenizer: defaultTokenizer
2177
2330
  };
2178
2331
 
2179
2332
  // exports
@@ -1,5 +1,5 @@
1
1
  /*
2
- *Version: 3.0 Timestamp: Tue Jul 31 21:09:16 PDT 2012
2
+ *Version: 3.1 Timestamp: Tue Aug 14 09:05:17 PDT 2012
3
3
 
4
4
  .select2-container
5
5
  position: relative
@@ -7,6 +7,7 @@
7
7
  /* inline-block for ie7
8
8
  zoom: 1
9
9
  *display: inline
10
+ vertical-align: top
10
11
  /*
11
12
  * Force border-box so that % widths fit the parent
12
13
  * container without overlap because of margin/padding.
@@ -328,7 +329,7 @@
328
329
  font-style: normal
329
330
  .select2-highlighted em
330
331
  background: transparent
331
- .select2-no-results, .select2-selection-limit
332
+ .select2-no-results, .select2-searching, .select2-selection-limit
332
333
  background: #f4f4f4
333
334
  display: list-item
334
335
  .select2-disabled
@@ -497,4 +498,4 @@
497
498
 
498
499
  .select2-offscreen
499
500
  position: absolute
500
- left: -10000px
501
+ left: -10000px
metadata CHANGED
@@ -1,84 +1,89 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: select2-rails
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 3
7
- - 0
8
- - 0
9
- version: 3.0.0
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.1.0
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
7
+ authors:
12
8
  - Rogerio Medeiros
13
9
  autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
-
17
- date: 2012-08-06 00:00:00 -03:00
18
- default_executable:
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- type: :runtime
22
- version_requirements: &id001 !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ~>
25
- - !ruby/object:Gem::Version
26
- segments:
27
- - 0
28
- - 14
29
- version: "0.14"
12
+ date: 2012-08-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
30
15
  name: thor
31
- requirement: *id001
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '0.14'
22
+ type: :runtime
32
23
  prerelease: false
33
- - !ruby/object:Gem::Dependency
34
- type: :development
35
- version_requirements: &id002 !ruby/object:Gem::Requirement
36
- requirements:
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
37
27
  - - ~>
38
- - !ruby/object:Gem::Version
39
- segments:
40
- - 1
41
- - 0
42
- version: "1.0"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.14'
30
+ - !ruby/object:Gem::Dependency
43
31
  name: bundler
44
- requirement: *id002
45
- prerelease: false
46
- - !ruby/object:Gem::Dependency
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '1.0'
47
38
  type: :development
48
- version_requirements: &id003 !ruby/object:Gem::Requirement
49
- requirements:
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
50
43
  - - ~>
51
- - !ruby/object:Gem::Version
52
- segments:
53
- - 3
54
- - 0
55
- version: "3.0"
44
+ - !ruby/object:Gem::Version
45
+ version: '1.0'
46
+ - !ruby/object:Gem::Dependency
56
47
  name: rails
57
- requirement: *id003
58
- prerelease: false
59
- - !ruby/object:Gem::Dependency
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '3.0'
60
54
  type: :development
61
- version_requirements: &id004 !ruby/object:Gem::Requirement
62
- requirements:
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
63
59
  - - ~>
64
- - !ruby/object:Gem::Version
65
- segments:
66
- - 3
67
- - 1
68
- version: "3.1"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ - !ruby/object:Gem::Dependency
69
63
  name: sass
70
- requirement: *id004
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '3.1'
70
+ type: :development
71
71
  prerelease: false
72
- description: Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results. This gem integrates Select2 with Rails asset pipeline for easy of use.
73
- email:
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '3.1'
78
+ description: Select2 is a jQuery based replacement for select boxes. It supports searching,
79
+ remote data sets, and infinite scrolling of results. This gem integrates Select2
80
+ with Rails asset pipeline for easy of use.
81
+ email:
74
82
  - argerim@gmail.com
75
83
  executables: []
76
-
77
84
  extensions: []
78
-
79
85
  extra_rdoc_files: []
80
-
81
- files:
86
+ files:
82
87
  - .gitignore
83
88
  - Gemfile
84
89
  - LICENSE
@@ -93,35 +98,34 @@ files:
93
98
  - vendor/assets/images/spinner.gif
94
99
  - vendor/assets/javascripts/select2.js
95
100
  - vendor/assets/stylesheets/select2.css.sass
96
- has_rdoc: true
97
101
  homepage: https://github.com/argerim/select2-rails
98
102
  licenses: []
99
-
100
103
  post_install_message:
101
104
  rdoc_options: []
102
-
103
- require_paths:
105
+ require_paths:
104
106
  - lib
105
- required_ruby_version: !ruby/object:Gem::Requirement
106
- requirements:
107
- - - ">="
108
- - !ruby/object:Gem::Version
109
- segments:
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ! '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ segments:
110
114
  - 0
111
- version: "0"
112
- required_rubygems_version: !ruby/object:Gem::Requirement
113
- requirements:
114
- - - ">="
115
- - !ruby/object:Gem::Version
116
- segments:
115
+ hash: -2917332029930381823
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ! '>='
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ segments:
117
123
  - 0
118
- version: "0"
124
+ hash: -2917332029930381823
119
125
  requirements: []
120
-
121
126
  rubyforge_project:
122
- rubygems_version: 1.3.6
127
+ rubygems_version: 1.8.24
123
128
  signing_key:
124
129
  specification_version: 3
125
130
  summary: Integrate Select2 javascript library with Rails asset pipeline
126
131
  test_files: []
127
-