twitter-typeahead-rails 0.10.5 → 0.11.1.pre.corejavascript
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/README.md +3 -4
- data/lib/twitter-typeahead-rails/version.rb +1 -1
- data/vendor/assets/javascripts/twitter/typeahead.js +0 -2
- data/vendor/assets/javascripts/twitter/typeahead.min.js +0 -2
- data/vendor/assets/javascripts/twitter/typeahead/bloodhound.js +480 -279
- data/vendor/assets/javascripts/twitter/typeahead/bloodhound.min.js +7 -0
- data/vendor/assets/javascripts/twitter/typeahead/typeahead.bundle.js +1538 -858
- data/vendor/assets/javascripts/twitter/typeahead/typeahead.bundle.min.js +4 -3
- data/vendor/assets/javascripts/twitter/typeahead/typeahead.jquery.js +895 -540
- data/vendor/assets/javascripts/twitter/typeahead/typeahead.jquery.min.js +7 -0
- metadata +17 -16
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
MmQ3ZDUzNTQ3ODU3NWU4Njg1ZDY4ZmMzZDE1NDI0YjEwMjg3NjYwNA==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ef1c9d7c03cb7ceb3422f9da077080ca20504e66
|
4
|
+
data.tar.gz: 4574d3cb280a3fd7fa8ddb7ac24c9b7ba0b3db2c
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
YTgzNTA5YjI1OWMyNThhZTZmZTQ4ODZlNTEzOTUxY2I4ODhlZGFmMGViNGQ1
|
11
|
-
NTU0MDJiYjhkYWI0ODQ4YTg4MzNhNDg4ZWJjNWJhYTliMDU1YTY=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
NGFhNTRhNjViNGYxZGI1ZjBiOWE2YWU0NjIxNWE4ZDAyNmViZjcxZTg4NWEy
|
14
|
-
NWEyMWI3ZTM2MDZhYzY5YThjOTBjMjczYmYzODUzYTQ4OTFhYzczNGUyZmJk
|
15
|
-
MzgwYWJmMTExMjU1MjRkY2U4ZTA2M2M5MjQ4NTczMmJlNWE4ZGQ=
|
6
|
+
metadata.gz: ba47f2ede69b1d391e9d247d216f6ddf8563a6dad88968eef7e0b58b03dfb1c015033661153d18d3d7d497ce171e9f9525040b44ff0c098ec1d53d57a64fb9d7
|
7
|
+
data.tar.gz: 0d97243cd0557b7a1d39ca6e60e36cb26eb0b1c5bc11c07055423eeb67cc6eb663f6769e64374a7f82d259c80a6799d4d80619c1bcc4f9fb63567487242ac2b0
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Twitter typeahead.js jquery plugin
|
2
2
|
|
3
|
-
This asset gem packages the [twitter typeahead.js](https://github.com/
|
3
|
+
This asset gem packages the [mantained twitter typeahead.js](https://github.com/corejavascript/typeahead.js) jquery plugin for the Rails asset pipeline.
|
4
4
|
|
5
5
|
To learn more about typeahead.js read the post [Twitter's engineering blog](http://engineering.twitter.com/2013/02/twitter-typeaheadjs-you-autocomplete-me.html).
|
6
6
|
|
@@ -42,7 +42,7 @@ Add one of the following to your application.js manifest:
|
|
42
42
|
|
43
43
|
```js
|
44
44
|
|
45
|
-
// Twitter typeahead
|
45
|
+
// Twitter typeahead example.
|
46
46
|
|
47
47
|
// instantiate the bloodhound suggestion engine
|
48
48
|
var numbers = new Bloodhound({
|
@@ -72,7 +72,7 @@ $('.example-numbers .typeahead').typeahead(null, {
|
|
72
72
|
});
|
73
73
|
```
|
74
74
|
|
75
|
-
Currently this version tracks version v0.
|
75
|
+
Currently this version tracks version v0.11.1.
|
76
76
|
|
77
77
|
## Contributing
|
78
78
|
|
@@ -81,4 +81,3 @@ Currently this version tracks version v0.10.5.
|
|
81
81
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
82
82
|
4. Push to the branch (`git push origin my-new-feature`)
|
83
83
|
5. Create new Pull Request
|
84
|
-
|
@@ -1,10 +1,20 @@
|
|
1
1
|
/*!
|
2
|
-
* typeahead.js 0.
|
2
|
+
* typeahead.js 0.11.1
|
3
3
|
* https://github.com/twitter/typeahead.js
|
4
|
-
* Copyright 2013-
|
4
|
+
* Copyright 2013-2015 Twitter, Inc. and other contributors; Licensed MIT
|
5
5
|
*/
|
6
6
|
|
7
|
-
(function(
|
7
|
+
(function(root, factory) {
|
8
|
+
if (typeof define === "function" && define.amd) {
|
9
|
+
define([ "jquery" ], function(a0) {
|
10
|
+
return root["Bloodhound"] = factory(a0);
|
11
|
+
});
|
12
|
+
} else if (typeof exports === "object") {
|
13
|
+
module.exports = factory(require("jquery"));
|
14
|
+
} else {
|
15
|
+
root["Bloodhound"] = factory(jQuery);
|
16
|
+
}
|
17
|
+
})(this, function($) {
|
8
18
|
var _ = function() {
|
9
19
|
"use strict";
|
10
20
|
return {
|
@@ -29,6 +39,12 @@
|
|
29
39
|
isUndefined: function(obj) {
|
30
40
|
return typeof obj === "undefined";
|
31
41
|
},
|
42
|
+
isElement: function(obj) {
|
43
|
+
return !!(obj && obj.nodeType === 1);
|
44
|
+
},
|
45
|
+
isJQuery: function(obj) {
|
46
|
+
return obj instanceof $;
|
47
|
+
},
|
32
48
|
toStr: function toStr(s) {
|
33
49
|
return _.isUndefined(s) || s === null ? "" : s + "";
|
34
50
|
},
|
@@ -66,12 +82,18 @@
|
|
66
82
|
return !!result;
|
67
83
|
},
|
68
84
|
mixin: $.extend,
|
69
|
-
|
85
|
+
identity: function(x) {
|
86
|
+
return x;
|
87
|
+
},
|
88
|
+
clone: function(obj) {
|
89
|
+
return $.extend(true, {}, obj);
|
90
|
+
},
|
91
|
+
getIdGenerator: function() {
|
70
92
|
var counter = 0;
|
71
93
|
return function() {
|
72
94
|
return counter++;
|
73
95
|
};
|
74
|
-
}
|
96
|
+
},
|
75
97
|
templatify: function templatify(obj) {
|
76
98
|
return $.isFunction(obj) ? obj : template;
|
77
99
|
function template() {
|
@@ -123,10 +145,13 @@
|
|
123
145
|
return result;
|
124
146
|
};
|
125
147
|
},
|
148
|
+
stringify: function(val) {
|
149
|
+
return _.isString(val) ? val : JSON.stringify(val);
|
150
|
+
},
|
126
151
|
noop: function() {}
|
127
152
|
};
|
128
153
|
}();
|
129
|
-
var VERSION = "0.
|
154
|
+
var VERSION = "0.11.1";
|
130
155
|
var tokenizers = function() {
|
131
156
|
"use strict";
|
132
157
|
return {
|
@@ -146,11 +171,11 @@
|
|
146
171
|
return str ? str.split(/\W+/) : [];
|
147
172
|
}
|
148
173
|
function getObjTokenizer(tokenizer) {
|
149
|
-
return function setKey() {
|
150
|
-
|
174
|
+
return function setKey(keys) {
|
175
|
+
keys = _.isArray(keys) ? keys : [].slice.call(arguments, 0);
|
151
176
|
return function tokenize(o) {
|
152
177
|
var tokens = [];
|
153
|
-
_.each(
|
178
|
+
_.each(keys, function(k) {
|
154
179
|
tokens = tokens.concat(tokenizer(_.toStr(o[k])));
|
155
180
|
});
|
156
181
|
return tokens;
|
@@ -173,6 +198,7 @@
|
|
173
198
|
if (this.size >= this.maxSize) {
|
174
199
|
this.list.remove(tailItem);
|
175
200
|
delete this.hash[tailItem.key];
|
201
|
+
this.size--;
|
176
202
|
}
|
177
203
|
if (node = this.hash[key]) {
|
178
204
|
node.val = val;
|
@@ -227,73 +253,72 @@
|
|
227
253
|
}();
|
228
254
|
var PersistentStorage = function() {
|
229
255
|
"use strict";
|
230
|
-
var
|
256
|
+
var LOCAL_STORAGE;
|
231
257
|
try {
|
232
|
-
|
233
|
-
|
234
|
-
|
258
|
+
LOCAL_STORAGE = window.localStorage;
|
259
|
+
LOCAL_STORAGE.setItem("~~~", "!");
|
260
|
+
LOCAL_STORAGE.removeItem("~~~");
|
235
261
|
} catch (err) {
|
236
|
-
|
262
|
+
LOCAL_STORAGE = null;
|
237
263
|
}
|
238
|
-
function PersistentStorage(namespace) {
|
264
|
+
function PersistentStorage(namespace, override) {
|
239
265
|
this.prefix = [ "__", namespace, "__" ].join("");
|
240
266
|
this.ttlKey = "__ttl__";
|
241
267
|
this.keyMatcher = new RegExp("^" + _.escapeRegExChars(this.prefix));
|
268
|
+
this.ls = override || LOCAL_STORAGE;
|
269
|
+
!this.ls && this._noop();
|
242
270
|
}
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
get
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
}
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
} else {
|
261
|
-
ls.removeItem(this._ttlKey(key));
|
262
|
-
}
|
263
|
-
return ls.setItem(this._prefix(key), encode(val));
|
264
|
-
},
|
265
|
-
remove: function(key) {
|
266
|
-
ls.removeItem(this._ttlKey(key));
|
267
|
-
ls.removeItem(this._prefix(key));
|
268
|
-
return this;
|
269
|
-
},
|
270
|
-
clear: function() {
|
271
|
-
var i, key, keys = [], len = ls.length;
|
272
|
-
for (i = 0; i < len; i++) {
|
273
|
-
if ((key = ls.key(i)).match(this.keyMatcher)) {
|
274
|
-
keys.push(key.replace(this.keyMatcher, ""));
|
275
|
-
}
|
276
|
-
}
|
277
|
-
for (i = keys.length; i--; ) {
|
278
|
-
this.remove(keys[i]);
|
271
|
+
_.mixin(PersistentStorage.prototype, {
|
272
|
+
_prefix: function(key) {
|
273
|
+
return this.prefix + key;
|
274
|
+
},
|
275
|
+
_ttlKey: function(key) {
|
276
|
+
return this._prefix(key) + this.ttlKey;
|
277
|
+
},
|
278
|
+
_noop: function() {
|
279
|
+
this.get = this.set = this.remove = this.clear = this.isExpired = _.noop;
|
280
|
+
},
|
281
|
+
_safeSet: function(key, val) {
|
282
|
+
try {
|
283
|
+
this.ls.setItem(key, val);
|
284
|
+
} catch (err) {
|
285
|
+
if (err.name === "QuotaExceededError") {
|
286
|
+
this.clear();
|
287
|
+
this._noop();
|
279
288
|
}
|
280
|
-
return this;
|
281
|
-
},
|
282
|
-
isExpired: function(key) {
|
283
|
-
var ttl = decode(ls.getItem(this._ttlKey(key)));
|
284
|
-
return _.isNumber(ttl) && now() > ttl ? true : false;
|
285
289
|
}
|
286
|
-
}
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
290
|
+
},
|
291
|
+
get: function(key) {
|
292
|
+
if (this.isExpired(key)) {
|
293
|
+
this.remove(key);
|
294
|
+
}
|
295
|
+
return decode(this.ls.getItem(this._prefix(key)));
|
296
|
+
},
|
297
|
+
set: function(key, val, ttl) {
|
298
|
+
if (_.isNumber(ttl)) {
|
299
|
+
this._safeSet(this._ttlKey(key), encode(now() + ttl));
|
300
|
+
} else {
|
301
|
+
this.ls.removeItem(this._ttlKey(key));
|
302
|
+
}
|
303
|
+
return this._safeSet(this._prefix(key), encode(val));
|
304
|
+
},
|
305
|
+
remove: function(key) {
|
306
|
+
this.ls.removeItem(this._ttlKey(key));
|
307
|
+
this.ls.removeItem(this._prefix(key));
|
308
|
+
return this;
|
309
|
+
},
|
310
|
+
clear: function() {
|
311
|
+
var i, keys = gatherMatchingKeys(this.keyMatcher);
|
312
|
+
for (i = keys.length; i--; ) {
|
313
|
+
this.remove(keys[i]);
|
314
|
+
}
|
315
|
+
return this;
|
316
|
+
},
|
317
|
+
isExpired: function(key) {
|
318
|
+
var ttl = decode(this.ls.getItem(this._ttlKey(key)));
|
319
|
+
return _.isNumber(ttl) && now() > ttl ? true : false;
|
320
|
+
}
|
321
|
+
});
|
297
322
|
return PersistentStorage;
|
298
323
|
function now() {
|
299
324
|
return new Date().getTime();
|
@@ -302,7 +327,16 @@
|
|
302
327
|
return JSON.stringify(_.isUndefined(val) ? null : val);
|
303
328
|
}
|
304
329
|
function decode(val) {
|
305
|
-
return
|
330
|
+
return $.parseJSON(val);
|
331
|
+
}
|
332
|
+
function gatherMatchingKeys(keyMatcher) {
|
333
|
+
var i, key, keys = [], len = LOCAL_STORAGE.length;
|
334
|
+
for (i = 0; i < len; i++) {
|
335
|
+
if ((key = LOCAL_STORAGE.key(i)).match(keyMatcher)) {
|
336
|
+
keys.push(key.replace(keyMatcher, ""));
|
337
|
+
}
|
338
|
+
}
|
339
|
+
return keys;
|
306
340
|
}
|
307
341
|
}();
|
308
342
|
var Transport = function() {
|
@@ -311,9 +345,9 @@
|
|
311
345
|
function Transport(o) {
|
312
346
|
o = o || {};
|
313
347
|
this.cancelled = false;
|
314
|
-
this.
|
315
|
-
this._send = o.transport
|
316
|
-
this._get = o.
|
348
|
+
this.lastReq = null;
|
349
|
+
this._send = o.transport;
|
350
|
+
this._get = o.limiter ? o.limiter(this._get) : this._get;
|
317
351
|
this._cache = o.cache === false ? new LruCache(0) : sharedCache;
|
318
352
|
}
|
319
353
|
Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {
|
@@ -323,84 +357,73 @@
|
|
323
357
|
sharedCache.reset();
|
324
358
|
};
|
325
359
|
_.mixin(Transport.prototype, {
|
326
|
-
|
327
|
-
|
328
|
-
|
360
|
+
_fingerprint: function fingerprint(o) {
|
361
|
+
o = o || {};
|
362
|
+
return o.url + o.type + $.param(o.data || {});
|
363
|
+
},
|
364
|
+
_get: function(o, cb) {
|
365
|
+
var that = this, fingerprint, jqXhr;
|
366
|
+
fingerprint = this._fingerprint(o);
|
367
|
+
if (this.cancelled || fingerprint !== this.lastReq) {
|
329
368
|
return;
|
330
369
|
}
|
331
|
-
if (jqXhr = pendingRequests[
|
370
|
+
if (jqXhr = pendingRequests[fingerprint]) {
|
332
371
|
jqXhr.done(done).fail(fail);
|
333
372
|
} else if (pendingRequestsCount < maxPendingRequests) {
|
334
373
|
pendingRequestsCount++;
|
335
|
-
pendingRequests[
|
374
|
+
pendingRequests[fingerprint] = this._send(o).done(done).fail(fail).always(always);
|
336
375
|
} else {
|
337
376
|
this.onDeckRequestArgs = [].slice.call(arguments, 0);
|
338
377
|
}
|
339
378
|
function done(resp) {
|
340
|
-
cb
|
341
|
-
that._cache.set(
|
379
|
+
cb(null, resp);
|
380
|
+
that._cache.set(fingerprint, resp);
|
342
381
|
}
|
343
382
|
function fail() {
|
344
|
-
cb
|
383
|
+
cb(true);
|
345
384
|
}
|
346
385
|
function always() {
|
347
386
|
pendingRequestsCount--;
|
348
|
-
delete pendingRequests[
|
387
|
+
delete pendingRequests[fingerprint];
|
349
388
|
if (that.onDeckRequestArgs) {
|
350
389
|
that._get.apply(that, that.onDeckRequestArgs);
|
351
390
|
that.onDeckRequestArgs = null;
|
352
391
|
}
|
353
392
|
}
|
354
393
|
},
|
355
|
-
get: function(
|
356
|
-
var resp;
|
357
|
-
|
358
|
-
|
359
|
-
o
|
360
|
-
}
|
394
|
+
get: function(o, cb) {
|
395
|
+
var resp, fingerprint;
|
396
|
+
cb = cb || $.noop;
|
397
|
+
o = _.isString(o) ? {
|
398
|
+
url: o
|
399
|
+
} : o || {};
|
400
|
+
fingerprint = this._fingerprint(o);
|
361
401
|
this.cancelled = false;
|
362
|
-
this.
|
363
|
-
if (resp = this._cache.get(
|
364
|
-
|
365
|
-
cb && cb(null, resp);
|
366
|
-
});
|
402
|
+
this.lastReq = fingerprint;
|
403
|
+
if (resp = this._cache.get(fingerprint)) {
|
404
|
+
cb(null, resp);
|
367
405
|
} else {
|
368
|
-
this._get(
|
406
|
+
this._get(o, cb);
|
369
407
|
}
|
370
|
-
return !!resp;
|
371
408
|
},
|
372
409
|
cancel: function() {
|
373
410
|
this.cancelled = true;
|
374
411
|
}
|
375
412
|
});
|
376
413
|
return Transport;
|
377
|
-
function callbackToDeferred(fn) {
|
378
|
-
return function customSendWrapper(url, o) {
|
379
|
-
var deferred = $.Deferred();
|
380
|
-
fn(url, o, onSuccess, onError);
|
381
|
-
return deferred;
|
382
|
-
function onSuccess(resp) {
|
383
|
-
_.defer(function() {
|
384
|
-
deferred.resolve(resp);
|
385
|
-
});
|
386
|
-
}
|
387
|
-
function onError(err) {
|
388
|
-
_.defer(function() {
|
389
|
-
deferred.reject(err);
|
390
|
-
});
|
391
|
-
}
|
392
|
-
};
|
393
|
-
}
|
394
414
|
}();
|
395
|
-
var SearchIndex = function() {
|
415
|
+
var SearchIndex = window.SearchIndex = function() {
|
396
416
|
"use strict";
|
417
|
+
var CHILDREN = "c", IDS = "i";
|
397
418
|
function SearchIndex(o) {
|
398
419
|
o = o || {};
|
399
420
|
if (!o.datumTokenizer || !o.queryTokenizer) {
|
400
421
|
$.error("datumTokenizer and queryTokenizer are both required");
|
401
422
|
}
|
423
|
+
this.identify = o.identify || _.stringify;
|
402
424
|
this.datumTokenizer = o.datumTokenizer;
|
403
425
|
this.queryTokenizer = o.queryTokenizer;
|
426
|
+
this.matchAnyQueryToken = o.matchAnyQueryToken;
|
404
427
|
this.reset();
|
405
428
|
}
|
406
429
|
_.mixin(SearchIndex.prototype, {
|
@@ -413,46 +436,61 @@
|
|
413
436
|
data = _.isArray(data) ? data : [ data ];
|
414
437
|
_.each(data, function(datum) {
|
415
438
|
var id, tokens;
|
416
|
-
id = that.
|
439
|
+
that.datums[id = that.identify(datum)] = datum;
|
417
440
|
tokens = normalizeTokens(that.datumTokenizer(datum));
|
418
441
|
_.each(tokens, function(token) {
|
419
442
|
var node, chars, ch;
|
420
443
|
node = that.trie;
|
421
444
|
chars = token.split("");
|
422
445
|
while (ch = chars.shift()) {
|
423
|
-
node = node
|
424
|
-
node.
|
446
|
+
node = node[CHILDREN][ch] || (node[CHILDREN][ch] = newNode());
|
447
|
+
node[IDS].push(id);
|
425
448
|
}
|
426
449
|
});
|
427
450
|
});
|
428
451
|
},
|
429
|
-
get: function get(
|
452
|
+
get: function get(ids) {
|
453
|
+
var that = this;
|
454
|
+
return _.map(ids, function(id) {
|
455
|
+
return that.datums[id];
|
456
|
+
});
|
457
|
+
},
|
458
|
+
search: function search(query) {
|
430
459
|
var that = this, tokens, matches;
|
431
460
|
tokens = normalizeTokens(this.queryTokenizer(query));
|
432
461
|
_.each(tokens, function(token) {
|
433
462
|
var node, chars, ch, ids;
|
434
|
-
if (matches && matches.length === 0) {
|
463
|
+
if (matches && matches.length === 0 && !that.matchAnyQueryToken) {
|
435
464
|
return false;
|
436
465
|
}
|
437
466
|
node = that.trie;
|
438
467
|
chars = token.split("");
|
439
468
|
while (node && (ch = chars.shift())) {
|
440
|
-
node = node
|
469
|
+
node = node[CHILDREN][ch];
|
441
470
|
}
|
442
471
|
if (node && chars.length === 0) {
|
443
|
-
ids = node.
|
472
|
+
ids = node[IDS].slice(0);
|
444
473
|
matches = matches ? getIntersection(matches, ids) : ids;
|
445
474
|
} else {
|
446
|
-
|
447
|
-
|
475
|
+
if (!that.matchAnyQueryToken) {
|
476
|
+
matches = [];
|
477
|
+
return false;
|
478
|
+
}
|
448
479
|
}
|
449
480
|
});
|
450
481
|
return matches ? _.map(unique(matches), function(id) {
|
451
482
|
return that.datums[id];
|
452
483
|
}) : [];
|
453
484
|
},
|
485
|
+
all: function all() {
|
486
|
+
var values = [];
|
487
|
+
for (var key in this.datums) {
|
488
|
+
values.push(this.datums[key]);
|
489
|
+
}
|
490
|
+
return values;
|
491
|
+
},
|
454
492
|
reset: function reset() {
|
455
|
-
this.datums =
|
493
|
+
this.datums = {};
|
456
494
|
this.trie = newNode();
|
457
495
|
},
|
458
496
|
serialize: function serialize() {
|
@@ -473,10 +511,10 @@
|
|
473
511
|
return tokens;
|
474
512
|
}
|
475
513
|
function newNode() {
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
514
|
+
var node = {};
|
515
|
+
node[IDS] = [];
|
516
|
+
node[CHILDREN] = {};
|
517
|
+
return node;
|
480
518
|
}
|
481
519
|
function unique(array) {
|
482
520
|
var seen = {}, uniques = [];
|
@@ -490,8 +528,8 @@
|
|
490
528
|
}
|
491
529
|
function getIntersection(arrayA, arrayB) {
|
492
530
|
var ai = 0, bi = 0, intersection = [];
|
493
|
-
arrayA = arrayA.sort(
|
494
|
-
arrayB = arrayB.sort(
|
531
|
+
arrayA = arrayA.sort();
|
532
|
+
arrayB = arrayB.sort();
|
495
533
|
var lenArrayA = arrayA.length, lenArrayB = arrayB.length;
|
496
534
|
while (ai < lenArrayA && bi < lenArrayB) {
|
497
535
|
if (arrayA[ai] < arrayB[bi]) {
|
@@ -505,169 +543,330 @@
|
|
505
543
|
}
|
506
544
|
}
|
507
545
|
return intersection;
|
508
|
-
|
509
|
-
|
546
|
+
}
|
547
|
+
}();
|
548
|
+
var Prefetch = function() {
|
549
|
+
"use strict";
|
550
|
+
var keys;
|
551
|
+
keys = {
|
552
|
+
data: "data",
|
553
|
+
protocol: "protocol",
|
554
|
+
thumbprint: "thumbprint"
|
555
|
+
};
|
556
|
+
function Prefetch(o) {
|
557
|
+
this.url = o.url;
|
558
|
+
this.ttl = o.ttl;
|
559
|
+
this.cache = o.cache;
|
560
|
+
this.prepare = o.prepare;
|
561
|
+
this.transform = o.transform;
|
562
|
+
this.transport = o.transport;
|
563
|
+
this.thumbprint = o.thumbprint;
|
564
|
+
this.storage = new PersistentStorage(o.cacheKey);
|
565
|
+
}
|
566
|
+
_.mixin(Prefetch.prototype, {
|
567
|
+
_settings: function settings() {
|
568
|
+
return {
|
569
|
+
url: this.url,
|
570
|
+
type: "GET",
|
571
|
+
dataType: "json"
|
572
|
+
};
|
573
|
+
},
|
574
|
+
store: function store(data) {
|
575
|
+
if (!this.cache) {
|
576
|
+
return;
|
577
|
+
}
|
578
|
+
this.storage.set(keys.data, data, this.ttl);
|
579
|
+
this.storage.set(keys.protocol, location.protocol, this.ttl);
|
580
|
+
this.storage.set(keys.thumbprint, this.thumbprint, this.ttl);
|
581
|
+
},
|
582
|
+
fromCache: function fromCache() {
|
583
|
+
var stored = {}, isExpired;
|
584
|
+
if (!this.cache) {
|
585
|
+
return null;
|
586
|
+
}
|
587
|
+
stored.data = this.storage.get(keys.data);
|
588
|
+
stored.protocol = this.storage.get(keys.protocol);
|
589
|
+
stored.thumbprint = this.storage.get(keys.thumbprint);
|
590
|
+
isExpired = stored.thumbprint !== this.thumbprint || stored.protocol !== location.protocol;
|
591
|
+
return stored.data && !isExpired ? stored.data : null;
|
592
|
+
},
|
593
|
+
fromNetwork: function(cb) {
|
594
|
+
var that = this, settings;
|
595
|
+
if (!cb) {
|
596
|
+
return;
|
597
|
+
}
|
598
|
+
settings = this.prepare(this._settings());
|
599
|
+
this.transport(settings).fail(onError).done(onResponse);
|
600
|
+
function onError() {
|
601
|
+
cb(true);
|
602
|
+
}
|
603
|
+
function onResponse(resp) {
|
604
|
+
cb(null, that.transform(resp));
|
605
|
+
}
|
606
|
+
},
|
607
|
+
clear: function clear() {
|
608
|
+
this.storage.clear();
|
609
|
+
return this;
|
510
610
|
}
|
611
|
+
});
|
612
|
+
return Prefetch;
|
613
|
+
}();
|
614
|
+
var Remote = function() {
|
615
|
+
"use strict";
|
616
|
+
function Remote(o) {
|
617
|
+
this.url = o.url;
|
618
|
+
this.prepare = o.prepare;
|
619
|
+
this.transform = o.transform;
|
620
|
+
this.indexResponse = o.indexResponse;
|
621
|
+
this.transport = new Transport({
|
622
|
+
cache: o.cache,
|
623
|
+
limiter: o.limiter,
|
624
|
+
transport: o.transport
|
625
|
+
});
|
511
626
|
}
|
627
|
+
_.mixin(Remote.prototype, {
|
628
|
+
_settings: function settings() {
|
629
|
+
return {
|
630
|
+
url: this.url,
|
631
|
+
type: "GET",
|
632
|
+
dataType: "json"
|
633
|
+
};
|
634
|
+
},
|
635
|
+
get: function get(query, cb) {
|
636
|
+
var that = this, settings;
|
637
|
+
if (!cb) {
|
638
|
+
return;
|
639
|
+
}
|
640
|
+
query = query || "";
|
641
|
+
settings = this.prepare(query, this._settings());
|
642
|
+
return this.transport.get(settings, onResponse);
|
643
|
+
function onResponse(err, resp) {
|
644
|
+
err ? cb([]) : cb(that.transform(resp));
|
645
|
+
}
|
646
|
+
},
|
647
|
+
cancelLastRequest: function cancelLastRequest() {
|
648
|
+
this.transport.cancel();
|
649
|
+
}
|
650
|
+
});
|
651
|
+
return Remote;
|
512
652
|
}();
|
513
653
|
var oParser = function() {
|
514
654
|
"use strict";
|
515
|
-
return {
|
516
|
-
|
517
|
-
|
518
|
-
|
655
|
+
return function parse(o) {
|
656
|
+
var defaults, sorter;
|
657
|
+
defaults = {
|
658
|
+
initialize: true,
|
659
|
+
identify: _.stringify,
|
660
|
+
datumTokenizer: null,
|
661
|
+
queryTokenizer: null,
|
662
|
+
matchAnyQueryToken: false,
|
663
|
+
sufficient: 5,
|
664
|
+
indexRemote: false,
|
665
|
+
sorter: null,
|
666
|
+
local: [],
|
667
|
+
prefetch: null,
|
668
|
+
remote: null
|
669
|
+
};
|
670
|
+
o = _.mixin(defaults, o || {});
|
671
|
+
!o.datumTokenizer && $.error("datumTokenizer is required");
|
672
|
+
!o.queryTokenizer && $.error("queryTokenizer is required");
|
673
|
+
sorter = o.sorter;
|
674
|
+
o.sorter = sorter ? function(x) {
|
675
|
+
return x.sort(sorter);
|
676
|
+
} : _.identity;
|
677
|
+
o.local = _.isFunction(o.local) ? o.local() : o.local;
|
678
|
+
o.prefetch = parsePrefetch(o.prefetch);
|
679
|
+
o.remote = parseRemote(o.remote);
|
680
|
+
return o;
|
519
681
|
};
|
520
|
-
function
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
682
|
+
function parsePrefetch(o) {
|
683
|
+
var defaults;
|
684
|
+
if (!o) {
|
685
|
+
return null;
|
686
|
+
}
|
525
687
|
defaults = {
|
526
688
|
url: null,
|
527
|
-
thumbprint: "",
|
528
689
|
ttl: 24 * 60 * 60 * 1e3,
|
529
|
-
|
530
|
-
|
690
|
+
cache: true,
|
691
|
+
cacheKey: null,
|
692
|
+
thumbprint: "",
|
693
|
+
prepare: _.identity,
|
694
|
+
transform: _.identity,
|
695
|
+
transport: null
|
531
696
|
};
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
return prefetch;
|
697
|
+
o = _.isString(o) ? {
|
698
|
+
url: o
|
699
|
+
} : o;
|
700
|
+
o = _.mixin(defaults, o);
|
701
|
+
!o.url && $.error("prefetch requires url to be set");
|
702
|
+
o.transform = o.filter || o.transform;
|
703
|
+
o.cacheKey = o.cacheKey || o.url;
|
704
|
+
o.thumbprint = VERSION + o.thumbprint;
|
705
|
+
o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax;
|
706
|
+
return o;
|
543
707
|
}
|
544
|
-
function
|
545
|
-
var
|
708
|
+
function parseRemote(o) {
|
709
|
+
var defaults;
|
710
|
+
if (!o) {
|
711
|
+
return;
|
712
|
+
}
|
546
713
|
defaults = {
|
547
714
|
url: null,
|
548
715
|
cache: true,
|
549
|
-
|
716
|
+
prepare: null,
|
550
717
|
replace: null,
|
718
|
+
wildcard: null,
|
719
|
+
limiter: null,
|
551
720
|
rateLimitBy: "debounce",
|
552
721
|
rateLimitWait: 300,
|
553
|
-
|
554
|
-
|
555
|
-
ajax: {}
|
722
|
+
transform: _.identity,
|
723
|
+
transport: null
|
556
724
|
};
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
725
|
+
o = _.isString(o) ? {
|
726
|
+
url: o
|
727
|
+
} : o;
|
728
|
+
o = _.mixin(defaults, o);
|
729
|
+
!o.url && $.error("remote requires url to be set");
|
730
|
+
o.transform = o.filter || o.transform;
|
731
|
+
o.prepare = toRemotePrepare(o);
|
732
|
+
o.limiter = toLimiter(o);
|
733
|
+
o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax;
|
734
|
+
delete o.replace;
|
735
|
+
delete o.wildcard;
|
736
|
+
delete o.rateLimitBy;
|
737
|
+
delete o.rateLimitWait;
|
738
|
+
return o;
|
739
|
+
}
|
740
|
+
function toRemotePrepare(o) {
|
741
|
+
var prepare, replace, wildcard;
|
742
|
+
prepare = o.prepare;
|
743
|
+
replace = o.replace;
|
744
|
+
wildcard = o.wildcard;
|
745
|
+
if (prepare) {
|
746
|
+
return prepare;
|
747
|
+
}
|
748
|
+
if (replace) {
|
749
|
+
prepare = prepareByReplace;
|
750
|
+
} else if (o.wildcard) {
|
751
|
+
prepare = prepareByWildcard;
|
752
|
+
} else {
|
753
|
+
prepare = idenityPrepare;
|
754
|
+
}
|
755
|
+
return prepare;
|
756
|
+
function prepareByReplace(query, settings) {
|
757
|
+
settings.url = replace(settings.url, query);
|
758
|
+
return settings;
|
759
|
+
}
|
760
|
+
function prepareByWildcard(query, settings) {
|
761
|
+
settings.url = settings.url.replace(wildcard, encodeURIComponent(query));
|
762
|
+
return settings;
|
568
763
|
}
|
569
|
-
|
570
|
-
|
571
|
-
|
764
|
+
function idenityPrepare(query, settings) {
|
765
|
+
return settings;
|
766
|
+
}
|
767
|
+
}
|
768
|
+
function toLimiter(o) {
|
769
|
+
var limiter, method, wait;
|
770
|
+
limiter = o.limiter;
|
771
|
+
method = o.rateLimitBy;
|
772
|
+
wait = o.rateLimitWait;
|
773
|
+
if (!limiter) {
|
774
|
+
limiter = /^throttle$/i.test(method) ? throttle(wait) : debounce(wait);
|
775
|
+
}
|
776
|
+
return limiter;
|
777
|
+
function debounce(wait) {
|
778
|
+
return function debounce(fn) {
|
572
779
|
return _.debounce(fn, wait);
|
573
780
|
};
|
574
781
|
}
|
575
|
-
function
|
576
|
-
return function(fn) {
|
782
|
+
function throttle(wait) {
|
783
|
+
return function throttle(fn) {
|
577
784
|
return _.throttle(fn, wait);
|
578
785
|
};
|
579
786
|
}
|
580
787
|
}
|
788
|
+
function callbackToDeferred(fn) {
|
789
|
+
return function wrapper(o) {
|
790
|
+
var deferred = $.Deferred();
|
791
|
+
fn(o, onSuccess, onError);
|
792
|
+
return deferred;
|
793
|
+
function onSuccess(resp) {
|
794
|
+
_.defer(function() {
|
795
|
+
deferred.resolve(resp);
|
796
|
+
});
|
797
|
+
}
|
798
|
+
function onError(err) {
|
799
|
+
_.defer(function() {
|
800
|
+
deferred.reject(err);
|
801
|
+
});
|
802
|
+
}
|
803
|
+
};
|
804
|
+
}
|
581
805
|
}();
|
582
|
-
|
806
|
+
var Bloodhound = function() {
|
583
807
|
"use strict";
|
584
|
-
var old
|
585
|
-
old =
|
586
|
-
keys = {
|
587
|
-
data: "data",
|
588
|
-
protocol: "protocol",
|
589
|
-
thumbprint: "thumbprint"
|
590
|
-
};
|
591
|
-
root.Bloodhound = Bloodhound;
|
808
|
+
var old;
|
809
|
+
old = window && window.Bloodhound;
|
592
810
|
function Bloodhound(o) {
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
this.
|
597
|
-
this.
|
598
|
-
this.
|
599
|
-
this.
|
600
|
-
this.prefetch =
|
601
|
-
this.remote = oParser.remote(o);
|
602
|
-
this.cacheKey = this.prefetch ? this.prefetch.cacheKey || this.prefetch.url : null;
|
811
|
+
o = oParser(o);
|
812
|
+
this.sorter = o.sorter;
|
813
|
+
this.identify = o.identify;
|
814
|
+
this.sufficient = o.sufficient;
|
815
|
+
this.indexRemote = o.indexRemote;
|
816
|
+
this.local = o.local;
|
817
|
+
this.remote = o.remote ? new Remote(o.remote) : null;
|
818
|
+
this.prefetch = o.prefetch ? new Prefetch(o.prefetch) : null;
|
603
819
|
this.index = new SearchIndex({
|
820
|
+
identify: this.identify,
|
604
821
|
datumTokenizer: o.datumTokenizer,
|
605
822
|
queryTokenizer: o.queryTokenizer
|
606
823
|
});
|
607
|
-
|
824
|
+
o.initialize !== false && this.initialize();
|
608
825
|
}
|
609
826
|
Bloodhound.noConflict = function noConflict() {
|
610
|
-
|
827
|
+
window && (window.Bloodhound = old);
|
611
828
|
return Bloodhound;
|
612
829
|
};
|
613
830
|
Bloodhound.tokenizers = tokenizers;
|
614
831
|
_.mixin(Bloodhound.prototype, {
|
615
|
-
|
616
|
-
var that = this
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
} else {
|
621
|
-
deferred = $.ajax(o.url, o.ajax).done(handlePrefetchResponse);
|
622
|
-
}
|
623
|
-
return deferred;
|
624
|
-
function handlePrefetchResponse(resp) {
|
625
|
-
that.clear();
|
626
|
-
that.add(o.filter ? o.filter(resp) : resp);
|
627
|
-
that._saveToStorage(that.index.serialize(), o.thumbprint, o.ttl);
|
628
|
-
}
|
629
|
-
},
|
630
|
-
_getFromRemote: function getFromRemote(query, cb) {
|
631
|
-
var that = this, url, uriEncodedQuery;
|
632
|
-
if (!this.transport) {
|
633
|
-
return;
|
832
|
+
__ttAdapter: function ttAdapter() {
|
833
|
+
var that = this;
|
834
|
+
return this.remote ? withAsync : withoutAsync;
|
835
|
+
function withAsync(query, sync, async) {
|
836
|
+
return that.search(query, sync, async);
|
634
837
|
}
|
635
|
-
|
636
|
-
|
637
|
-
url = this.remote.replace ? this.remote.replace(this.remote.url, query) : this.remote.url.replace(this.remote.wildcard, uriEncodedQuery);
|
638
|
-
return this.transport.get(url, this.remote.ajax, handleRemoteResponse);
|
639
|
-
function handleRemoteResponse(err, resp) {
|
640
|
-
err ? cb([]) : cb(that.remote.filter ? that.remote.filter(resp) : resp);
|
838
|
+
function withoutAsync(query, sync) {
|
839
|
+
return that.search(query, sync);
|
641
840
|
}
|
642
841
|
},
|
643
|
-
|
644
|
-
this
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
this.
|
650
|
-
|
842
|
+
_loadPrefetch: function loadPrefetch() {
|
843
|
+
var that = this, deferred, serialized;
|
844
|
+
deferred = $.Deferred();
|
845
|
+
if (!this.prefetch) {
|
846
|
+
deferred.resolve();
|
847
|
+
} else if (serialized = this.prefetch.fromCache()) {
|
848
|
+
this.index.bootstrap(serialized);
|
849
|
+
deferred.resolve();
|
850
|
+
} else {
|
851
|
+
this.prefetch.fromNetwork(done);
|
651
852
|
}
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
853
|
+
return deferred.promise();
|
854
|
+
function done(err, data) {
|
855
|
+
if (err) {
|
856
|
+
return deferred.reject();
|
857
|
+
}
|
858
|
+
that.add(data);
|
859
|
+
that.prefetch.store(that.index.serialize());
|
860
|
+
deferred.resolve();
|
659
861
|
}
|
660
|
-
isExpired = stored.thumbprint !== thumbprint || stored.protocol !== location.protocol;
|
661
|
-
return stored.data && !isExpired ? stored.data : null;
|
662
862
|
},
|
663
863
|
_initialize: function initialize() {
|
664
|
-
var that = this,
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
return this.initPromise = deferred.promise();
|
864
|
+
var that = this, deferred;
|
865
|
+
this.clear();
|
866
|
+
(this.initPromise = this._loadPrefetch()).done(addLocalToIndex);
|
867
|
+
return this.initPromise;
|
669
868
|
function addLocalToIndex() {
|
670
|
-
that.add(
|
869
|
+
that.add(that.local);
|
671
870
|
}
|
672
871
|
},
|
673
872
|
initialize: function initialize(force) {
|
@@ -675,53 +874,55 @@
|
|
675
874
|
},
|
676
875
|
add: function add(data) {
|
677
876
|
this.index.add(data);
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
877
|
+
return this;
|
878
|
+
},
|
879
|
+
get: function get(ids) {
|
880
|
+
ids = _.isArray(ids) ? ids : [].slice.call(arguments);
|
881
|
+
return this.index.get(ids);
|
882
|
+
},
|
883
|
+
search: function search(query, sync, async) {
|
884
|
+
var that = this, local;
|
885
|
+
sync = sync || _.noop;
|
886
|
+
async = async || _.noop;
|
887
|
+
local = this.sorter(this.index.search(query));
|
888
|
+
sync(this.remote ? local.slice() : local);
|
889
|
+
if (this.remote && local.length < this.sufficient) {
|
890
|
+
this.remote.get(query, processRemote);
|
891
|
+
} else if (this.remote) {
|
892
|
+
this.remote.cancelLastRequest();
|
893
|
+
}
|
894
|
+
return this;
|
895
|
+
function processRemote(remote) {
|
896
|
+
var nonDuplicates = [];
|
897
|
+
_.each(remote, function(r) {
|
898
|
+
!_.some(local, function(l) {
|
899
|
+
return that.identify(r) === that.identify(l);
|
900
|
+
}) && nonDuplicates.push(r);
|
696
901
|
});
|
697
|
-
|
902
|
+
that.indexRemote && that.add(nonDuplicates);
|
903
|
+
async(nonDuplicates);
|
698
904
|
}
|
699
905
|
},
|
906
|
+
all: function all() {
|
907
|
+
return this.index.all();
|
908
|
+
},
|
700
909
|
clear: function clear() {
|
701
910
|
this.index.reset();
|
911
|
+
return this;
|
702
912
|
},
|
703
913
|
clearPrefetchCache: function clearPrefetchCache() {
|
704
|
-
this.
|
914
|
+
this.prefetch && this.prefetch.clear();
|
915
|
+
return this;
|
705
916
|
},
|
706
917
|
clearRemoteCache: function clearRemoteCache() {
|
707
|
-
|
918
|
+
Transport.resetCache();
|
919
|
+
return this;
|
708
920
|
},
|
709
921
|
ttAdapter: function ttAdapter() {
|
710
|
-
return
|
922
|
+
return this.__ttAdapter();
|
711
923
|
}
|
712
924
|
});
|
713
925
|
return Bloodhound;
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
return array.sort(sortFn);
|
718
|
-
}
|
719
|
-
function noSort(array) {
|
720
|
-
return array;
|
721
|
-
}
|
722
|
-
}
|
723
|
-
function ignoreDuplicates() {
|
724
|
-
return false;
|
725
|
-
}
|
726
|
-
})(this);
|
727
|
-
})(window.jQuery);
|
926
|
+
}();
|
927
|
+
return Bloodhound;
|
928
|
+
});
|