twitter-typeahead-rails 0.10.2 → 0.10.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,127 +1,134 @@
1
1
  /*!
2
- * typeahead.js 0.10.2
2
+ * typeahead.js 0.10.5
3
3
  * https://github.com/twitter/typeahead.js
4
4
  * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
5
5
  */
6
6
 
7
7
  (function($) {
8
- var _ = {
9
- isMsie: function() {
10
- return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
11
- },
12
- isBlankString: function(str) {
13
- return !str || /^\s*$/.test(str);
14
- },
15
- escapeRegExChars: function(str) {
16
- return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
17
- },
18
- isString: function(obj) {
19
- return typeof obj === "string";
20
- },
21
- isNumber: function(obj) {
22
- return typeof obj === "number";
23
- },
24
- isArray: $.isArray,
25
- isFunction: $.isFunction,
26
- isObject: $.isPlainObject,
27
- isUndefined: function(obj) {
28
- return typeof obj === "undefined";
29
- },
30
- bind: $.proxy,
31
- each: function(collection, cb) {
32
- $.each(collection, reverseArgs);
33
- function reverseArgs(index, value) {
34
- return cb(value, index);
35
- }
36
- },
37
- map: $.map,
38
- filter: $.grep,
39
- every: function(obj, test) {
40
- var result = true;
41
- if (!obj) {
42
- return result;
43
- }
44
- $.each(obj, function(key, val) {
45
- if (!(result = test.call(null, val, key, obj))) {
46
- return false;
8
+ var _ = function() {
9
+ "use strict";
10
+ return {
11
+ isMsie: function() {
12
+ return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
13
+ },
14
+ isBlankString: function(str) {
15
+ return !str || /^\s*$/.test(str);
16
+ },
17
+ escapeRegExChars: function(str) {
18
+ return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
19
+ },
20
+ isString: function(obj) {
21
+ return typeof obj === "string";
22
+ },
23
+ isNumber: function(obj) {
24
+ return typeof obj === "number";
25
+ },
26
+ isArray: $.isArray,
27
+ isFunction: $.isFunction,
28
+ isObject: $.isPlainObject,
29
+ isUndefined: function(obj) {
30
+ return typeof obj === "undefined";
31
+ },
32
+ toStr: function toStr(s) {
33
+ return _.isUndefined(s) || s === null ? "" : s + "";
34
+ },
35
+ bind: $.proxy,
36
+ each: function(collection, cb) {
37
+ $.each(collection, reverseArgs);
38
+ function reverseArgs(index, value) {
39
+ return cb(value, index);
47
40
  }
48
- });
49
- return !!result;
50
- },
51
- some: function(obj, test) {
52
- var result = false;
53
- if (!obj) {
54
- return result;
55
- }
56
- $.each(obj, function(key, val) {
57
- if (result = test.call(null, val, key, obj)) {
58
- return false;
41
+ },
42
+ map: $.map,
43
+ filter: $.grep,
44
+ every: function(obj, test) {
45
+ var result = true;
46
+ if (!obj) {
47
+ return result;
59
48
  }
60
- });
61
- return !!result;
62
- },
63
- mixin: $.extend,
64
- getUniqueId: function() {
65
- var counter = 0;
66
- return function() {
67
- return counter++;
68
- };
69
- }(),
70
- templatify: function templatify(obj) {
71
- return $.isFunction(obj) ? obj : template;
72
- function template() {
73
- return String(obj);
74
- }
75
- },
76
- defer: function(fn) {
77
- setTimeout(fn, 0);
78
- },
79
- debounce: function(func, wait, immediate) {
80
- var timeout, result;
81
- return function() {
82
- var context = this, args = arguments, later, callNow;
83
- later = function() {
84
- timeout = null;
85
- if (!immediate) {
86
- result = func.apply(context, args);
49
+ $.each(obj, function(key, val) {
50
+ if (!(result = test.call(null, val, key, obj))) {
51
+ return false;
87
52
  }
88
- };
89
- callNow = immediate && !timeout;
90
- clearTimeout(timeout);
91
- timeout = setTimeout(later, wait);
92
- if (callNow) {
93
- result = func.apply(context, args);
53
+ });
54
+ return !!result;
55
+ },
56
+ some: function(obj, test) {
57
+ var result = false;
58
+ if (!obj) {
59
+ return result;
94
60
  }
95
- return result;
96
- };
97
- },
98
- throttle: function(func, wait) {
99
- var context, args, timeout, result, previous, later;
100
- previous = 0;
101
- later = function() {
102
- previous = new Date();
103
- timeout = null;
104
- result = func.apply(context, args);
105
- };
106
- return function() {
107
- var now = new Date(), remaining = wait - (now - previous);
108
- context = this;
109
- args = arguments;
110
- if (remaining <= 0) {
61
+ $.each(obj, function(key, val) {
62
+ if (result = test.call(null, val, key, obj)) {
63
+ return false;
64
+ }
65
+ });
66
+ return !!result;
67
+ },
68
+ mixin: $.extend,
69
+ getUniqueId: function() {
70
+ var counter = 0;
71
+ return function() {
72
+ return counter++;
73
+ };
74
+ }(),
75
+ templatify: function templatify(obj) {
76
+ return $.isFunction(obj) ? obj : template;
77
+ function template() {
78
+ return String(obj);
79
+ }
80
+ },
81
+ defer: function(fn) {
82
+ setTimeout(fn, 0);
83
+ },
84
+ debounce: function(func, wait, immediate) {
85
+ var timeout, result;
86
+ return function() {
87
+ var context = this, args = arguments, later, callNow;
88
+ later = function() {
89
+ timeout = null;
90
+ if (!immediate) {
91
+ result = func.apply(context, args);
92
+ }
93
+ };
94
+ callNow = immediate && !timeout;
111
95
  clearTimeout(timeout);
96
+ timeout = setTimeout(later, wait);
97
+ if (callNow) {
98
+ result = func.apply(context, args);
99
+ }
100
+ return result;
101
+ };
102
+ },
103
+ throttle: function(func, wait) {
104
+ var context, args, timeout, result, previous, later;
105
+ previous = 0;
106
+ later = function() {
107
+ previous = new Date();
112
108
  timeout = null;
113
- previous = now;
114
109
  result = func.apply(context, args);
115
- } else if (!timeout) {
116
- timeout = setTimeout(later, remaining);
117
- }
118
- return result;
119
- };
120
- },
121
- noop: function() {}
122
- };
123
- var VERSION = "0.10.2";
124
- var tokenizers = function(root) {
110
+ };
111
+ return function() {
112
+ var now = new Date(), remaining = wait - (now - previous);
113
+ context = this;
114
+ args = arguments;
115
+ if (remaining <= 0) {
116
+ clearTimeout(timeout);
117
+ timeout = null;
118
+ previous = now;
119
+ result = func.apply(context, args);
120
+ } else if (!timeout) {
121
+ timeout = setTimeout(later, remaining);
122
+ }
123
+ return result;
124
+ };
125
+ },
126
+ noop: function() {}
127
+ };
128
+ }();
129
+ var VERSION = "0.10.5";
130
+ var tokenizers = function() {
131
+ "use strict";
125
132
  return {
126
133
  nonword: nonword,
127
134
  whitespace: whitespace,
@@ -130,26 +137,35 @@
130
137
  whitespace: getObjTokenizer(whitespace)
131
138
  }
132
139
  };
133
- function whitespace(s) {
134
- return s.split(/\s+/);
140
+ function whitespace(str) {
141
+ str = _.toStr(str);
142
+ return str ? str.split(/\s+/) : [];
135
143
  }
136
- function nonword(s) {
137
- return s.split(/\W+/);
144
+ function nonword(str) {
145
+ str = _.toStr(str);
146
+ return str ? str.split(/\W+/) : [];
138
147
  }
139
148
  function getObjTokenizer(tokenizer) {
140
- return function setKey(key) {
149
+ return function setKey() {
150
+ var args = [].slice.call(arguments, 0);
141
151
  return function tokenize(o) {
142
- return tokenizer(o[key]);
152
+ var tokens = [];
153
+ _.each(args, function(k) {
154
+ tokens = tokens.concat(tokenizer(_.toStr(o[k])));
155
+ });
156
+ return tokens;
143
157
  };
144
158
  };
145
159
  }
146
160
  }();
147
161
  var LruCache = function() {
162
+ "use strict";
148
163
  function LruCache(maxSize) {
149
- this.maxSize = maxSize || 100;
150
- this.size = 0;
151
- this.hash = {};
152
- this.list = new List();
164
+ this.maxSize = _.isNumber(maxSize) ? maxSize : 100;
165
+ this.reset();
166
+ if (this.maxSize <= 0) {
167
+ this.set = this.get = $.noop;
168
+ }
153
169
  }
154
170
  _.mixin(LruCache.prototype, {
155
171
  set: function set(key, val) {
@@ -174,6 +190,11 @@
174
190
  this.list.moveToFront(node);
175
191
  return node.val;
176
192
  }
193
+ },
194
+ reset: function reset() {
195
+ this.size = 0;
196
+ this.hash = {};
197
+ this.list = new List();
177
198
  }
178
199
  });
179
200
  function List() {
@@ -205,6 +226,7 @@
205
226
  return LruCache;
206
227
  }();
207
228
  var PersistentStorage = function() {
229
+ "use strict";
208
230
  var ls, methods;
209
231
  try {
210
232
  ls = window.localStorage;
@@ -216,7 +238,7 @@
216
238
  function PersistentStorage(namespace) {
217
239
  this.prefix = [ "__", namespace, "__" ].join("");
218
240
  this.ttlKey = "__ttl__";
219
- this.keyMatcher = new RegExp("^" + this.prefix);
241
+ this.keyMatcher = new RegExp("^" + _.escapeRegExChars(this.prefix));
220
242
  }
221
243
  if (ls && window.JSON) {
222
244
  methods = {
@@ -284,21 +306,28 @@
284
306
  }
285
307
  }();
286
308
  var Transport = function() {
287
- var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, requestCache = new LruCache(10);
309
+ "use strict";
310
+ var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, sharedCache = new LruCache(10);
288
311
  function Transport(o) {
289
312
  o = o || {};
313
+ this.cancelled = false;
314
+ this.lastUrl = null;
290
315
  this._send = o.transport ? callbackToDeferred(o.transport) : $.ajax;
291
316
  this._get = o.rateLimiter ? o.rateLimiter(this._get) : this._get;
317
+ this._cache = o.cache === false ? new LruCache(0) : sharedCache;
292
318
  }
293
319
  Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {
294
320
  maxPendingRequests = num;
295
321
  };
296
- Transport.resetCache = function clearCache() {
297
- requestCache = new LruCache(10);
322
+ Transport.resetCache = function resetCache() {
323
+ sharedCache.reset();
298
324
  };
299
325
  _.mixin(Transport.prototype, {
300
326
  _get: function(url, o, cb) {
301
327
  var that = this, jqXhr;
328
+ if (this.cancelled || url !== this.lastUrl) {
329
+ return;
330
+ }
302
331
  if (jqXhr = pendingRequests[url]) {
303
332
  jqXhr.done(done).fail(fail);
304
333
  } else if (pendingRequestsCount < maxPendingRequests) {
@@ -309,7 +338,7 @@
309
338
  }
310
339
  function done(resp) {
311
340
  cb && cb(null, resp);
312
- requestCache.set(url, resp);
341
+ that._cache.set(url, resp);
313
342
  }
314
343
  function fail() {
315
344
  cb && cb(true);
@@ -329,7 +358,9 @@
329
358
  cb = o;
330
359
  o = {};
331
360
  }
332
- if (resp = requestCache.get(url)) {
361
+ this.cancelled = false;
362
+ this.lastUrl = url;
363
+ if (resp = this._cache.get(url)) {
333
364
  _.defer(function() {
334
365
  cb && cb(null, resp);
335
366
  });
@@ -337,6 +368,9 @@
337
368
  this._get(url, o, cb);
338
369
  }
339
370
  return !!resp;
371
+ },
372
+ cancel: function() {
373
+ this.cancelled = true;
340
374
  }
341
375
  });
342
376
  return Transport;
@@ -359,6 +393,7 @@
359
393
  }
360
394
  }();
361
395
  var SearchIndex = function() {
396
+ "use strict";
362
397
  function SearchIndex(o) {
363
398
  o = o || {};
364
399
  if (!o.datumTokenizer || !o.queryTokenizer) {
@@ -445,7 +480,7 @@
445
480
  }
446
481
  function unique(array) {
447
482
  var seen = {}, uniques = [];
448
- for (var i = 0; i < array.length; i++) {
483
+ for (var i = 0, len = array.length; i < len; i++) {
449
484
  if (!seen[array[i]]) {
450
485
  seen[array[i]] = true;
451
486
  uniques.push(array[i]);
@@ -457,7 +492,8 @@
457
492
  var ai = 0, bi = 0, intersection = [];
458
493
  arrayA = arrayA.sort(compare);
459
494
  arrayB = arrayB.sort(compare);
460
- while (ai < arrayA.length && bi < arrayB.length) {
495
+ var lenArrayA = arrayA.length, lenArrayB = arrayB.length;
496
+ while (ai < lenArrayA && bi < lenArrayB) {
461
497
  if (arrayA[ai] < arrayB[bi]) {
462
498
  ai++;
463
499
  } else if (arrayA[ai] > arrayB[bi]) {
@@ -475,6 +511,7 @@
475
511
  }
476
512
  }();
477
513
  var oParser = function() {
514
+ "use strict";
478
515
  return {
479
516
  local: getLocal,
480
517
  prefetch: getPrefetch,
@@ -508,6 +545,7 @@
508
545
  var remote, defaults;
509
546
  defaults = {
510
547
  url: null,
548
+ cache: true,
511
549
  wildcard: "%QUERY",
512
550
  replace: null,
513
551
  rateLimitBy: "debounce",
@@ -542,6 +580,7 @@
542
580
  }
543
581
  }();
544
582
  (function(root) {
583
+ "use strict";
545
584
  var old, keys;
546
585
  old = root.Bloodhound;
547
586
  keys = {
@@ -590,6 +629,9 @@
590
629
  },
591
630
  _getFromRemote: function getFromRemote(query, cb) {
592
631
  var that = this, url, uriEncodedQuery;
632
+ if (!this.transport) {
633
+ return;
634
+ }
593
635
  query = query || "";
594
636
  uriEncodedQuery = encodeURIComponent(query);
595
637
  url = this.remote.replace ? this.remote.replace(this.remote.url, query) : this.remote.url.replace(this.remote.wildcard, uriEncodedQuery);
@@ -598,6 +640,9 @@
598
640
  err ? cb([]) : cb(that.remote.filter ? that.remote.filter(resp) : resp);
599
641
  }
600
642
  },
643
+ _cancelLastRemoteRequest: function cancelLastRemoteRequest() {
644
+ this.transport && this.transport.cancel();
645
+ },
601
646
  _saveToStorage: function saveToStorage(data, thumbprint, ttl) {
602
647
  if (this.storage) {
603
648
  this.storage.set(keys.data, data, ttl);
@@ -635,9 +680,7 @@
635
680
  var that = this, matches = [], cacheHit = false;
636
681
  matches = this.index.get(query);
637
682
  matches = this.sorter(matches).slice(0, this.limit);
638
- if (matches.length < this.limit && this.transport) {
639
- cacheHit = this._getFromRemote(query, returnRemoteMatches);
640
- }
683
+ matches.length < this.limit ? cacheHit = this._getFromRemote(query, returnRemoteMatches) : this._cancelLastRemoteRequest();
641
684
  if (!cacheHit) {
642
685
  (matches.length > 0 || !this.transport) && cb && cb(matches);
643
686
  }
@@ -681,71 +724,79 @@
681
724
  return false;
682
725
  }
683
726
  })(this);
684
- var html = {
685
- wrapper: '<span class="twitter-typeahead"></span>',
686
- dropdown: '<span class="tt-dropdown-menu"></span>',
687
- dataset: '<div class="tt-dataset-%CLASS%"></div>',
688
- suggestions: '<span class="tt-suggestions"></span>',
689
- suggestion: '<div class="tt-suggestion"></div>'
690
- };
691
- var css = {
692
- wrapper: {
693
- position: "relative",
694
- display: "inline-block"
695
- },
696
- hint: {
697
- position: "absolute",
698
- top: "0",
699
- left: "0",
700
- borderColor: "transparent",
701
- boxShadow: "none"
702
- },
703
- input: {
704
- position: "relative",
705
- verticalAlign: "top",
706
- backgroundColor: "transparent"
707
- },
708
- inputWithNoHint: {
709
- position: "relative",
710
- verticalAlign: "top"
711
- },
712
- dropdown: {
713
- position: "absolute",
714
- top: "100%",
715
- left: "0",
716
- zIndex: "100",
717
- display: "none"
718
- },
719
- suggestions: {
720
- display: "block"
721
- },
722
- suggestion: {
723
- whiteSpace: "nowrap",
724
- cursor: "pointer"
725
- },
726
- suggestionChild: {
727
- whiteSpace: "normal"
728
- },
729
- ltr: {
730
- left: "0",
731
- right: "auto"
732
- },
733
- rtl: {
734
- left: "auto",
735
- right: " 0"
727
+ var html = function() {
728
+ return {
729
+ wrapper: '<span class="twitter-typeahead"></span>',
730
+ dropdown: '<span class="tt-dropdown-menu"></span>',
731
+ dataset: '<div class="tt-dataset-%CLASS%"></div>',
732
+ suggestions: '<span class="tt-suggestions"></span>',
733
+ suggestion: '<div class="tt-suggestion"></div>'
734
+ };
735
+ }();
736
+ var css = function() {
737
+ "use strict";
738
+ var css = {
739
+ wrapper: {
740
+ position: "relative",
741
+ display: "inline-block"
742
+ },
743
+ hint: {
744
+ position: "absolute",
745
+ top: "0",
746
+ left: "0",
747
+ borderColor: "transparent",
748
+ boxShadow: "none",
749
+ opacity: "1"
750
+ },
751
+ input: {
752
+ position: "relative",
753
+ verticalAlign: "top",
754
+ backgroundColor: "transparent"
755
+ },
756
+ inputWithNoHint: {
757
+ position: "relative",
758
+ verticalAlign: "top"
759
+ },
760
+ dropdown: {
761
+ position: "absolute",
762
+ top: "100%",
763
+ left: "0",
764
+ zIndex: "100",
765
+ display: "none"
766
+ },
767
+ suggestions: {
768
+ display: "block"
769
+ },
770
+ suggestion: {
771
+ whiteSpace: "nowrap",
772
+ cursor: "pointer"
773
+ },
774
+ suggestionChild: {
775
+ whiteSpace: "normal"
776
+ },
777
+ ltr: {
778
+ left: "0",
779
+ right: "auto"
780
+ },
781
+ rtl: {
782
+ left: "auto",
783
+ right: " 0"
784
+ }
785
+ };
786
+ if (_.isMsie()) {
787
+ _.mixin(css.input, {
788
+ backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"
789
+ });
736
790
  }
737
- };
738
- if (_.isMsie()) {
739
- _.mixin(css.input, {
740
- backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"
741
- });
742
- }
743
- if (_.isMsie() && _.isMsie() <= 7) {
744
- _.mixin(css.input, {
745
- marginTop: "-1px"
746
- });
747
- }
791
+ if (_.isMsie() && _.isMsie() <= 7) {
792
+ _.mixin(css.input, {
793
+ marginTop: "-1px"
794
+ });
795
+ }
796
+ return css;
797
+ }();
748
798
  var EventBus = function() {
799
+ "use strict";
749
800
  var namespace = "typeahead:";
750
801
  function EventBus(o) {
751
802
  if (!o || !o.el) {
@@ -762,6 +813,7 @@
762
813
  return EventBus;
763
814
  }();
764
815
  var EventEmitter = function() {
816
+ "use strict";
765
817
  var splitter = /\s+/, nextTick = getNextTick();
766
818
  return {
767
819
  onSync: onSync,
@@ -821,7 +873,7 @@
821
873
  return flush;
822
874
  function flush() {
823
875
  var cancelled;
824
- for (var i = 0; !cancelled && i < callbacks.length; i += 1) {
876
+ for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) {
825
877
  cancelled = callbacks[i].apply(context, args) === false;
826
878
  }
827
879
  return !cancelled;
@@ -851,6 +903,7 @@
851
903
  }
852
904
  }();
853
905
  var highlight = function(doc) {
906
+ "use strict";
854
907
  var defaults = {
855
908
  node: null,
856
909
  pattern: null,
@@ -869,7 +922,7 @@
869
922
  regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly);
870
923
  traverse(o.node, hightlightTextNode);
871
924
  function hightlightTextNode(textNode) {
872
- var match, patternNode;
925
+ var match, patternNode, wrapperNode;
873
926
  if (match = regex.exec(textNode.data)) {
874
927
  wrapperNode = doc.createElement(o.tagName);
875
928
  o.className && (wrapperNode.className = o.className);
@@ -894,7 +947,7 @@
894
947
  };
895
948
  function getRegex(patterns, caseSensitive, wordsOnly) {
896
949
  var escapedPatterns = [], regexStr;
897
- for (var i = 0; i < patterns.length; i++) {
950
+ for (var i = 0, len = patterns.length; i < len; i++) {
898
951
  escapedPatterns.push(_.escapeRegExChars(patterns[i]));
899
952
  }
900
953
  regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")";
@@ -902,6 +955,7 @@
902
955
  }
903
956
  }(window.document);
904
957
  var Input = function() {
958
+ "use strict";
905
959
  var specialKeyCodeMap;
906
960
  specialKeyCodeMap = {
907
961
  9: "tab",
@@ -997,8 +1051,9 @@
997
1051
  inputValue = this.getInputValue();
998
1052
  areEquivalent = areQueriesEquivalent(inputValue, this.query);
999
1053
  hasDifferentWhitespace = areEquivalent ? this.query.length !== inputValue.length : false;
1054
+ this.query = inputValue;
1000
1055
  if (!areEquivalent) {
1001
- this.trigger("queryChanged", this.query = inputValue);
1056
+ this.trigger("queryChanged", this.query);
1002
1057
  } else if (hasDifferentWhitespace) {
1003
1058
  this.trigger("whitespaceChanged", this.query);
1004
1059
  }
@@ -1095,6 +1150,7 @@
1095
1150
  }
1096
1151
  }();
1097
1152
  var Dataset = function() {
1153
+ "use strict";
1098
1154
  var datasetKey = "ttDataset", valueKey = "ttValue", datumKey = "ttDatum";
1099
1155
  function Dataset(o) {
1100
1156
  o = o || {};
@@ -1148,6 +1204,7 @@
1148
1204
  nodes = _.map(suggestions, getSuggestionNode);
1149
1205
  $suggestions.append.apply($suggestions, nodes);
1150
1206
  that.highlight && highlight({
1207
+ className: "tt-highlight",
1151
1208
  node: $suggestions[0],
1152
1209
  pattern: query
1153
1210
  });
@@ -1227,6 +1284,7 @@
1227
1284
  }
1228
1285
  }();
1229
1286
  var Dropdown = function() {
1287
+ "use strict";
1230
1288
  function Dropdown(o) {
1231
1289
  var that = this, onSuggestionClick, onSuggestionMouseEnter, onSuggestionMouseLeave;
1232
1290
  o = o || {};
@@ -1386,6 +1444,7 @@
1386
1444
  }
1387
1445
  }();
1388
1446
  var Typeahead = function() {
1447
+ "use strict";
1389
1448
  var attrsKey = "ttAttrs";
1390
1449
  function Typeahead(o) {
1391
1450
  var $menu, $input, $hint;
@@ -1396,7 +1455,7 @@
1396
1455
  this.isActivated = false;
1397
1456
  this.autoselect = !!o.autoselect;
1398
1457
  this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;
1399
- this.$node = buildDomStructure(o.input, o.withHint);
1458
+ this.$node = buildDom(o.input, o.withHint);
1400
1459
  $menu = this.$node.find(".tt-dropdown-menu");
1401
1460
  $input = this.$node.find(".tt-input");
1402
1461
  $hint = this.$node.find(".tt-hint");
@@ -1564,6 +1623,7 @@
1564
1623
  this.dropdown.close();
1565
1624
  },
1566
1625
  setVal: function setVal(val) {
1626
+ val = _.toStr(val);
1567
1627
  if (this.isActivated) {
1568
1628
  this.input.setInputValue(val);
1569
1629
  } else {
@@ -1583,15 +1643,16 @@
1583
1643
  }
1584
1644
  });
1585
1645
  return Typeahead;
1586
- function buildDomStructure(input, withHint) {
1646
+ function buildDom(input, withHint) {
1587
1647
  var $input, $wrapper, $dropdown, $hint;
1588
1648
  $input = $(input);
1589
1649
  $wrapper = $(html.wrapper).css(css.wrapper);
1590
1650
  $dropdown = $(html.dropdown).css(css.dropdown);
1591
1651
  $hint = $input.clone().css(css.hint).css(getBackgroundStyles($input));
1592
- $hint.val("").removeData().addClass("tt-hint").removeAttr("id name placeholder").prop("disabled", true).attr({
1652
+ $hint.val("").removeData().addClass("tt-hint").removeAttr("id name placeholder required").prop("readonly", true).attr({
1593
1653
  autocomplete: "off",
1594
- spellcheck: "false"
1654
+ spellcheck: "false",
1655
+ tabindex: -1
1595
1656
  });
1596
1657
  $input.data(attrsKey, {
1597
1658
  dir: $input.attr("dir"),
@@ -1630,6 +1691,7 @@
1630
1691
  }
1631
1692
  }();
1632
1693
  (function() {
1694
+ "use strict";
1633
1695
  var old, typeaheadKey, methods;
1634
1696
  old = $.fn.typeahead;
1635
1697
  typeaheadKey = "ttTypeahead";
@@ -1702,8 +1764,12 @@
1702
1764
  }
1703
1765
  };
1704
1766
  $.fn.typeahead = function(method) {
1705
- if (methods[method]) {
1706
- return methods[method].apply(this, [].slice.call(arguments, 1));
1767
+ var tts;
1768
+ if (methods[method] && method !== "initialize") {
1769
+ tts = this.filter(function() {
1770
+ return !!$(this).data(typeaheadKey);
1771
+ });
1772
+ return methods[method].apply(tts, [].slice.call(arguments, 1));
1707
1773
  } else {
1708
1774
  return methods.initialize.apply(this, arguments);
1709
1775
  }