twitter-typeahead-rails 0.10.1 → 0.10.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +2 -2
- data/lib/twitter-typeahead-rails/version.rb +1 -1
- data/vendor/assets/javascripts/twitter/typeahead/bloodhound.js +77 -44
- data/vendor/assets/javascripts/twitter/typeahead/typeahead.bundle.js +170 -112
- data/vendor/assets/javascripts/twitter/typeahead/typeahead.bundle.min.js +3 -3
- data/vendor/assets/javascripts/twitter/typeahead/typeahead.jquery.js +95 -70
- metadata +2 -2
data/README.md
CHANGED
@@ -46,7 +46,7 @@ Add one of the following to your application.js manifest:
|
|
46
46
|
|
47
47
|
// instantiate the bloodhound suggestion engine
|
48
48
|
var numbers = new Bloodhound({
|
49
|
-
datumTokenizer:
|
49
|
+
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('num'),
|
50
50
|
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
51
51
|
local: [
|
52
52
|
{ num: 'one' },
|
@@ -72,7 +72,7 @@ $('.example-numbers .typeahead').typeahead(null, {
|
|
72
72
|
});
|
73
73
|
```
|
74
74
|
|
75
|
-
Currently this version tracks version v0.10.
|
75
|
+
Currently this version tracks version v0.10.2.
|
76
76
|
|
77
77
|
## Contributing
|
78
78
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
/*!
|
2
|
-
* typeahead.js 0.10.
|
2
|
+
* typeahead.js 0.10.2
|
3
3
|
* https://github.com/twitter/typeahead.js
|
4
|
-
* Copyright 2013 Twitter, Inc. and other contributors; Licensed MIT
|
4
|
+
* Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
|
5
5
|
*/
|
6
6
|
|
7
7
|
(function($) {
|
@@ -120,8 +120,31 @@
|
|
120
120
|
},
|
121
121
|
noop: function() {}
|
122
122
|
};
|
123
|
-
var VERSION = "0.10.
|
124
|
-
var
|
123
|
+
var VERSION = "0.10.2";
|
124
|
+
var tokenizers = function(root) {
|
125
|
+
return {
|
126
|
+
nonword: nonword,
|
127
|
+
whitespace: whitespace,
|
128
|
+
obj: {
|
129
|
+
nonword: getObjTokenizer(nonword),
|
130
|
+
whitespace: getObjTokenizer(whitespace)
|
131
|
+
}
|
132
|
+
};
|
133
|
+
function whitespace(s) {
|
134
|
+
return s.split(/\s+/);
|
135
|
+
}
|
136
|
+
function nonword(s) {
|
137
|
+
return s.split(/\W+/);
|
138
|
+
}
|
139
|
+
function getObjTokenizer(tokenizer) {
|
140
|
+
return function setKey(key) {
|
141
|
+
return function tokenize(o) {
|
142
|
+
return tokenizer(o[key]);
|
143
|
+
};
|
144
|
+
};
|
145
|
+
}
|
146
|
+
}();
|
147
|
+
var LruCache = function() {
|
125
148
|
function LruCache(maxSize) {
|
126
149
|
this.maxSize = maxSize || 100;
|
127
150
|
this.size = 0;
|
@@ -180,7 +203,7 @@
|
|
180
203
|
this.prev = this.next = null;
|
181
204
|
}
|
182
205
|
return LruCache;
|
183
|
-
}(
|
206
|
+
}();
|
184
207
|
var PersistentStorage = function() {
|
185
208
|
var ls, methods;
|
186
209
|
try {
|
@@ -277,17 +300,20 @@
|
|
277
300
|
_get: function(url, o, cb) {
|
278
301
|
var that = this, jqXhr;
|
279
302
|
if (jqXhr = pendingRequests[url]) {
|
280
|
-
jqXhr.done(done);
|
303
|
+
jqXhr.done(done).fail(fail);
|
281
304
|
} else if (pendingRequestsCount < maxPendingRequests) {
|
282
305
|
pendingRequestsCount++;
|
283
|
-
pendingRequests[url] = this._send(url, o).done(done).always(always);
|
306
|
+
pendingRequests[url] = this._send(url, o).done(done).fail(fail).always(always);
|
284
307
|
} else {
|
285
308
|
this.onDeckRequestArgs = [].slice.call(arguments, 0);
|
286
309
|
}
|
287
310
|
function done(resp) {
|
288
|
-
cb && cb(resp);
|
311
|
+
cb && cb(null, resp);
|
289
312
|
requestCache.set(url, resp);
|
290
313
|
}
|
314
|
+
function fail() {
|
315
|
+
cb && cb(true);
|
316
|
+
}
|
291
317
|
function always() {
|
292
318
|
pendingRequestsCount--;
|
293
319
|
delete pendingRequests[url];
|
@@ -298,14 +324,14 @@
|
|
298
324
|
}
|
299
325
|
},
|
300
326
|
get: function(url, o, cb) {
|
301
|
-
var
|
327
|
+
var resp;
|
302
328
|
if (_.isFunction(o)) {
|
303
329
|
cb = o;
|
304
330
|
o = {};
|
305
331
|
}
|
306
332
|
if (resp = requestCache.get(url)) {
|
307
333
|
_.defer(function() {
|
308
|
-
cb && cb(resp);
|
334
|
+
cb && cb(null, resp);
|
309
335
|
});
|
310
336
|
} else {
|
311
337
|
this._get(url, o, cb);
|
@@ -340,8 +366,7 @@
|
|
340
366
|
}
|
341
367
|
this.datumTokenizer = o.datumTokenizer;
|
342
368
|
this.queryTokenizer = o.queryTokenizer;
|
343
|
-
this.
|
344
|
-
this.trie = newNode();
|
369
|
+
this.reset();
|
345
370
|
}
|
346
371
|
_.mixin(SearchIndex.prototype, {
|
347
372
|
bootstrap: function bootstrap(o) {
|
@@ -356,7 +381,7 @@
|
|
356
381
|
id = that.datums.push(datum) - 1;
|
357
382
|
tokens = normalizeTokens(that.datumTokenizer(datum));
|
358
383
|
_.each(tokens, function(token) {
|
359
|
-
var node, chars, ch
|
384
|
+
var node, chars, ch;
|
360
385
|
node = that.trie;
|
361
386
|
chars = token.split("");
|
362
387
|
while (ch = chars.shift()) {
|
@@ -391,6 +416,10 @@
|
|
391
416
|
return that.datums[id];
|
392
417
|
}) : [];
|
393
418
|
},
|
419
|
+
reset: function reset() {
|
420
|
+
this.datums = [];
|
421
|
+
this.trie = newNode();
|
422
|
+
},
|
394
423
|
serialize: function serialize() {
|
395
424
|
return {
|
396
425
|
datums: this.datums,
|
@@ -452,11 +481,7 @@
|
|
452
481
|
remote: getRemote
|
453
482
|
};
|
454
483
|
function getLocal(o) {
|
455
|
-
|
456
|
-
if (_.isFunction(local)) {
|
457
|
-
local = local.call(null);
|
458
|
-
}
|
459
|
-
return local;
|
484
|
+
return o.local || null;
|
460
485
|
}
|
461
486
|
function getPrefetch(o) {
|
462
487
|
var prefetch, defaults;
|
@@ -516,13 +541,15 @@
|
|
516
541
|
}
|
517
542
|
}
|
518
543
|
}();
|
519
|
-
|
520
|
-
var keys;
|
544
|
+
(function(root) {
|
545
|
+
var old, keys;
|
546
|
+
old = root.Bloodhound;
|
521
547
|
keys = {
|
522
548
|
data: "data",
|
523
549
|
protocol: "protocol",
|
524
550
|
thumbprint: "thumbprint"
|
525
551
|
};
|
552
|
+
root.Bloodhound = Bloodhound;
|
526
553
|
function Bloodhound(o) {
|
527
554
|
if (!o || !o.local && !o.prefetch && !o.remote) {
|
528
555
|
$.error("one of local, prefetch, or remote is required");
|
@@ -540,14 +567,11 @@
|
|
540
567
|
});
|
541
568
|
this.storage = this.cacheKey ? new PersistentStorage(this.cacheKey) : null;
|
542
569
|
}
|
543
|
-
Bloodhound.
|
544
|
-
|
545
|
-
|
546
|
-
},
|
547
|
-
nonword: function nonwordTokenizer(s) {
|
548
|
-
return s.split(/\W+/);
|
549
|
-
}
|
570
|
+
Bloodhound.noConflict = function noConflict() {
|
571
|
+
root.Bloodhound = old;
|
572
|
+
return Bloodhound;
|
550
573
|
};
|
574
|
+
Bloodhound.tokenizers = tokenizers;
|
551
575
|
_.mixin(Bloodhound.prototype, {
|
552
576
|
_loadPrefetch: function loadPrefetch(o) {
|
553
577
|
var that = this, serialized, deferred;
|
@@ -559,9 +583,8 @@
|
|
559
583
|
}
|
560
584
|
return deferred;
|
561
585
|
function handlePrefetchResponse(resp) {
|
562
|
-
|
563
|
-
|
564
|
-
that.add(filtered);
|
586
|
+
that.clear();
|
587
|
+
that.add(o.filter ? o.filter(resp) : resp);
|
565
588
|
that._saveToStorage(that.index.serialize(), o.thumbprint, o.ttl);
|
566
589
|
}
|
567
590
|
},
|
@@ -571,9 +594,8 @@
|
|
571
594
|
uriEncodedQuery = encodeURIComponent(query);
|
572
595
|
url = this.remote.replace ? this.remote.replace(this.remote.url, query) : this.remote.url.replace(this.remote.wildcard, uriEncodedQuery);
|
573
596
|
return this.transport.get(url, this.remote.ajax, handleRemoteResponse);
|
574
|
-
function handleRemoteResponse(resp) {
|
575
|
-
|
576
|
-
cb(filtered);
|
597
|
+
function handleRemoteResponse(err, resp) {
|
598
|
+
err ? cb([]) : cb(that.remote.filter ? that.remote.filter(resp) : resp);
|
577
599
|
}
|
578
600
|
},
|
579
601
|
_saveToStorage: function saveToStorage(data, thumbprint, ttl) {
|
@@ -593,30 +615,32 @@
|
|
593
615
|
isExpired = stored.thumbprint !== thumbprint || stored.protocol !== location.protocol;
|
594
616
|
return stored.data && !isExpired ? stored.data : null;
|
595
617
|
},
|
596
|
-
|
597
|
-
var that = this, deferred;
|
618
|
+
_initialize: function initialize() {
|
619
|
+
var that = this, local = this.local, deferred;
|
598
620
|
deferred = this.prefetch ? this._loadPrefetch(this.prefetch) : $.Deferred().resolve();
|
599
|
-
|
621
|
+
local && deferred.done(addLocalToIndex);
|
600
622
|
this.transport = this.remote ? new Transport(this.remote) : null;
|
601
|
-
this.
|
602
|
-
return deferred.promise();
|
603
|
-
};
|
604
|
-
return deferred.promise();
|
623
|
+
return this.initPromise = deferred.promise();
|
605
624
|
function addLocalToIndex() {
|
606
|
-
that.add(
|
625
|
+
that.add(_.isFunction(local) ? local() : local);
|
607
626
|
}
|
608
627
|
},
|
628
|
+
initialize: function initialize(force) {
|
629
|
+
return !this.initPromise || force ? this._initialize() : this.initPromise;
|
630
|
+
},
|
609
631
|
add: function add(data) {
|
610
632
|
this.index.add(data);
|
611
633
|
},
|
612
634
|
get: function get(query, cb) {
|
613
|
-
var that = this, matches, cacheHit = false;
|
635
|
+
var that = this, matches = [], cacheHit = false;
|
614
636
|
matches = this.index.get(query);
|
615
637
|
matches = this.sorter(matches).slice(0, this.limit);
|
616
638
|
if (matches.length < this.limit && this.transport) {
|
617
639
|
cacheHit = this._getFromRemote(query, returnRemoteMatches);
|
618
640
|
}
|
619
|
-
!cacheHit
|
641
|
+
if (!cacheHit) {
|
642
|
+
(matches.length > 0 || !this.transport) && cb && cb(matches);
|
643
|
+
}
|
620
644
|
function returnRemoteMatches(remoteMatches) {
|
621
645
|
var matchesWithBackfill = matches.slice(0);
|
622
646
|
_.each(remoteMatches, function(remoteMatch) {
|
@@ -630,6 +654,15 @@
|
|
630
654
|
cb && cb(that.sorter(matchesWithBackfill));
|
631
655
|
}
|
632
656
|
},
|
657
|
+
clear: function clear() {
|
658
|
+
this.index.reset();
|
659
|
+
},
|
660
|
+
clearPrefetchCache: function clearPrefetchCache() {
|
661
|
+
this.storage && this.storage.clear();
|
662
|
+
},
|
663
|
+
clearRemoteCache: function clearRemoteCache() {
|
664
|
+
this.transport && Transport.resetCache();
|
665
|
+
},
|
633
666
|
ttAdapter: function ttAdapter() {
|
634
667
|
return _.bind(this.get, this);
|
635
668
|
}
|
@@ -647,5 +680,5 @@
|
|
647
680
|
function ignoreDuplicates() {
|
648
681
|
return false;
|
649
682
|
}
|
650
|
-
}();
|
683
|
+
})(this);
|
651
684
|
})(window.jQuery);
|
@@ -1,7 +1,7 @@
|
|
1
1
|
/*!
|
2
|
-
* typeahead.js 0.10.
|
2
|
+
* typeahead.js 0.10.2
|
3
3
|
* https://github.com/twitter/typeahead.js
|
4
|
-
* Copyright 2013 Twitter, Inc. and other contributors; Licensed MIT
|
4
|
+
* Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
|
5
5
|
*/
|
6
6
|
|
7
7
|
(function($) {
|
@@ -120,8 +120,31 @@
|
|
120
120
|
},
|
121
121
|
noop: function() {}
|
122
122
|
};
|
123
|
-
var VERSION = "0.10.
|
124
|
-
var
|
123
|
+
var VERSION = "0.10.2";
|
124
|
+
var tokenizers = function(root) {
|
125
|
+
return {
|
126
|
+
nonword: nonword,
|
127
|
+
whitespace: whitespace,
|
128
|
+
obj: {
|
129
|
+
nonword: getObjTokenizer(nonword),
|
130
|
+
whitespace: getObjTokenizer(whitespace)
|
131
|
+
}
|
132
|
+
};
|
133
|
+
function whitespace(s) {
|
134
|
+
return s.split(/\s+/);
|
135
|
+
}
|
136
|
+
function nonword(s) {
|
137
|
+
return s.split(/\W+/);
|
138
|
+
}
|
139
|
+
function getObjTokenizer(tokenizer) {
|
140
|
+
return function setKey(key) {
|
141
|
+
return function tokenize(o) {
|
142
|
+
return tokenizer(o[key]);
|
143
|
+
};
|
144
|
+
};
|
145
|
+
}
|
146
|
+
}();
|
147
|
+
var LruCache = function() {
|
125
148
|
function LruCache(maxSize) {
|
126
149
|
this.maxSize = maxSize || 100;
|
127
150
|
this.size = 0;
|
@@ -180,7 +203,7 @@
|
|
180
203
|
this.prev = this.next = null;
|
181
204
|
}
|
182
205
|
return LruCache;
|
183
|
-
}(
|
206
|
+
}();
|
184
207
|
var PersistentStorage = function() {
|
185
208
|
var ls, methods;
|
186
209
|
try {
|
@@ -277,17 +300,20 @@
|
|
277
300
|
_get: function(url, o, cb) {
|
278
301
|
var that = this, jqXhr;
|
279
302
|
if (jqXhr = pendingRequests[url]) {
|
280
|
-
jqXhr.done(done);
|
303
|
+
jqXhr.done(done).fail(fail);
|
281
304
|
} else if (pendingRequestsCount < maxPendingRequests) {
|
282
305
|
pendingRequestsCount++;
|
283
|
-
pendingRequests[url] = this._send(url, o).done(done).always(always);
|
306
|
+
pendingRequests[url] = this._send(url, o).done(done).fail(fail).always(always);
|
284
307
|
} else {
|
285
308
|
this.onDeckRequestArgs = [].slice.call(arguments, 0);
|
286
309
|
}
|
287
310
|
function done(resp) {
|
288
|
-
cb && cb(resp);
|
311
|
+
cb && cb(null, resp);
|
289
312
|
requestCache.set(url, resp);
|
290
313
|
}
|
314
|
+
function fail() {
|
315
|
+
cb && cb(true);
|
316
|
+
}
|
291
317
|
function always() {
|
292
318
|
pendingRequestsCount--;
|
293
319
|
delete pendingRequests[url];
|
@@ -298,14 +324,14 @@
|
|
298
324
|
}
|
299
325
|
},
|
300
326
|
get: function(url, o, cb) {
|
301
|
-
var
|
327
|
+
var resp;
|
302
328
|
if (_.isFunction(o)) {
|
303
329
|
cb = o;
|
304
330
|
o = {};
|
305
331
|
}
|
306
332
|
if (resp = requestCache.get(url)) {
|
307
333
|
_.defer(function() {
|
308
|
-
cb && cb(resp);
|
334
|
+
cb && cb(null, resp);
|
309
335
|
});
|
310
336
|
} else {
|
311
337
|
this._get(url, o, cb);
|
@@ -340,8 +366,7 @@
|
|
340
366
|
}
|
341
367
|
this.datumTokenizer = o.datumTokenizer;
|
342
368
|
this.queryTokenizer = o.queryTokenizer;
|
343
|
-
this.
|
344
|
-
this.trie = newNode();
|
369
|
+
this.reset();
|
345
370
|
}
|
346
371
|
_.mixin(SearchIndex.prototype, {
|
347
372
|
bootstrap: function bootstrap(o) {
|
@@ -356,7 +381,7 @@
|
|
356
381
|
id = that.datums.push(datum) - 1;
|
357
382
|
tokens = normalizeTokens(that.datumTokenizer(datum));
|
358
383
|
_.each(tokens, function(token) {
|
359
|
-
var node, chars, ch
|
384
|
+
var node, chars, ch;
|
360
385
|
node = that.trie;
|
361
386
|
chars = token.split("");
|
362
387
|
while (ch = chars.shift()) {
|
@@ -391,6 +416,10 @@
|
|
391
416
|
return that.datums[id];
|
392
417
|
}) : [];
|
393
418
|
},
|
419
|
+
reset: function reset() {
|
420
|
+
this.datums = [];
|
421
|
+
this.trie = newNode();
|
422
|
+
},
|
394
423
|
serialize: function serialize() {
|
395
424
|
return {
|
396
425
|
datums: this.datums,
|
@@ -452,11 +481,7 @@
|
|
452
481
|
remote: getRemote
|
453
482
|
};
|
454
483
|
function getLocal(o) {
|
455
|
-
|
456
|
-
if (_.isFunction(local)) {
|
457
|
-
local = local.call(null);
|
458
|
-
}
|
459
|
-
return local;
|
484
|
+
return o.local || null;
|
460
485
|
}
|
461
486
|
function getPrefetch(o) {
|
462
487
|
var prefetch, defaults;
|
@@ -516,13 +541,15 @@
|
|
516
541
|
}
|
517
542
|
}
|
518
543
|
}();
|
519
|
-
|
520
|
-
var keys;
|
544
|
+
(function(root) {
|
545
|
+
var old, keys;
|
546
|
+
old = root.Bloodhound;
|
521
547
|
keys = {
|
522
548
|
data: "data",
|
523
549
|
protocol: "protocol",
|
524
550
|
thumbprint: "thumbprint"
|
525
551
|
};
|
552
|
+
root.Bloodhound = Bloodhound;
|
526
553
|
function Bloodhound(o) {
|
527
554
|
if (!o || !o.local && !o.prefetch && !o.remote) {
|
528
555
|
$.error("one of local, prefetch, or remote is required");
|
@@ -540,14 +567,11 @@
|
|
540
567
|
});
|
541
568
|
this.storage = this.cacheKey ? new PersistentStorage(this.cacheKey) : null;
|
542
569
|
}
|
543
|
-
Bloodhound.
|
544
|
-
|
545
|
-
|
546
|
-
},
|
547
|
-
nonword: function nonwordTokenizer(s) {
|
548
|
-
return s.split(/\W+/);
|
549
|
-
}
|
570
|
+
Bloodhound.noConflict = function noConflict() {
|
571
|
+
root.Bloodhound = old;
|
572
|
+
return Bloodhound;
|
550
573
|
};
|
574
|
+
Bloodhound.tokenizers = tokenizers;
|
551
575
|
_.mixin(Bloodhound.prototype, {
|
552
576
|
_loadPrefetch: function loadPrefetch(o) {
|
553
577
|
var that = this, serialized, deferred;
|
@@ -559,9 +583,8 @@
|
|
559
583
|
}
|
560
584
|
return deferred;
|
561
585
|
function handlePrefetchResponse(resp) {
|
562
|
-
|
563
|
-
|
564
|
-
that.add(filtered);
|
586
|
+
that.clear();
|
587
|
+
that.add(o.filter ? o.filter(resp) : resp);
|
565
588
|
that._saveToStorage(that.index.serialize(), o.thumbprint, o.ttl);
|
566
589
|
}
|
567
590
|
},
|
@@ -571,9 +594,8 @@
|
|
571
594
|
uriEncodedQuery = encodeURIComponent(query);
|
572
595
|
url = this.remote.replace ? this.remote.replace(this.remote.url, query) : this.remote.url.replace(this.remote.wildcard, uriEncodedQuery);
|
573
596
|
return this.transport.get(url, this.remote.ajax, handleRemoteResponse);
|
574
|
-
function handleRemoteResponse(resp) {
|
575
|
-
|
576
|
-
cb(filtered);
|
597
|
+
function handleRemoteResponse(err, resp) {
|
598
|
+
err ? cb([]) : cb(that.remote.filter ? that.remote.filter(resp) : resp);
|
577
599
|
}
|
578
600
|
},
|
579
601
|
_saveToStorage: function saveToStorage(data, thumbprint, ttl) {
|
@@ -593,30 +615,32 @@
|
|
593
615
|
isExpired = stored.thumbprint !== thumbprint || stored.protocol !== location.protocol;
|
594
616
|
return stored.data && !isExpired ? stored.data : null;
|
595
617
|
},
|
596
|
-
|
597
|
-
var that = this, deferred;
|
618
|
+
_initialize: function initialize() {
|
619
|
+
var that = this, local = this.local, deferred;
|
598
620
|
deferred = this.prefetch ? this._loadPrefetch(this.prefetch) : $.Deferred().resolve();
|
599
|
-
|
621
|
+
local && deferred.done(addLocalToIndex);
|
600
622
|
this.transport = this.remote ? new Transport(this.remote) : null;
|
601
|
-
this.
|
602
|
-
return deferred.promise();
|
603
|
-
};
|
604
|
-
return deferred.promise();
|
623
|
+
return this.initPromise = deferred.promise();
|
605
624
|
function addLocalToIndex() {
|
606
|
-
that.add(
|
625
|
+
that.add(_.isFunction(local) ? local() : local);
|
607
626
|
}
|
608
627
|
},
|
628
|
+
initialize: function initialize(force) {
|
629
|
+
return !this.initPromise || force ? this._initialize() : this.initPromise;
|
630
|
+
},
|
609
631
|
add: function add(data) {
|
610
632
|
this.index.add(data);
|
611
633
|
},
|
612
634
|
get: function get(query, cb) {
|
613
|
-
var that = this, matches, cacheHit = false;
|
635
|
+
var that = this, matches = [], cacheHit = false;
|
614
636
|
matches = this.index.get(query);
|
615
637
|
matches = this.sorter(matches).slice(0, this.limit);
|
616
638
|
if (matches.length < this.limit && this.transport) {
|
617
639
|
cacheHit = this._getFromRemote(query, returnRemoteMatches);
|
618
640
|
}
|
619
|
-
!cacheHit
|
641
|
+
if (!cacheHit) {
|
642
|
+
(matches.length > 0 || !this.transport) && cb && cb(matches);
|
643
|
+
}
|
620
644
|
function returnRemoteMatches(remoteMatches) {
|
621
645
|
var matchesWithBackfill = matches.slice(0);
|
622
646
|
_.each(remoteMatches, function(remoteMatch) {
|
@@ -630,6 +654,15 @@
|
|
630
654
|
cb && cb(that.sorter(matchesWithBackfill));
|
631
655
|
}
|
632
656
|
},
|
657
|
+
clear: function clear() {
|
658
|
+
this.index.reset();
|
659
|
+
},
|
660
|
+
clearPrefetchCache: function clearPrefetchCache() {
|
661
|
+
this.storage && this.storage.clear();
|
662
|
+
},
|
663
|
+
clearRemoteCache: function clearRemoteCache() {
|
664
|
+
this.transport && Transport.resetCache();
|
665
|
+
},
|
633
666
|
ttAdapter: function ttAdapter() {
|
634
667
|
return _.bind(this.get, this);
|
635
668
|
}
|
@@ -647,13 +680,13 @@
|
|
647
680
|
function ignoreDuplicates() {
|
648
681
|
return false;
|
649
682
|
}
|
650
|
-
}();
|
683
|
+
})(this);
|
651
684
|
var html = {
|
652
685
|
wrapper: '<span class="twitter-typeahead"></span>',
|
653
686
|
dropdown: '<span class="tt-dropdown-menu"></span>',
|
654
687
|
dataset: '<div class="tt-dataset-%CLASS%"></div>',
|
655
688
|
suggestions: '<span class="tt-suggestions"></span>',
|
656
|
-
suggestion: '<div class="tt-suggestion"
|
689
|
+
suggestion: '<div class="tt-suggestion"></div>'
|
657
690
|
};
|
658
691
|
var css = {
|
659
692
|
wrapper: {
|
@@ -771,7 +804,7 @@
|
|
771
804
|
return this;
|
772
805
|
}
|
773
806
|
function trigger(types) {
|
774
|
-
var
|
807
|
+
var type, callbacks, args, syncFlush, asyncFlush;
|
775
808
|
if (!this._callbacks) {
|
776
809
|
return this;
|
777
810
|
}
|
@@ -795,7 +828,7 @@
|
|
795
828
|
}
|
796
829
|
}
|
797
830
|
function getNextTick() {
|
798
|
-
var nextTickFn
|
831
|
+
var nextTickFn;
|
799
832
|
if (window.setImmediate) {
|
800
833
|
nextTickFn = function nextTickSetImmediate(fn) {
|
801
834
|
setImmediate(function() {
|
@@ -892,7 +925,7 @@
|
|
892
925
|
this.$hint = $(o.hint);
|
893
926
|
this.$input = $(o.input).on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown);
|
894
927
|
if (this.$hint.length === 0) {
|
895
|
-
this.
|
928
|
+
this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop;
|
896
929
|
}
|
897
930
|
if (!_.isMsie()) {
|
898
931
|
this.$input.on("input.tt", onInput);
|
@@ -911,11 +944,11 @@
|
|
911
944
|
return (str || "").replace(/^\s*/g, "").replace(/\s{2,}/g, " ");
|
912
945
|
};
|
913
946
|
_.mixin(Input.prototype, EventEmitter, {
|
914
|
-
_onBlur: function onBlur(
|
947
|
+
_onBlur: function onBlur() {
|
915
948
|
this.resetInputValue();
|
916
949
|
this.trigger("blurred");
|
917
950
|
},
|
918
|
-
_onFocus: function onFocus(
|
951
|
+
_onFocus: function onFocus() {
|
919
952
|
this.trigger("focused");
|
920
953
|
},
|
921
954
|
_onKeydown: function onKeydown($e) {
|
@@ -925,14 +958,14 @@
|
|
925
958
|
this.trigger(keyName + "Keyed", $e);
|
926
959
|
}
|
927
960
|
},
|
928
|
-
_onInput: function onInput(
|
961
|
+
_onInput: function onInput() {
|
929
962
|
this._checkInputValue();
|
930
963
|
},
|
931
964
|
_managePreventDefault: function managePreventDefault(keyName, $e) {
|
932
965
|
var preventDefault, hintValue, inputValue;
|
933
966
|
switch (keyName) {
|
934
967
|
case "tab":
|
935
|
-
hintValue = this.
|
968
|
+
hintValue = this.getHint();
|
936
969
|
inputValue = this.getInputValue();
|
937
970
|
preventDefault = hintValue && hintValue !== inputValue && !withModifier($e);
|
938
971
|
break;
|
@@ -987,19 +1020,27 @@
|
|
987
1020
|
},
|
988
1021
|
setInputValue: function setInputValue(value, silent) {
|
989
1022
|
this.$input.val(value);
|
990
|
-
|
1023
|
+
silent ? this.clearHint() : this._checkInputValue();
|
991
1024
|
},
|
992
|
-
|
1025
|
+
resetInputValue: function resetInputValue() {
|
1026
|
+
this.setInputValue(this.query, true);
|
1027
|
+
},
|
1028
|
+
getHint: function getHint() {
|
993
1029
|
return this.$hint.val();
|
994
1030
|
},
|
995
|
-
|
1031
|
+
setHint: function setHint(value) {
|
996
1032
|
this.$hint.val(value);
|
997
1033
|
},
|
998
|
-
resetInputValue: function resetInputValue() {
|
999
|
-
this.$input.val(this.query);
|
1000
|
-
},
|
1001
1034
|
clearHint: function clearHint() {
|
1002
|
-
this
|
1035
|
+
this.setHint("");
|
1036
|
+
},
|
1037
|
+
clearHintIfInvalid: function clearHintIfInvalid() {
|
1038
|
+
var val, hint, valIsPrefixOfHint, isValid;
|
1039
|
+
val = this.getInputValue();
|
1040
|
+
hint = this.getHint();
|
1041
|
+
valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;
|
1042
|
+
isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow();
|
1043
|
+
!isValid && this.clearHint();
|
1003
1044
|
},
|
1004
1045
|
getLanguageDirection: function getLanguageDirection() {
|
1005
1046
|
return (this.$input.css("direction") || "ltr").toLowerCase();
|
@@ -1033,7 +1074,7 @@
|
|
1033
1074
|
return $('<pre aria-hidden="true"></pre>').css({
|
1034
1075
|
position: "absolute",
|
1035
1076
|
visibility: "hidden",
|
1036
|
-
whiteSpace: "
|
1077
|
+
whiteSpace: "pre",
|
1037
1078
|
fontFamily: $input.css("font-family"),
|
1038
1079
|
fontSize: $input.css("font-size"),
|
1039
1080
|
fontStyle: $input.css("font-style"),
|
@@ -1112,10 +1153,8 @@
|
|
1112
1153
|
});
|
1113
1154
|
return $suggestions;
|
1114
1155
|
function getSuggestionNode(suggestion) {
|
1115
|
-
var $el
|
1116
|
-
|
1117
|
-
outerHtml = html.suggestion.replace("%BODY%", innerHtml);
|
1118
|
-
$el = $(outerHtml).data(datasetKey, that.name).data(valueKey, that.displayFn(suggestion)).data(datumKey, suggestion);
|
1156
|
+
var $el;
|
1157
|
+
$el = $(html.suggestion).append(that.templates.suggestion(suggestion)).data(datasetKey, that.name).data(valueKey, that.displayFn(suggestion)).data(datumKey, suggestion);
|
1119
1158
|
$el.children().each(function() {
|
1120
1159
|
$(this).css(css.suggestionChild);
|
1121
1160
|
});
|
@@ -1141,13 +1180,21 @@
|
|
1141
1180
|
update: function update(query) {
|
1142
1181
|
var that = this;
|
1143
1182
|
this.query = query;
|
1144
|
-
this.
|
1145
|
-
|
1146
|
-
|
1183
|
+
this.canceled = false;
|
1184
|
+
this.source(query, render);
|
1185
|
+
function render(suggestions) {
|
1186
|
+
if (!that.canceled && query === that.query) {
|
1187
|
+
that._render(query, suggestions);
|
1188
|
+
}
|
1147
1189
|
}
|
1148
1190
|
},
|
1191
|
+
cancel: function cancel() {
|
1192
|
+
this.canceled = true;
|
1193
|
+
},
|
1149
1194
|
clear: function clear() {
|
1150
|
-
this.
|
1195
|
+
this.cancel();
|
1196
|
+
this.$el.empty();
|
1197
|
+
this.trigger("rendered");
|
1151
1198
|
},
|
1152
1199
|
isEmpty: function isEmpty() {
|
1153
1200
|
return this.$el.is(":empty");
|
@@ -1206,7 +1253,7 @@
|
|
1206
1253
|
this._removeCursor();
|
1207
1254
|
this._setCursor($($e.currentTarget), true);
|
1208
1255
|
},
|
1209
|
-
_onSuggestionMouseLeave: function onSuggestionMouseLeave(
|
1256
|
+
_onSuggestionMouseLeave: function onSuggestionMouseLeave() {
|
1210
1257
|
this._removeCursor();
|
1211
1258
|
},
|
1212
1259
|
_onRendered: function onRendered() {
|
@@ -1341,17 +1388,34 @@
|
|
1341
1388
|
var Typeahead = function() {
|
1342
1389
|
var attrsKey = "ttAttrs";
|
1343
1390
|
function Typeahead(o) {
|
1344
|
-
var $menu, $input, $hint
|
1391
|
+
var $menu, $input, $hint;
|
1345
1392
|
o = o || {};
|
1346
1393
|
if (!o.input) {
|
1347
1394
|
$.error("missing input");
|
1348
1395
|
}
|
1396
|
+
this.isActivated = false;
|
1349
1397
|
this.autoselect = !!o.autoselect;
|
1350
1398
|
this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;
|
1351
1399
|
this.$node = buildDomStructure(o.input, o.withHint);
|
1352
1400
|
$menu = this.$node.find(".tt-dropdown-menu");
|
1353
1401
|
$input = this.$node.find(".tt-input");
|
1354
1402
|
$hint = this.$node.find(".tt-hint");
|
1403
|
+
$input.on("blur.tt", function($e) {
|
1404
|
+
var active, isActive, hasActive;
|
1405
|
+
active = document.activeElement;
|
1406
|
+
isActive = $menu.is(active);
|
1407
|
+
hasActive = $menu.has(active).length > 0;
|
1408
|
+
if (_.isMsie() && (isActive || hasActive)) {
|
1409
|
+
$e.preventDefault();
|
1410
|
+
$e.stopImmediatePropagation();
|
1411
|
+
_.defer(function() {
|
1412
|
+
$input.focus();
|
1413
|
+
});
|
1414
|
+
}
|
1415
|
+
});
|
1416
|
+
$menu.on("mousedown.tt", function($e) {
|
1417
|
+
$e.preventDefault();
|
1418
|
+
});
|
1355
1419
|
this.eventBus = o.eventBus || new EventBus({
|
1356
1420
|
el: $input
|
1357
1421
|
});
|
@@ -1363,15 +1427,7 @@
|
|
1363
1427
|
input: $input,
|
1364
1428
|
hint: $hint
|
1365
1429
|
}).onSync("focused", this._onFocused, this).onSync("blurred", this._onBlurred, this).onSync("enterKeyed", this._onEnterKeyed, this).onSync("tabKeyed", this._onTabKeyed, this).onSync("escKeyed", this._onEscKeyed, this).onSync("upKeyed", this._onUpKeyed, this).onSync("downKeyed", this._onDownKeyed, this).onSync("leftKeyed", this._onLeftKeyed, this).onSync("rightKeyed", this._onRightKeyed, this).onSync("queryChanged", this._onQueryChanged, this).onSync("whitespaceChanged", this._onWhitespaceChanged, this);
|
1366
|
-
|
1367
|
-
if (_.isMsie() && _.isMsie() < 9) {
|
1368
|
-
$input[0].onbeforedeactivate = function() {
|
1369
|
-
window.event.returnValue = false;
|
1370
|
-
$input[0].onbeforedeactivate = null;
|
1371
|
-
};
|
1372
|
-
}
|
1373
|
-
$e.preventDefault();
|
1374
|
-
});
|
1430
|
+
this._setLanguageDirection();
|
1375
1431
|
}
|
1376
1432
|
_.mixin(Typeahead.prototype, {
|
1377
1433
|
_onSuggestionClicked: function onSuggestionClicked(type, $el) {
|
@@ -1382,7 +1438,6 @@
|
|
1382
1438
|
},
|
1383
1439
|
_onCursorMoved: function onCursorMoved() {
|
1384
1440
|
var datum = this.dropdown.getDatumForCursor();
|
1385
|
-
this.input.clearHint();
|
1386
1441
|
this.input.setInputValue(datum.value, true);
|
1387
1442
|
this.eventBus.trigger("cursorchanged", datum.raw, datum.datasetName);
|
1388
1443
|
},
|
@@ -1402,10 +1457,12 @@
|
|
1402
1457
|
this.eventBus.trigger("closed");
|
1403
1458
|
},
|
1404
1459
|
_onFocused: function onFocused() {
|
1405
|
-
this.
|
1460
|
+
this.isActivated = true;
|
1406
1461
|
this.dropdown.open();
|
1407
1462
|
},
|
1408
1463
|
_onBlurred: function onBlurred() {
|
1464
|
+
this.isActivated = false;
|
1465
|
+
this.dropdown.empty();
|
1409
1466
|
this.dropdown.close();
|
1410
1467
|
},
|
1411
1468
|
_onEnterKeyed: function onEnterKeyed(type, $e) {
|
@@ -1426,7 +1483,7 @@
|
|
1426
1483
|
this._select(datum);
|
1427
1484
|
$e.preventDefault();
|
1428
1485
|
} else {
|
1429
|
-
this._autocomplete();
|
1486
|
+
this._autocomplete(true);
|
1430
1487
|
}
|
1431
1488
|
},
|
1432
1489
|
_onEscKeyed: function onEscKeyed() {
|
@@ -1435,19 +1492,13 @@
|
|
1435
1492
|
},
|
1436
1493
|
_onUpKeyed: function onUpKeyed() {
|
1437
1494
|
var query = this.input.getQuery();
|
1438
|
-
|
1439
|
-
this.dropdown.update(query);
|
1440
|
-
}
|
1495
|
+
this.dropdown.isEmpty && query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.moveCursorUp();
|
1441
1496
|
this.dropdown.open();
|
1442
|
-
this.dropdown.moveCursorUp();
|
1443
1497
|
},
|
1444
1498
|
_onDownKeyed: function onDownKeyed() {
|
1445
1499
|
var query = this.input.getQuery();
|
1446
|
-
|
1447
|
-
this.dropdown.update(query);
|
1448
|
-
}
|
1500
|
+
this.dropdown.isEmpty && query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.moveCursorDown();
|
1449
1501
|
this.dropdown.open();
|
1450
|
-
this.dropdown.moveCursorDown();
|
1451
1502
|
},
|
1452
1503
|
_onLeftKeyed: function onLeftKeyed() {
|
1453
1504
|
this.dir === "rtl" && this._autocomplete();
|
@@ -1456,9 +1507,8 @@
|
|
1456
1507
|
this.dir === "ltr" && this._autocomplete();
|
1457
1508
|
},
|
1458
1509
|
_onQueryChanged: function onQueryChanged(e, query) {
|
1459
|
-
this.input.
|
1460
|
-
this.dropdown.empty();
|
1461
|
-
query.length >= this.minLength && this.dropdown.update(query);
|
1510
|
+
this.input.clearHintIfInvalid();
|
1511
|
+
query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.empty();
|
1462
1512
|
this.dropdown.open();
|
1463
1513
|
this._setLanguageDirection();
|
1464
1514
|
},
|
@@ -1475,29 +1525,31 @@
|
|
1475
1525
|
}
|
1476
1526
|
},
|
1477
1527
|
_updateHint: function updateHint() {
|
1478
|
-
var datum,
|
1528
|
+
var datum, val, query, escapedQuery, frontMatchRegEx, match;
|
1479
1529
|
datum = this.dropdown.getDatumForTopSuggestion();
|
1480
1530
|
if (datum && this.dropdown.isVisible() && !this.input.hasOverflow()) {
|
1481
|
-
|
1482
|
-
query = Input.normalizeQuery(
|
1531
|
+
val = this.input.getInputValue();
|
1532
|
+
query = Input.normalizeQuery(val);
|
1483
1533
|
escapedQuery = _.escapeRegExChars(query);
|
1484
|
-
frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(
|
1534
|
+
frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i");
|
1485
1535
|
match = frontMatchRegEx.exec(datum.value);
|
1486
|
-
this.input.
|
1536
|
+
match ? this.input.setHint(val + match[1]) : this.input.clearHint();
|
1537
|
+
} else {
|
1538
|
+
this.input.clearHint();
|
1487
1539
|
}
|
1488
1540
|
},
|
1489
|
-
_autocomplete: function autocomplete() {
|
1490
|
-
var hint, query, datum;
|
1491
|
-
hint = this.input.
|
1541
|
+
_autocomplete: function autocomplete(laxCursor) {
|
1542
|
+
var hint, query, isCursorAtEnd, datum;
|
1543
|
+
hint = this.input.getHint();
|
1492
1544
|
query = this.input.getQuery();
|
1493
|
-
|
1545
|
+
isCursorAtEnd = laxCursor || this.input.isCursorAtEnd();
|
1546
|
+
if (hint && query !== hint && isCursorAtEnd) {
|
1494
1547
|
datum = this.dropdown.getDatumForTopSuggestion();
|
1495
1548
|
datum && this.input.setInputValue(datum.value);
|
1496
1549
|
this.eventBus.trigger("autocompleted", datum.raw, datum.datasetName);
|
1497
1550
|
}
|
1498
1551
|
},
|
1499
1552
|
_select: function select(datum) {
|
1500
|
-
this.input.clearHint();
|
1501
1553
|
this.input.setQuery(datum.value);
|
1502
1554
|
this.input.setInputValue(datum.value, true);
|
1503
1555
|
this._setLanguageDirection();
|
@@ -1511,11 +1563,17 @@
|
|
1511
1563
|
close: function close() {
|
1512
1564
|
this.dropdown.close();
|
1513
1565
|
},
|
1514
|
-
|
1515
|
-
|
1566
|
+
setVal: function setVal(val) {
|
1567
|
+
if (this.isActivated) {
|
1568
|
+
this.input.setInputValue(val);
|
1569
|
+
} else {
|
1570
|
+
this.input.setQuery(val);
|
1571
|
+
this.input.setInputValue(val, true);
|
1572
|
+
}
|
1573
|
+
this._setLanguageDirection();
|
1516
1574
|
},
|
1517
|
-
|
1518
|
-
this.input.
|
1575
|
+
getVal: function getVal() {
|
1576
|
+
return this.input.getQuery();
|
1519
1577
|
},
|
1520
1578
|
destroy: function destroy() {
|
1521
1579
|
this.input.destroy();
|
@@ -1617,17 +1675,17 @@
|
|
1617
1675
|
}
|
1618
1676
|
},
|
1619
1677
|
val: function val(newVal) {
|
1620
|
-
return !arguments.length ?
|
1621
|
-
function
|
1678
|
+
return !arguments.length ? getVal(this.first()) : this.each(setVal);
|
1679
|
+
function setVal() {
|
1622
1680
|
var $input = $(this), typeahead;
|
1623
1681
|
if (typeahead = $input.data(typeaheadKey)) {
|
1624
|
-
typeahead.
|
1682
|
+
typeahead.setVal(newVal);
|
1625
1683
|
}
|
1626
1684
|
}
|
1627
|
-
function
|
1685
|
+
function getVal($input) {
|
1628
1686
|
var typeahead, query;
|
1629
1687
|
if (typeahead = $input.data(typeaheadKey)) {
|
1630
|
-
query = typeahead.
|
1688
|
+
query = typeahead.getVal();
|
1631
1689
|
}
|
1632
1690
|
return query;
|
1633
1691
|
}
|