flashgrid-ext 1.0.4 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +0 -1
- data/lib/flashgrid/ext/version.rb +1 -1
- data/vendor/assets/javascripts/typeahead.js +364 -1120
- data/vendor/assets/stylesheets/typeahead.css.scss +2 -35
- metadata +3 -4
- data/vendor/assets/javascripts/typeahead_search.js +0 -645
@@ -4,38 +4,5 @@
|
|
4
4
|
|
5
5
|
/* #Typeahead
|
6
6
|
================================================== */
|
7
|
-
.typeahead
|
8
|
-
.typeahead
|
9
|
-
background-clip: padding-box;
|
10
|
-
background-color: rgba(246,247,249,1);
|
11
|
-
border-radius: 3px;
|
12
|
-
box-shadow: 0 1px 3px rgba(0,0,0,0.3);
|
13
|
-
color: rgba(71,74,84,1);
|
14
|
-
display: none;
|
15
|
-
float: left;
|
16
|
-
list-style: none;
|
17
|
-
margin: 2px 0 0;
|
18
|
-
min-width: 160px;
|
19
|
-
padding: 5px 0;
|
20
|
-
position: absolute;
|
21
|
-
top: 100%;
|
22
|
-
z-index: 1000;
|
23
|
-
}
|
24
|
-
.typeahead-suggestion {
|
25
|
-
clear: both;
|
26
|
-
color: rgba(71,74,84,1);
|
27
|
-
display: block;
|
28
|
-
font-size: 12px;
|
29
|
-
font-weight: bold;
|
30
|
-
line-height: 20px;
|
31
|
-
padding: 5px 15px;
|
32
|
-
text-decoration: none;
|
33
|
-
white-space: nowrap;
|
34
|
-
}
|
35
|
-
.typeahead-suggestion.typeahead-cursor { color: rgba(58,144,216,1); }
|
36
|
-
.typeahead-suggestion p {
|
37
|
-
font-size: 12px;
|
38
|
-
font-weight: bold;
|
39
|
-
line-height: 20px;
|
40
|
-
margin: 0;
|
41
|
-
}
|
7
|
+
.typeahead { z-index: 1051; }
|
8
|
+
.typeahead b { color: rgba(122,179,23,1); }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flashgrid-ext
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Juan Gomez
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-02-
|
11
|
+
date: 2014-02-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -65,7 +65,6 @@ files:
|
|
65
65
|
- vendor/assets/javascripts/sort.js
|
66
66
|
- vendor/assets/javascripts/time_ago.js
|
67
67
|
- vendor/assets/javascripts/typeahead.js
|
68
|
-
- vendor/assets/javascripts/typeahead_search.js
|
69
68
|
- vendor/assets/stylesheets/animate.css.scss
|
70
69
|
- vendor/assets/stylesheets/calendar.css.scss
|
71
70
|
- vendor/assets/stylesheets/carousel.css.scss
|
@@ -93,7 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
93
92
|
version: '0'
|
94
93
|
requirements: []
|
95
94
|
rubyforge_project:
|
96
|
-
rubygems_version: 2.2.
|
95
|
+
rubygems_version: 2.2.2
|
97
96
|
signing_key:
|
98
97
|
specification_version: 4
|
99
98
|
summary: Flashgrid Extensions
|
@@ -1,645 +0,0 @@
|
|
1
|
-
(function($) {
|
2
|
-
var _ = {
|
3
|
-
isMsie: function() {
|
4
|
-
return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
|
5
|
-
},
|
6
|
-
isBlankString: function(str) {
|
7
|
-
return !str || /^\s*$/.test(str);
|
8
|
-
},
|
9
|
-
escapeRegExChars: function(str) {
|
10
|
-
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
11
|
-
},
|
12
|
-
isString: function(obj) {
|
13
|
-
return typeof obj === "string";
|
14
|
-
},
|
15
|
-
isNumber: function(obj) {
|
16
|
-
return typeof obj === "number";
|
17
|
-
},
|
18
|
-
isArray: $.isArray,
|
19
|
-
isFunction: $.isFunction,
|
20
|
-
isObject: $.isPlainObject,
|
21
|
-
isUndefined: function(obj) {
|
22
|
-
return typeof obj === "undefined";
|
23
|
-
},
|
24
|
-
bind: $.proxy,
|
25
|
-
each: function(collection, cb) {
|
26
|
-
$.each(collection, reverseArgs);
|
27
|
-
function reverseArgs(index, value) {
|
28
|
-
return cb(value, index);
|
29
|
-
}
|
30
|
-
},
|
31
|
-
map: $.map,
|
32
|
-
filter: $.grep,
|
33
|
-
every: function(obj, test) {
|
34
|
-
var result = true;
|
35
|
-
if (!obj) {
|
36
|
-
return result;
|
37
|
-
}
|
38
|
-
$.each(obj, function(key, val) {
|
39
|
-
if (!(result = test.call(null, val, key, obj))) {
|
40
|
-
return false;
|
41
|
-
}
|
42
|
-
});
|
43
|
-
return !!result;
|
44
|
-
},
|
45
|
-
some: function(obj, test) {
|
46
|
-
var result = false;
|
47
|
-
if (!obj) {
|
48
|
-
return result;
|
49
|
-
}
|
50
|
-
$.each(obj, function(key, val) {
|
51
|
-
if (result = test.call(null, val, key, obj)) {
|
52
|
-
return false;
|
53
|
-
}
|
54
|
-
});
|
55
|
-
return !!result;
|
56
|
-
},
|
57
|
-
mixin: $.extend,
|
58
|
-
getUniqueId: function() {
|
59
|
-
var counter = 0;
|
60
|
-
return function() {
|
61
|
-
return counter++;
|
62
|
-
};
|
63
|
-
}(),
|
64
|
-
templatify: function templatify(obj) {
|
65
|
-
return $.isFunction(obj) ? obj : template;
|
66
|
-
function template() {
|
67
|
-
return String(obj);
|
68
|
-
}
|
69
|
-
},
|
70
|
-
defer: function(fn) {
|
71
|
-
setTimeout(fn, 0);
|
72
|
-
},
|
73
|
-
debounce: function(func, wait, immediate) {
|
74
|
-
var timeout, result;
|
75
|
-
return function() {
|
76
|
-
var context = this, args = arguments, later, callNow;
|
77
|
-
later = function() {
|
78
|
-
timeout = null;
|
79
|
-
if (!immediate) {
|
80
|
-
result = func.apply(context, args);
|
81
|
-
}
|
82
|
-
};
|
83
|
-
callNow = immediate && !timeout;
|
84
|
-
clearTimeout(timeout);
|
85
|
-
timeout = setTimeout(later, wait);
|
86
|
-
if (callNow) {
|
87
|
-
result = func.apply(context, args);
|
88
|
-
}
|
89
|
-
return result;
|
90
|
-
};
|
91
|
-
},
|
92
|
-
throttle: function(func, wait) {
|
93
|
-
var context, args, timeout, result, previous, later;
|
94
|
-
previous = 0;
|
95
|
-
later = function() {
|
96
|
-
previous = new Date();
|
97
|
-
timeout = null;
|
98
|
-
result = func.apply(context, args);
|
99
|
-
};
|
100
|
-
return function() {
|
101
|
-
var now = new Date(), remaining = wait - (now - previous);
|
102
|
-
context = this;
|
103
|
-
args = arguments;
|
104
|
-
if (remaining <= 0) {
|
105
|
-
clearTimeout(timeout);
|
106
|
-
timeout = null;
|
107
|
-
previous = now;
|
108
|
-
result = func.apply(context, args);
|
109
|
-
} else if (!timeout) {
|
110
|
-
timeout = setTimeout(later, remaining);
|
111
|
-
}
|
112
|
-
return result;
|
113
|
-
};
|
114
|
-
},
|
115
|
-
noop: function() {}
|
116
|
-
};
|
117
|
-
var VERSION = "0.10.1";
|
118
|
-
var LruCache = function(root, undefined) {
|
119
|
-
function LruCache(maxSize) {
|
120
|
-
this.maxSize = maxSize || 100;
|
121
|
-
this.size = 0;
|
122
|
-
this.hash = {};
|
123
|
-
this.list = new List();
|
124
|
-
}
|
125
|
-
_.mixin(LruCache.prototype, {
|
126
|
-
set: function set(key, val) {
|
127
|
-
var tailItem = this.list.tail, node;
|
128
|
-
if (this.size >= this.maxSize) {
|
129
|
-
this.list.remove(tailItem);
|
130
|
-
delete this.hash[tailItem.key];
|
131
|
-
}
|
132
|
-
if (node = this.hash[key]) {
|
133
|
-
node.val = val;
|
134
|
-
this.list.moveToFront(node);
|
135
|
-
} else {
|
136
|
-
node = new Node(key, val);
|
137
|
-
this.list.add(node);
|
138
|
-
this.hash[key] = node;
|
139
|
-
this.size++;
|
140
|
-
}
|
141
|
-
},
|
142
|
-
get: function get(key) {
|
143
|
-
var node = this.hash[key];
|
144
|
-
if (node) {
|
145
|
-
this.list.moveToFront(node);
|
146
|
-
return node.val;
|
147
|
-
}
|
148
|
-
}
|
149
|
-
});
|
150
|
-
function List() {
|
151
|
-
this.head = this.tail = null;
|
152
|
-
}
|
153
|
-
_.mixin(List.prototype, {
|
154
|
-
add: function add(node) {
|
155
|
-
if (this.head) {
|
156
|
-
node.next = this.head;
|
157
|
-
this.head.prev = node;
|
158
|
-
}
|
159
|
-
this.head = node;
|
160
|
-
this.tail = this.tail || node;
|
161
|
-
},
|
162
|
-
remove: function remove(node) {
|
163
|
-
node.prev ? node.prev.next = node.next : this.head = node.next;
|
164
|
-
node.next ? node.next.prev = node.prev : this.tail = node.prev;
|
165
|
-
},
|
166
|
-
moveToFront: function(node) {
|
167
|
-
this.remove(node);
|
168
|
-
this.add(node);
|
169
|
-
}
|
170
|
-
});
|
171
|
-
function Node(key, val) {
|
172
|
-
this.key = key;
|
173
|
-
this.val = val;
|
174
|
-
this.prev = this.next = null;
|
175
|
-
}
|
176
|
-
return LruCache;
|
177
|
-
}(this);
|
178
|
-
var PersistentStorage = function() {
|
179
|
-
var ls, methods;
|
180
|
-
try {
|
181
|
-
ls = window.localStorage;
|
182
|
-
ls.setItem("~~~", "!");
|
183
|
-
ls.removeItem("~~~");
|
184
|
-
} catch (err) {
|
185
|
-
ls = null;
|
186
|
-
}
|
187
|
-
function PersistentStorage(namespace) {
|
188
|
-
this.prefix = [ "__", namespace, "__" ].join("");
|
189
|
-
this.ttlKey = "__ttl__";
|
190
|
-
this.keyMatcher = new RegExp("^" + this.prefix);
|
191
|
-
}
|
192
|
-
if (ls && window.JSON) {
|
193
|
-
methods = {
|
194
|
-
_prefix: function(key) {
|
195
|
-
return this.prefix + key;
|
196
|
-
},
|
197
|
-
_ttlKey: function(key) {
|
198
|
-
return this._prefix(key) + this.ttlKey;
|
199
|
-
},
|
200
|
-
get: function(key) {
|
201
|
-
if (this.isExpired(key)) {
|
202
|
-
this.remove(key);
|
203
|
-
}
|
204
|
-
return decode(ls.getItem(this._prefix(key)));
|
205
|
-
},
|
206
|
-
set: function(key, val, ttl) {
|
207
|
-
if (_.isNumber(ttl)) {
|
208
|
-
ls.setItem(this._ttlKey(key), encode(now() + ttl));
|
209
|
-
} else {
|
210
|
-
ls.removeItem(this._ttlKey(key));
|
211
|
-
}
|
212
|
-
return ls.setItem(this._prefix(key), encode(val));
|
213
|
-
},
|
214
|
-
remove: function(key) {
|
215
|
-
ls.removeItem(this._ttlKey(key));
|
216
|
-
ls.removeItem(this._prefix(key));
|
217
|
-
return this;
|
218
|
-
},
|
219
|
-
clear: function() {
|
220
|
-
var i, key, keys = [], len = ls.length;
|
221
|
-
for (i = 0; i < len; i++) {
|
222
|
-
if ((key = ls.key(i)).match(this.keyMatcher)) {
|
223
|
-
keys.push(key.replace(this.keyMatcher, ""));
|
224
|
-
}
|
225
|
-
}
|
226
|
-
for (i = keys.length; i--; ) {
|
227
|
-
this.remove(keys[i]);
|
228
|
-
}
|
229
|
-
return this;
|
230
|
-
},
|
231
|
-
isExpired: function(key) {
|
232
|
-
var ttl = decode(ls.getItem(this._ttlKey(key)));
|
233
|
-
return _.isNumber(ttl) && now() > ttl ? true : false;
|
234
|
-
}
|
235
|
-
};
|
236
|
-
} else {
|
237
|
-
methods = {
|
238
|
-
get: _.noop,
|
239
|
-
set: _.noop,
|
240
|
-
remove: _.noop,
|
241
|
-
clear: _.noop,
|
242
|
-
isExpired: _.noop
|
243
|
-
};
|
244
|
-
}
|
245
|
-
_.mixin(PersistentStorage.prototype, methods);
|
246
|
-
return PersistentStorage;
|
247
|
-
function now() {
|
248
|
-
return new Date().getTime();
|
249
|
-
}
|
250
|
-
function encode(val) {
|
251
|
-
return JSON.stringify(_.isUndefined(val) ? null : val);
|
252
|
-
}
|
253
|
-
function decode(val) {
|
254
|
-
return JSON.parse(val);
|
255
|
-
}
|
256
|
-
}();
|
257
|
-
var Transport = function() {
|
258
|
-
var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, requestCache = new LruCache(10);
|
259
|
-
function Transport(o) {
|
260
|
-
o = o || {};
|
261
|
-
this._send = o.transport ? callbackToDeferred(o.transport) : $.ajax;
|
262
|
-
this._get = o.rateLimiter ? o.rateLimiter(this._get) : this._get;
|
263
|
-
}
|
264
|
-
Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {
|
265
|
-
maxPendingRequests = num;
|
266
|
-
};
|
267
|
-
Transport.resetCache = function clearCache() {
|
268
|
-
requestCache = new LruCache(10);
|
269
|
-
};
|
270
|
-
_.mixin(Transport.prototype, {
|
271
|
-
_get: function(url, o, cb) {
|
272
|
-
var that = this, jqXhr;
|
273
|
-
if (jqXhr = pendingRequests[url]) {
|
274
|
-
jqXhr.done(done);
|
275
|
-
} else if (pendingRequestsCount < maxPendingRequests) {
|
276
|
-
pendingRequestsCount++;
|
277
|
-
pendingRequests[url] = this._send(url, o).done(done).always(always);
|
278
|
-
} else {
|
279
|
-
this.onDeckRequestArgs = [].slice.call(arguments, 0);
|
280
|
-
}
|
281
|
-
function done(resp) {
|
282
|
-
cb && cb(resp);
|
283
|
-
requestCache.set(url, resp);
|
284
|
-
}
|
285
|
-
function always() {
|
286
|
-
pendingRequestsCount--;
|
287
|
-
delete pendingRequests[url];
|
288
|
-
if (that.onDeckRequestArgs) {
|
289
|
-
that._get.apply(that, that.onDeckRequestArgs);
|
290
|
-
that.onDeckRequestArgs = null;
|
291
|
-
}
|
292
|
-
}
|
293
|
-
},
|
294
|
-
get: function(url, o, cb) {
|
295
|
-
var that = this, resp;
|
296
|
-
if (_.isFunction(o)) {
|
297
|
-
cb = o;
|
298
|
-
o = {};
|
299
|
-
}
|
300
|
-
if (resp = requestCache.get(url)) {
|
301
|
-
_.defer(function() {
|
302
|
-
cb && cb(resp);
|
303
|
-
});
|
304
|
-
} else {
|
305
|
-
this._get(url, o, cb);
|
306
|
-
}
|
307
|
-
return !!resp;
|
308
|
-
}
|
309
|
-
});
|
310
|
-
return Transport;
|
311
|
-
function callbackToDeferred(fn) {
|
312
|
-
return function customSendWrapper(url, o) {
|
313
|
-
var deferred = $.Deferred();
|
314
|
-
fn(url, o, onSuccess, onError);
|
315
|
-
return deferred;
|
316
|
-
function onSuccess(resp) {
|
317
|
-
_.defer(function() {
|
318
|
-
deferred.resolve(resp);
|
319
|
-
});
|
320
|
-
}
|
321
|
-
function onError(err) {
|
322
|
-
_.defer(function() {
|
323
|
-
deferred.reject(err);
|
324
|
-
});
|
325
|
-
}
|
326
|
-
};
|
327
|
-
}
|
328
|
-
}();
|
329
|
-
var SearchIndex = function() {
|
330
|
-
function SearchIndex(o) {
|
331
|
-
o = o || {};
|
332
|
-
if (!o.datumTokenizer || !o.queryTokenizer) {
|
333
|
-
$.error("datumTokenizer and queryTokenizer are both required");
|
334
|
-
}
|
335
|
-
this.datumTokenizer = o.datumTokenizer;
|
336
|
-
this.queryTokenizer = o.queryTokenizer;
|
337
|
-
this.datums = [];
|
338
|
-
this.trie = newNode();
|
339
|
-
}
|
340
|
-
_.mixin(SearchIndex.prototype, {
|
341
|
-
bootstrap: function bootstrap(o) {
|
342
|
-
this.datums = o.datums;
|
343
|
-
this.trie = o.trie;
|
344
|
-
},
|
345
|
-
add: function(data) {
|
346
|
-
var that = this;
|
347
|
-
data = _.isArray(data) ? data : [ data ];
|
348
|
-
_.each(data, function(datum) {
|
349
|
-
var id, tokens;
|
350
|
-
id = that.datums.push(datum) - 1;
|
351
|
-
tokens = normalizeTokens(that.datumTokenizer(datum));
|
352
|
-
_.each(tokens, function(token) {
|
353
|
-
var node, chars, ch, ids;
|
354
|
-
node = that.trie;
|
355
|
-
chars = token.split("");
|
356
|
-
while (ch = chars.shift()) {
|
357
|
-
node = node.children[ch] || (node.children[ch] = newNode());
|
358
|
-
node.ids.push(id);
|
359
|
-
}
|
360
|
-
});
|
361
|
-
});
|
362
|
-
},
|
363
|
-
get: function get(query) {
|
364
|
-
var that = this, tokens, matches;
|
365
|
-
tokens = normalizeTokens(this.queryTokenizer(query));
|
366
|
-
_.each(tokens, function(token) {
|
367
|
-
var node, chars, ch, ids;
|
368
|
-
if (matches && matches.length === 0) {
|
369
|
-
return false;
|
370
|
-
}
|
371
|
-
node = that.trie;
|
372
|
-
chars = token.split("");
|
373
|
-
while (node && (ch = chars.shift())) {
|
374
|
-
node = node.children[ch];
|
375
|
-
}
|
376
|
-
if (node && chars.length === 0) {
|
377
|
-
ids = node.ids.slice(0);
|
378
|
-
matches = matches ? getIntersection(matches, ids) : ids;
|
379
|
-
} else {
|
380
|
-
matches = [];
|
381
|
-
return false;
|
382
|
-
}
|
383
|
-
});
|
384
|
-
return matches ? _.map(unique(matches), function(id) {
|
385
|
-
return that.datums[id];
|
386
|
-
}) : [];
|
387
|
-
},
|
388
|
-
serialize: function serialize() {
|
389
|
-
return {
|
390
|
-
datums: this.datums,
|
391
|
-
trie: this.trie
|
392
|
-
};
|
393
|
-
}
|
394
|
-
});
|
395
|
-
return SearchIndex;
|
396
|
-
function normalizeTokens(tokens) {
|
397
|
-
tokens = _.filter(tokens, function(token) {
|
398
|
-
return !!token;
|
399
|
-
});
|
400
|
-
tokens = _.map(tokens, function(token) {
|
401
|
-
return token.toLowerCase();
|
402
|
-
});
|
403
|
-
return tokens;
|
404
|
-
}
|
405
|
-
function newNode() {
|
406
|
-
return {
|
407
|
-
ids: [],
|
408
|
-
children: {}
|
409
|
-
};
|
410
|
-
}
|
411
|
-
function unique(array) {
|
412
|
-
var seen = {}, uniques = [];
|
413
|
-
for (var i = 0; i < array.length; i++) {
|
414
|
-
if (!seen[array[i]]) {
|
415
|
-
seen[array[i]] = true;
|
416
|
-
uniques.push(array[i]);
|
417
|
-
}
|
418
|
-
}
|
419
|
-
return uniques;
|
420
|
-
}
|
421
|
-
function getIntersection(arrayA, arrayB) {
|
422
|
-
var ai = 0, bi = 0, intersection = [];
|
423
|
-
arrayA = arrayA.sort(compare);
|
424
|
-
arrayB = arrayB.sort(compare);
|
425
|
-
while (ai < arrayA.length && bi < arrayB.length) {
|
426
|
-
if (arrayA[ai] < arrayB[bi]) {
|
427
|
-
ai++;
|
428
|
-
} else if (arrayA[ai] > arrayB[bi]) {
|
429
|
-
bi++;
|
430
|
-
} else {
|
431
|
-
intersection.push(arrayA[ai]);
|
432
|
-
ai++;
|
433
|
-
bi++;
|
434
|
-
}
|
435
|
-
}
|
436
|
-
return intersection;
|
437
|
-
function compare(a, b) {
|
438
|
-
return a - b;
|
439
|
-
}
|
440
|
-
}
|
441
|
-
}();
|
442
|
-
var oParser = function() {
|
443
|
-
return {
|
444
|
-
local: getLocal,
|
445
|
-
prefetch: getPrefetch,
|
446
|
-
remote: getRemote
|
447
|
-
};
|
448
|
-
function getLocal(o) {
|
449
|
-
var local = o.local || null;
|
450
|
-
if (_.isFunction(local)) {
|
451
|
-
local = local.call(null);
|
452
|
-
}
|
453
|
-
return local;
|
454
|
-
}
|
455
|
-
function getPrefetch(o) {
|
456
|
-
var prefetch, defaults;
|
457
|
-
defaults = {
|
458
|
-
url: null,
|
459
|
-
thumbprint: "",
|
460
|
-
ttl: 24 * 60 * 60 * 1e3,
|
461
|
-
filter: null,
|
462
|
-
ajax: {}
|
463
|
-
};
|
464
|
-
if (prefetch = o.prefetch || null) {
|
465
|
-
prefetch = _.isString(prefetch) ? {
|
466
|
-
url: prefetch
|
467
|
-
} : prefetch;
|
468
|
-
prefetch = _.mixin(defaults, prefetch);
|
469
|
-
prefetch.thumbprint = VERSION + prefetch.thumbprint;
|
470
|
-
prefetch.ajax.type = prefetch.ajax.type || "GET";
|
471
|
-
prefetch.ajax.dataType = prefetch.ajax.dataType || "json";
|
472
|
-
!prefetch.url && $.error("prefetch requires url to be set");
|
473
|
-
}
|
474
|
-
return prefetch;
|
475
|
-
}
|
476
|
-
function getRemote(o) {
|
477
|
-
var remote, defaults;
|
478
|
-
defaults = {
|
479
|
-
url: null,
|
480
|
-
wildcard: "%QUERY",
|
481
|
-
replace: null,
|
482
|
-
rateLimitBy: "debounce",
|
483
|
-
rateLimitWait: 300,
|
484
|
-
send: null,
|
485
|
-
filter: null,
|
486
|
-
ajax: {}
|
487
|
-
};
|
488
|
-
if (remote = o.remote || null) {
|
489
|
-
remote = _.isString(remote) ? {
|
490
|
-
url: remote
|
491
|
-
} : remote;
|
492
|
-
remote = _.mixin(defaults, remote);
|
493
|
-
remote.rateLimiter = /^throttle$/i.test(remote.rateLimitBy) ? byThrottle(remote.rateLimitWait) : byDebounce(remote.rateLimitWait);
|
494
|
-
remote.ajax.type = remote.ajax.type || "GET";
|
495
|
-
remote.ajax.dataType = remote.ajax.dataType || "json";
|
496
|
-
delete remote.rateLimitBy;
|
497
|
-
delete remote.rateLimitWait;
|
498
|
-
!remote.url && $.error("remote requires url to be set");
|
499
|
-
}
|
500
|
-
return remote;
|
501
|
-
function byDebounce(wait) {
|
502
|
-
return function(fn) {
|
503
|
-
return _.debounce(fn, wait);
|
504
|
-
};
|
505
|
-
}
|
506
|
-
function byThrottle(wait) {
|
507
|
-
return function(fn) {
|
508
|
-
return _.throttle(fn, wait);
|
509
|
-
};
|
510
|
-
}
|
511
|
-
}
|
512
|
-
}();
|
513
|
-
var Bloodhound = window.Bloodhound = function() {
|
514
|
-
var keys;
|
515
|
-
keys = {
|
516
|
-
data: "data",
|
517
|
-
protocol: "protocol",
|
518
|
-
thumbprint: "thumbprint"
|
519
|
-
};
|
520
|
-
function Bloodhound(o) {
|
521
|
-
if (!o || !o.local && !o.prefetch && !o.remote) {
|
522
|
-
$.error("one of local, prefetch, or remote is required");
|
523
|
-
}
|
524
|
-
this.limit = o.limit || 5;
|
525
|
-
this.sorter = getSorter(o.sorter);
|
526
|
-
this.dupDetector = o.dupDetector || ignoreDuplicates;
|
527
|
-
this.local = oParser.local(o);
|
528
|
-
this.prefetch = oParser.prefetch(o);
|
529
|
-
this.remote = oParser.remote(o);
|
530
|
-
this.cacheKey = this.prefetch ? this.prefetch.cacheKey || this.prefetch.url : null;
|
531
|
-
this.index = new SearchIndex({
|
532
|
-
datumTokenizer: o.datumTokenizer,
|
533
|
-
queryTokenizer: o.queryTokenizer
|
534
|
-
});
|
535
|
-
this.storage = this.cacheKey ? new PersistentStorage(this.cacheKey) : null;
|
536
|
-
}
|
537
|
-
Bloodhound.tokenizers = {
|
538
|
-
whitespace: function whitespaceTokenizer(s) {
|
539
|
-
return s.split(/\s+/);
|
540
|
-
},
|
541
|
-
nonword: function nonwordTokenizer(s) {
|
542
|
-
return s.split(/\W+/);
|
543
|
-
}
|
544
|
-
};
|
545
|
-
_.mixin(Bloodhound.prototype, {
|
546
|
-
_loadPrefetch: function loadPrefetch(o) {
|
547
|
-
var that = this, serialized, deferred;
|
548
|
-
if (serialized = this._readFromStorage(o.thumbprint)) {
|
549
|
-
this.index.bootstrap(serialized);
|
550
|
-
deferred = $.Deferred().resolve();
|
551
|
-
} else {
|
552
|
-
deferred = $.ajax(o.url, o.ajax).done(handlePrefetchResponse);
|
553
|
-
}
|
554
|
-
return deferred;
|
555
|
-
function handlePrefetchResponse(resp) {
|
556
|
-
var filtered;
|
557
|
-
filtered = o.filter ? o.filter(resp) : resp;
|
558
|
-
that.add(filtered);
|
559
|
-
that._saveToStorage(that.index.serialize(), o.thumbprint, o.ttl);
|
560
|
-
}
|
561
|
-
},
|
562
|
-
_getFromRemote: function getFromRemote(query, cb) {
|
563
|
-
var that = this, url, uriEncodedQuery;
|
564
|
-
query = query || "";
|
565
|
-
uriEncodedQuery = encodeURIComponent(query);
|
566
|
-
url = this.remote.replace ? this.remote.replace(this.remote.url, query) : this.remote.url.replace(this.remote.wildcard, uriEncodedQuery);
|
567
|
-
return this.transport.get(url, this.remote.ajax, handleRemoteResponse);
|
568
|
-
function handleRemoteResponse(resp) {
|
569
|
-
var filtered = that.remote.filter ? that.remote.filter(resp) : resp;
|
570
|
-
cb(filtered);
|
571
|
-
}
|
572
|
-
},
|
573
|
-
_saveToStorage: function saveToStorage(data, thumbprint, ttl) {
|
574
|
-
if (this.storage) {
|
575
|
-
this.storage.set(keys.data, data, ttl);
|
576
|
-
this.storage.set(keys.protocol, location.protocol, ttl);
|
577
|
-
this.storage.set(keys.thumbprint, thumbprint, ttl);
|
578
|
-
}
|
579
|
-
},
|
580
|
-
_readFromStorage: function readFromStorage(thumbprint) {
|
581
|
-
var stored = {}, isExpired;
|
582
|
-
if (this.storage) {
|
583
|
-
stored.data = this.storage.get(keys.data);
|
584
|
-
stored.protocol = this.storage.get(keys.protocol);
|
585
|
-
stored.thumbprint = this.storage.get(keys.thumbprint);
|
586
|
-
}
|
587
|
-
isExpired = stored.thumbprint !== thumbprint || stored.protocol !== location.protocol;
|
588
|
-
return stored.data && !isExpired ? stored.data : null;
|
589
|
-
},
|
590
|
-
initialize: function initialize() {
|
591
|
-
var that = this, deferred;
|
592
|
-
deferred = this.prefetch ? this._loadPrefetch(this.prefetch) : $.Deferred().resolve();
|
593
|
-
this.local && deferred.done(addLocalToIndex);
|
594
|
-
this.transport = this.remote ? new Transport(this.remote) : null;
|
595
|
-
this.initialize = function initialize() {
|
596
|
-
return deferred.promise();
|
597
|
-
};
|
598
|
-
return deferred.promise();
|
599
|
-
function addLocalToIndex() {
|
600
|
-
that.add(that.local);
|
601
|
-
}
|
602
|
-
},
|
603
|
-
add: function add(data) {
|
604
|
-
this.index.add(data);
|
605
|
-
},
|
606
|
-
get: function get(query, cb) {
|
607
|
-
var that = this, matches, cacheHit = false;
|
608
|
-
matches = this.index.get(query);
|
609
|
-
matches = this.sorter(matches).slice(0, this.limit);
|
610
|
-
if (matches.length < this.limit && this.transport) {
|
611
|
-
cacheHit = this._getFromRemote(query, returnRemoteMatches);
|
612
|
-
}
|
613
|
-
!cacheHit && cb && cb(matches);
|
614
|
-
function returnRemoteMatches(remoteMatches) {
|
615
|
-
var matchesWithBackfill = matches.slice(0);
|
616
|
-
_.each(remoteMatches, function(remoteMatch) {
|
617
|
-
var isDuplicate;
|
618
|
-
isDuplicate = _.some(matchesWithBackfill, function(match) {
|
619
|
-
return that.dupDetector(remoteMatch, match);
|
620
|
-
});
|
621
|
-
!isDuplicate && matchesWithBackfill.push(remoteMatch);
|
622
|
-
return matchesWithBackfill.length < that.limit;
|
623
|
-
});
|
624
|
-
cb && cb(that.sorter(matchesWithBackfill));
|
625
|
-
}
|
626
|
-
},
|
627
|
-
ttAdapter: function ttAdapter() {
|
628
|
-
return _.bind(this.get, this);
|
629
|
-
}
|
630
|
-
});
|
631
|
-
return Bloodhound;
|
632
|
-
function getSorter(sortFn) {
|
633
|
-
return _.isFunction(sortFn) ? sort : noSort;
|
634
|
-
function sort(array) {
|
635
|
-
return array.sort(sortFn);
|
636
|
-
}
|
637
|
-
function noSort(array) {
|
638
|
-
return array;
|
639
|
-
}
|
640
|
-
}
|
641
|
-
function ignoreDuplicates() {
|
642
|
-
return false;
|
643
|
-
}
|
644
|
-
}();
|
645
|
-
})(window.jQuery);
|