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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5d77a9df299635c4c33f9374fba7b84fbd62ce95
4
- data.tar.gz: c11b21bf56c75159d279402db6bb4b3e4e5242f1
3
+ metadata.gz: ea32f79411d1e47fe5c984235a66aa81e0474f42
4
+ data.tar.gz: 413c2cca138cae97d872bf4a9e5ff59923df172d
5
5
  SHA512:
6
- metadata.gz: caeb64f5c234e6043b9eafcdb9ec335ccd05a8dba04956a0de3b5efe98cbae8119b2bc689524b294c2ba9eeaffe5a38d12a89d3cf8dbedc987c6d594532c5b35
7
- data.tar.gz: 2930cd0b80b30c0c6cdd272f367831dbe3e0cfb78b76e8347cb0986f61d8c317b43c4b09d74041bdadee3a9b8ad0601dc2759db85fae743e0131ee42ee0618d5
6
+ metadata.gz: b89fd83a0fe480e3fad323c35fa7c7200693e48703c94d89ea12bf8d13198aa15c93facf67d9ef6d6cea2e9fd546df309ba6cb3304a22d93f9efb1bcc49678f8
7
+ data.tar.gz: 1e223b9a7c0ec62bc16eaeecfe4d1bb7210d622506aed9ea8cbf2f93b8af126ed11cd49e915cf38acd10fb777026e175576fc7055983d836d41474a52decb96b
data/README.md CHANGED
@@ -46,5 +46,4 @@ Add the JS files you want to include:
46
46
  //= require sort.js
47
47
  //= require time_ago.js
48
48
  //= require typeahead.js
49
- //= require typeahead_search.js
50
49
  ```
@@ -1,5 +1,5 @@
1
1
  module Flashgrid
2
2
  module Ext
3
- VERSION = "1.0.4"
3
+ VERSION = "1.0.5"
4
4
  end
5
5
  end
@@ -1,1124 +1,368 @@
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 html = {
118
- wrapper: '<span class="typeahead-wrapper"></span>',
119
- dropdown: '<span class="typeahead-dropdown-menu"></span>',
120
- dataset: '<div class="typeahead-dataset-%CLASS%"></div>',
121
- suggestions: '<span class="typeahead-suggestions"></span>',
122
- suggestion: '<div class="typeahead-suggestion">%BODY%</div>'
123
- };
124
- var css = {
125
- wrapper: {
126
- position: "relative",
127
- display: "inline-block"
128
- },
129
- hint: {
130
- position: "absolute",
131
- top: "0",
132
- left: "0",
133
- borderColor: "transparent",
134
- boxShadow: "none"
135
- },
136
- input: {
137
- position: "relative",
138
- verticalAlign: "top",
139
- backgroundColor: "transparent"
140
- },
141
- inputWithNoHint: {
142
- position: "relative",
143
- verticalAlign: "top"
144
- },
145
- dropdown: {
146
- position: "absolute",
147
- top: "100%",
148
- left: "0",
149
- zIndex: "100",
150
- display: "none"
151
- },
152
- suggestions: {
153
- display: "block"
154
- },
155
- suggestion: {
156
- whiteSpace: "nowrap",
157
- cursor: "pointer"
158
- },
159
- suggestionChild: {
160
- whiteSpace: "normal"
161
- },
162
- ltr: {
163
- left: "0",
164
- right: "auto"
165
- },
166
- rtl: {
167
- left: "auto",
168
- right: " 0"
169
- }
170
- };
171
- if (_.isMsie()) {
172
- _.mixin(css.input, {
173
- backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"
174
- });
1
+ !function($){
2
+
3
+ "use strict";
4
+ // jshint laxcomma: true
5
+
6
+
7
+ /* TYPEAHEAD PUBLIC CLASS DEFINITION
8
+ * ================================= */
9
+
10
+ var Typeahead = function (element, options) {
11
+ this.$element = $(element);
12
+ this.options = $.extend({}, $.fn.typeahead.defaults, options);
13
+ this.matcher = this.options.matcher || this.matcher;
14
+ this.sorter = this.options.sorter || this.sorter;
15
+ this.select = this.options.select || this.select;
16
+ this.autoSelect = typeof this.options.autoSelect == 'boolean' ? this.options.autoSelect : true;
17
+ this.highlighter = this.options.highlighter || this.highlighter;
18
+ this.updater = this.options.updater || this.updater;
19
+ this.source = this.options.source;
20
+ this.$menu = $(this.options.menu);
21
+ this.shown = false;
22
+ this.listen();
23
+ this.showHintOnFocus = typeof this.options.showHintOnFocus == 'boolean' ? this.options.showHintOnFocus : false;
24
+ };
25
+
26
+ Typeahead.prototype = {
27
+
28
+ constructor: Typeahead
29
+
30
+ , select: function () {
31
+ var val = this.$menu.find('.active').data('value');
32
+ if(this.autoSelect || val) {
33
+ this.$element
34
+ .val(this.updater(val))
35
+ .change();
36
+ }
37
+ return this.hide();
175
38
  }
176
- if (_.isMsie() && _.isMsie() <= 7) {
177
- _.mixin(css.input, {
178
- marginTop: "-1px"
179
- });
39
+
40
+ , updater: function (item) {
41
+ return item;
180
42
  }
181
- var EventBus = function() {
182
- var namespace = "typeahead:";
183
- function EventBus(o) {
184
- if (!o || !o.el) {
185
- $.error("EventBus initialized without el");
186
- }
187
- this.$el = $(o.el);
188
- }
189
- _.mixin(EventBus.prototype, {
190
- trigger: function(type) {
191
- var args = [].slice.call(arguments, 1);
192
- this.$el.trigger(namespace + type, args);
193
- }
194
- });
195
- return EventBus;
196
- }();
197
- var EventEmitter = function() {
198
- var splitter = /\s+/, nextTick = getNextTick();
199
- return {
200
- onSync: onSync,
201
- onAsync: onAsync,
202
- off: off,
203
- trigger: trigger
204
- };
205
- function on(method, types, cb, context) {
206
- var type;
207
- if (!cb) {
208
- return this;
209
- }
210
- types = types.split(splitter);
211
- cb = context ? bindContext(cb, context) : cb;
212
- this._callbacks = this._callbacks || {};
213
- while (type = types.shift()) {
214
- this._callbacks[type] = this._callbacks[type] || {
215
- sync: [],
216
- async: []
217
- };
218
- this._callbacks[type][method].push(cb);
219
- }
220
- return this;
221
- }
222
- function onAsync(types, cb, context) {
223
- return on.call(this, "async", types, cb, context);
224
- }
225
- function onSync(types, cb, context) {
226
- return on.call(this, "sync", types, cb, context);
227
- }
228
- function off(types) {
229
- var type;
230
- if (!this._callbacks) {
231
- return this;
232
- }
233
- types = types.split(splitter);
234
- while (type = types.shift()) {
235
- delete this._callbacks[type];
236
- }
237
- return this;
238
- }
239
- function trigger(types) {
240
- var that = this, type, callbacks, args, syncFlush, asyncFlush;
241
- if (!this._callbacks) {
242
- return this;
243
- }
244
- types = types.split(splitter);
245
- args = [].slice.call(arguments, 1);
246
- while ((type = types.shift()) && (callbacks = this._callbacks[type])) {
247
- syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args));
248
- asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args));
249
- syncFlush() && nextTick(asyncFlush);
250
- }
251
- return this;
252
- }
253
- function getFlush(callbacks, context, args) {
254
- return flush;
255
- function flush() {
256
- var cancelled;
257
- for (var i = 0; !cancelled && i < callbacks.length; i += 1) {
258
- cancelled = callbacks[i].apply(context, args) === false;
259
- }
260
- return !cancelled;
261
- }
262
- }
263
- function getNextTick() {
264
- var nextTickFn, messageChannel;
265
- if (window.setImmediate) {
266
- nextTickFn = function nextTickSetImmediate(fn) {
267
- setImmediate(function() {
268
- fn();
269
- });
270
- };
271
- } else {
272
- nextTickFn = function nextTickSetTimeout(fn) {
273
- setTimeout(function() {
274
- fn();
275
- }, 0);
276
- };
277
- }
278
- return nextTickFn;
279
- }
280
- function bindContext(fn, context) {
281
- return fn.bind ? fn.bind(context) : function() {
282
- fn.apply(context, [].slice.call(arguments, 0));
283
- };
284
- }
285
- }();
286
- var highlight = function(doc) {
287
- var defaults = {
288
- node: null,
289
- pattern: null,
290
- tagName: "strong",
291
- className: null,
292
- wordsOnly: false,
293
- caseSensitive: false
294
- };
295
- return function hightlight(o) {
296
- var regex;
297
- o = _.mixin({}, defaults, o);
298
- if (!o.node || !o.pattern) {
299
- return;
300
- }
301
- o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ];
302
- regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly);
303
- traverse(o.node, hightlightTextNode);
304
- function hightlightTextNode(textNode) {
305
- var match, patternNode;
306
- if (match = regex.exec(textNode.data)) {
307
- wrapperNode = doc.createElement(o.tagName);
308
- o.className && (wrapperNode.className = o.className);
309
- patternNode = textNode.splitText(match.index);
310
- patternNode.splitText(match[0].length);
311
- wrapperNode.appendChild(patternNode.cloneNode(true));
312
- textNode.parentNode.replaceChild(wrapperNode, patternNode);
313
- }
314
- return !!match;
315
- }
316
- function traverse(el, hightlightTextNode) {
317
- var childNode, TEXT_NODE_TYPE = 3;
318
- for (var i = 0; i < el.childNodes.length; i++) {
319
- childNode = el.childNodes[i];
320
- if (childNode.nodeType === TEXT_NODE_TYPE) {
321
- i += hightlightTextNode(childNode) ? 1 : 0;
322
- } else {
323
- traverse(childNode, hightlightTextNode);
324
- }
325
- }
326
- }
327
- };
328
- function getRegex(patterns, caseSensitive, wordsOnly) {
329
- var escapedPatterns = [], regexStr;
330
- for (var i = 0; i < patterns.length; i++) {
331
- escapedPatterns.push(_.escapeRegExChars(patterns[i]));
332
- }
333
- regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")";
334
- return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i");
335
- }
336
- }(window.document);
337
- var Input = function() {
338
- var specialKeyCodeMap;
339
- specialKeyCodeMap = {
340
- 9: "tab",
341
- 27: "esc",
342
- 37: "left",
343
- 39: "right",
344
- 13: "enter",
345
- 38: "up",
346
- 40: "down"
347
- };
348
- function Input(o) {
349
- var that = this, onBlur, onFocus, onKeydown, onInput;
350
- o = o || {};
351
- if (!o.input) {
352
- $.error("input is missing");
353
- }
354
- onBlur = _.bind(this._onBlur, this);
355
- onFocus = _.bind(this._onFocus, this);
356
- onKeydown = _.bind(this._onKeydown, this);
357
- onInput = _.bind(this._onInput, this);
358
- this.$hint = $(o.hint);
359
- this.$input = $(o.input).on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown);
360
- if (this.$hint.length === 0) {
361
- this.setHintValue = this.getHintValue = this.clearHint = _.noop;
362
- }
363
- if (!_.isMsie()) {
364
- this.$input.on("input.tt", onInput);
365
- } else {
366
- this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) {
367
- if (specialKeyCodeMap[$e.which || $e.keyCode]) {
368
- return;
369
- }
370
- _.defer(_.bind(that._onInput, that, $e));
371
- });
372
- }
373
- this.query = this.$input.val();
374
- this.$overflowHelper = buildOverflowHelper(this.$input);
375
- }
376
- Input.normalizeQuery = function(str) {
377
- return (str || "").replace(/^\s*/g, "").replace(/\s{2,}/g, " ");
378
- };
379
- _.mixin(Input.prototype, EventEmitter, {
380
- _onBlur: function onBlur($e) {
381
- this.resetInputValue();
382
- this.trigger("blurred");
383
- },
384
- _onFocus: function onFocus($e) {
385
- this.trigger("focused");
386
- },
387
- _onKeydown: function onKeydown($e) {
388
- var keyName = specialKeyCodeMap[$e.which || $e.keyCode];
389
- this._managePreventDefault(keyName, $e);
390
- if (keyName && this._shouldTrigger(keyName, $e)) {
391
- this.trigger(keyName + "Keyed", $e);
392
- }
393
- },
394
- _onInput: function onInput($e) {
395
- this._checkInputValue();
396
- },
397
- _managePreventDefault: function managePreventDefault(keyName, $e) {
398
- var preventDefault, hintValue, inputValue;
399
- switch (keyName) {
400
- case "tab":
401
- hintValue = this.getHintValue();
402
- inputValue = this.getInputValue();
403
- preventDefault = hintValue && hintValue !== inputValue && !withModifier($e);
404
- break;
405
-
406
- case "up":
407
- case "down":
408
- preventDefault = !withModifier($e);
409
- break;
410
-
411
- default:
412
- preventDefault = false;
413
- }
414
- preventDefault && $e.preventDefault();
415
- },
416
- _shouldTrigger: function shouldTrigger(keyName, $e) {
417
- var trigger;
418
- switch (keyName) {
419
- case "tab":
420
- trigger = !withModifier($e);
421
- break;
422
-
423
- default:
424
- trigger = true;
425
- }
426
- return trigger;
427
- },
428
- _checkInputValue: function checkInputValue() {
429
- var inputValue, areEquivalent, hasDifferentWhitespace;
430
- inputValue = this.getInputValue();
431
- areEquivalent = areQueriesEquivalent(inputValue, this.query);
432
- hasDifferentWhitespace = areEquivalent ? this.query.length !== inputValue.length : false;
433
- if (!areEquivalent) {
434
- this.trigger("queryChanged", this.query = inputValue);
435
- } else if (hasDifferentWhitespace) {
436
- this.trigger("whitespaceChanged", this.query);
437
- }
438
- },
439
- focus: function focus() {
440
- this.$input.focus();
441
- },
442
- blur: function blur() {
443
- this.$input.blur();
444
- },
445
- getQuery: function getQuery() {
446
- return this.query;
447
- },
448
- setQuery: function setQuery(query) {
449
- this.query = query;
450
- },
451
- getInputValue: function getInputValue() {
452
- return this.$input.val();
453
- },
454
- setInputValue: function setInputValue(value, silent) {
455
- this.$input.val(value);
456
- !silent && this._checkInputValue();
457
- },
458
- getHintValue: function getHintValue() {
459
- return this.$hint.val();
460
- },
461
- setHintValue: function setHintValue(value) {
462
- this.$hint.val(value);
463
- },
464
- resetInputValue: function resetInputValue() {
465
- this.$input.val(this.query);
466
- },
467
- clearHint: function clearHint() {
468
- this.$hint.val("");
469
- },
470
- getLanguageDirection: function getLanguageDirection() {
471
- return (this.$input.css("direction") || "ltr").toLowerCase();
472
- },
473
- hasOverflow: function hasOverflow() {
474
- var constraint = this.$input.width() - 2;
475
- this.$overflowHelper.text(this.getInputValue());
476
- return this.$overflowHelper.width() >= constraint;
477
- },
478
- isCursorAtEnd: function() {
479
- var valueLength, selectionStart, range;
480
- valueLength = this.$input.val().length;
481
- selectionStart = this.$input[0].selectionStart;
482
- if (_.isNumber(selectionStart)) {
483
- return selectionStart === valueLength;
484
- } else if (document.selection) {
485
- range = document.selection.createRange();
486
- range.moveStart("character", -valueLength);
487
- return valueLength === range.text.length;
488
- }
489
- return true;
490
- },
491
- destroy: function destroy() {
492
- this.$hint.off(".tt");
493
- this.$input.off(".tt");
494
- this.$hint = this.$input = this.$overflowHelper = null;
495
- }
496
- });
497
- return Input;
498
- function buildOverflowHelper($input) {
499
- return $('<pre aria-hidden="true"></pre>').css({
500
- position: "absolute",
501
- visibility: "hidden",
502
- whiteSpace: "nowrap",
503
- fontFamily: $input.css("font-family"),
504
- fontSize: $input.css("font-size"),
505
- fontStyle: $input.css("font-style"),
506
- fontVariant: $input.css("font-variant"),
507
- fontWeight: $input.css("font-weight"),
508
- wordSpacing: $input.css("word-spacing"),
509
- letterSpacing: $input.css("letter-spacing"),
510
- textIndent: $input.css("text-indent"),
511
- textRendering: $input.css("text-rendering"),
512
- textTransform: $input.css("text-transform")
513
- }).insertAfter($input);
514
- }
515
- function areQueriesEquivalent(a, b) {
516
- return Input.normalizeQuery(a) === Input.normalizeQuery(b);
517
- }
518
- function withModifier($e) {
519
- return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;
520
- }
521
- }();
522
- var Dataset = function() {
523
- var datasetKey = "ttDataset", valueKey = "ttValue", datumKey = "ttDatum";
524
- function Dataset(o) {
525
- o = o || {};
526
- o.templates = o.templates || {};
527
- if (!o.source) {
528
- $.error("missing source");
529
- }
530
- if (o.name && !isValidName(o.name)) {
531
- $.error("invalid dataset name: " + o.name);
532
- }
533
- this.query = null;
534
- this.highlight = !!o.highlight;
535
- this.name = o.name || _.getUniqueId();
536
- this.source = o.source;
537
- this.displayFn = getDisplayFn(o.display || o.displayKey);
538
- this.templates = getTemplates(o.templates, this.displayFn);
539
- this.$el = $(html.dataset.replace("%CLASS%", this.name));
540
- }
541
- Dataset.extractDatasetName = function extractDatasetName(el) {
542
- return $(el).data(datasetKey);
543
- };
544
- Dataset.extractValue = function extractDatum(el) {
545
- return $(el).data(valueKey);
546
- };
547
- Dataset.extractDatum = function extractDatum(el) {
548
- return $(el).data(datumKey);
549
- };
550
- _.mixin(Dataset.prototype, EventEmitter, {
551
- _render: function render(query, suggestions) {
552
- if (!this.$el) {
553
- return;
554
- }
555
- var that = this, hasSuggestions;
556
- this.$el.empty();
557
- hasSuggestions = suggestions && suggestions.length;
558
- if (!hasSuggestions && this.templates.empty) {
559
- this.$el.html(getEmptyHtml()).prepend(that.templates.header ? getHeaderHtml() : null).append(that.templates.footer ? getFooterHtml() : null);
560
- } else if (hasSuggestions) {
561
- this.$el.html(getSuggestionsHtml()).prepend(that.templates.header ? getHeaderHtml() : null).append(that.templates.footer ? getFooterHtml() : null);
562
- }
563
- this.trigger("rendered");
564
- function getEmptyHtml() {
565
- return that.templates.empty({
566
- query: query,
567
- isEmpty: true
568
- });
569
- }
570
- function getSuggestionsHtml() {
571
- var $suggestions, nodes;
572
- $suggestions = $(html.suggestions).css(css.suggestions);
573
- nodes = _.map(suggestions, getSuggestionNode);
574
- $suggestions.append.apply($suggestions, nodes);
575
- that.highlight && highlight({
576
- node: $suggestions[0],
577
- pattern: query
578
- });
579
- return $suggestions;
580
- function getSuggestionNode(suggestion) {
581
- var $el, innerHtml, outerHtml;
582
- innerHtml = that.templates.suggestion(suggestion);
583
- outerHtml = html.suggestion.replace("%BODY%", innerHtml);
584
- $el = $(outerHtml).data(datasetKey, that.name).data(valueKey, that.displayFn(suggestion)).data(datumKey, suggestion);
585
- $el.children().each(function() {
586
- $(this).css(css.suggestionChild);
587
- });
588
- return $el;
589
- }
590
- }
591
- function getHeaderHtml() {
592
- return that.templates.header({
593
- query: query,
594
- isEmpty: !hasSuggestions
595
- });
596
- }
597
- function getFooterHtml() {
598
- return that.templates.footer({
599
- query: query,
600
- isEmpty: !hasSuggestions
601
- });
602
- }
603
- },
604
- getRoot: function getRoot() {
605
- return this.$el;
606
- },
607
- update: function update(query) {
608
- var that = this;
609
- this.query = query;
610
- this.source(query, renderIfQueryIsSame);
611
- function renderIfQueryIsSame(suggestions) {
612
- query === that.query && that._render(query, suggestions);
613
- }
614
- },
615
- clear: function clear() {
616
- this._render(this.query || "");
617
- },
618
- isEmpty: function isEmpty() {
619
- return this.$el.is(":empty");
620
- },
621
- destroy: function destroy() {
622
- this.$el = null;
623
- }
624
- });
625
- return Dataset;
626
- function getDisplayFn(display) {
627
- display = display || "value";
628
- return _.isFunction(display) ? display : displayFn;
629
- function displayFn(obj) {
630
- return obj[display];
631
- }
632
- }
633
- function getTemplates(templates, displayFn) {
634
- return {
635
- empty: templates.empty && _.templatify(templates.empty),
636
- header: templates.header && _.templatify(templates.header),
637
- footer: templates.footer && _.templatify(templates.footer),
638
- suggestion: templates.suggestion || suggestionTemplate
639
- };
640
- function suggestionTemplate(context) {
641
- return "<p>" + displayFn(context) + "</p>";
642
- }
643
- }
644
- function isValidName(str) {
645
- return /^[_a-zA-Z0-9-]+$/.test(str);
646
- }
647
- }();
648
- var Dropdown = function() {
649
- function Dropdown(o) {
650
- var that = this, onSuggestionClick, onSuggestionMouseEnter, onSuggestionMouseLeave;
651
- o = o || {};
652
- if (!o.menu) {
653
- $.error("menu is required");
654
- }
655
- this.isOpen = false;
656
- this.isEmpty = true;
657
- this.datasets = _.map(o.datasets, initializeDataset);
658
- onSuggestionClick = _.bind(this._onSuggestionClick, this);
659
- onSuggestionMouseEnter = _.bind(this._onSuggestionMouseEnter, this);
660
- onSuggestionMouseLeave = _.bind(this._onSuggestionMouseLeave, this);
661
- this.$menu = $(o.menu).on("click.tt", ".typeahead-suggestion", onSuggestionClick).on("mouseenter.tt", ".typeahead-suggestion", onSuggestionMouseEnter).on("mouseleave.tt", ".typeahead-suggestion", onSuggestionMouseLeave);
662
- _.each(this.datasets, function(dataset) {
663
- that.$menu.append(dataset.getRoot());
664
- dataset.onSync("rendered", that._onRendered, that);
665
- });
666
- }
667
- _.mixin(Dropdown.prototype, EventEmitter, {
668
- _onSuggestionClick: function onSuggestionClick($e) {
669
- this.trigger("suggestionClicked", $($e.currentTarget));
670
- },
671
- _onSuggestionMouseEnter: function onSuggestionMouseEnter($e) {
672
- this._removeCursor();
673
- this._setCursor($($e.currentTarget), true);
674
- },
675
- _onSuggestionMouseLeave: function onSuggestionMouseLeave($e) {
676
- this._removeCursor();
677
- },
678
- _onRendered: function onRendered() {
679
- this.isEmpty = _.every(this.datasets, isDatasetEmpty);
680
- this.isEmpty ? this._hide() : this.isOpen && this._show();
681
- this.trigger("datasetRendered");
682
- function isDatasetEmpty(dataset) {
683
- return dataset.isEmpty();
684
- }
685
- },
686
- _hide: function() {
687
- this.$menu.hide();
688
- },
689
- _show: function() {
690
- this.$menu.css("display", "block");
691
- },
692
- _getSuggestions: function getSuggestions() {
693
- return this.$menu.find(".typeahead-suggestion");
694
- },
695
- _getCursor: function getCursor() {
696
- return this.$menu.find(".typeahead-cursor").first();
697
- },
698
- _setCursor: function setCursor($el, silent) {
699
- $el.first().addClass("typeahead-cursor");
700
- !silent && this.trigger("cursorMoved");
701
- },
702
- _removeCursor: function removeCursor() {
703
- this._getCursor().removeClass("typeahead-cursor");
704
- },
705
- _moveCursor: function moveCursor(increment) {
706
- var $suggestions, $oldCursor, newCursorIndex, $newCursor;
707
- if (!this.isOpen) {
708
- return;
709
- }
710
- $oldCursor = this._getCursor();
711
- $suggestions = this._getSuggestions();
712
- this._removeCursor();
713
- newCursorIndex = $suggestions.index($oldCursor) + increment;
714
- newCursorIndex = (newCursorIndex + 1) % ($suggestions.length + 1) - 1;
715
- if (newCursorIndex === -1) {
716
- this.trigger("cursorRemoved");
717
- return;
718
- } else if (newCursorIndex < -1) {
719
- newCursorIndex = $suggestions.length - 1;
720
- }
721
- this._setCursor($newCursor = $suggestions.eq(newCursorIndex));
722
- this._ensureVisible($newCursor);
723
- },
724
- _ensureVisible: function ensureVisible($el) {
725
- var elTop, elBottom, menuScrollTop, menuHeight;
726
- elTop = $el.position().top;
727
- elBottom = elTop + $el.outerHeight(true);
728
- menuScrollTop = this.$menu.scrollTop();
729
- menuHeight = this.$menu.height() + parseInt(this.$menu.css("paddingTop"), 10) + parseInt(this.$menu.css("paddingBottom"), 10);
730
- if (elTop < 0) {
731
- this.$menu.scrollTop(menuScrollTop + elTop);
732
- } else if (menuHeight < elBottom) {
733
- this.$menu.scrollTop(menuScrollTop + (elBottom - menuHeight));
734
- }
735
- },
736
- close: function close() {
737
- if (this.isOpen) {
738
- this.isOpen = false;
739
- this._removeCursor();
740
- this._hide();
741
- this.trigger("closed");
742
- }
743
- },
744
- open: function open() {
745
- if (!this.isOpen) {
746
- this.isOpen = true;
747
- !this.isEmpty && this._show();
748
- this.trigger("opened");
749
- }
750
- },
751
- setLanguageDirection: function setLanguageDirection(dir) {
752
- this.$menu.css(dir === "ltr" ? css.ltr : css.rtl);
753
- },
754
- moveCursorUp: function moveCursorUp() {
755
- this._moveCursor(-1);
756
- },
757
- moveCursorDown: function moveCursorDown() {
758
- this._moveCursor(+1);
759
- },
760
- getDatumForSuggestion: function getDatumForSuggestion($el) {
761
- var datum = null;
762
- if ($el.length) {
763
- datum = {
764
- raw: Dataset.extractDatum($el),
765
- value: Dataset.extractValue($el),
766
- datasetName: Dataset.extractDatasetName($el)
767
- };
768
- }
769
- return datum;
770
- },
771
- getDatumForCursor: function getDatumForCursor() {
772
- return this.getDatumForSuggestion(this._getCursor().first());
773
- },
774
- getDatumForTopSuggestion: function getDatumForTopSuggestion() {
775
- return this.getDatumForSuggestion(this._getSuggestions().first());
776
- },
777
- update: function update(query) {
778
- _.each(this.datasets, updateDataset);
779
- function updateDataset(dataset) {
780
- dataset.update(query);
781
- }
782
- },
783
- empty: function empty() {
784
- _.each(this.datasets, clearDataset);
785
- this.isEmpty = true;
786
- function clearDataset(dataset) {
787
- dataset.clear();
788
- }
789
- },
790
- isVisible: function isVisible() {
791
- return this.isOpen && !this.isEmpty;
792
- },
793
- destroy: function destroy() {
794
- this.$menu.off(".tt");
795
- this.$menu = null;
796
- _.each(this.datasets, destroyDataset);
797
- function destroyDataset(dataset) {
798
- dataset.destroy();
799
- }
800
- }
801
- });
802
- return Dropdown;
803
- function initializeDataset(oDataset) {
804
- return new Dataset(oDataset);
805
- }
806
- }();
807
- var Typeahead = function() {
808
- var attrsKey = "ttAttrs";
809
- function Typeahead(o) {
810
- var $menu, $input, $hint, datasets;
811
- o = o || {};
812
- if (!o.input) {
813
- $.error("missing input");
814
- }
815
- this.autoselect = !!o.autoselect;
816
- this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;
817
- this.$node = buildDomStructure(o.input, o.withHint);
818
- $menu = this.$node.find(".typeahead-dropdown-menu");
819
- $input = this.$node.find(".typeahead-input");
820
- $hint = this.$node.find(".typeahead-hint");
821
- this.eventBus = o.eventBus || new EventBus({
822
- el: $input
823
- });
824
- this.dropdown = new Dropdown({
825
- menu: $menu,
826
- datasets: o.datasets
827
- }).onSync("suggestionClicked", this._onSuggestionClicked, this).onSync("cursorMoved", this._onCursorMoved, this).onSync("cursorRemoved", this._onCursorRemoved, this).onSync("opened", this._onOpened, this).onSync("closed", this._onClosed, this).onAsync("datasetRendered", this._onDatasetRendered, this);
828
- this.input = new Input({
829
- input: $input,
830
- hint: $hint
831
- }).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);
832
- $menu.on("mousedown.tt", function($e) {
833
- if (_.isMsie() && _.isMsie() < 9) {
834
- $input[0].onbeforedeactivate = function() {
835
- window.event.returnValue = false;
836
- $input[0].onbeforedeactivate = null;
837
- };
838
- }
839
- $e.preventDefault();
840
- });
841
- }
842
- _.mixin(Typeahead.prototype, {
843
- _onSuggestionClicked: function onSuggestionClicked(type, $el) {
844
- var datum;
845
- if (datum = this.dropdown.getDatumForSuggestion($el)) {
846
- this._select(datum);
847
- }
848
- },
849
- _onCursorMoved: function onCursorMoved() {
850
- var datum = this.dropdown.getDatumForCursor();
851
- this.input.clearHint();
852
- this.input.setInputValue(datum.value, true);
853
- this.eventBus.trigger("cursorchanged", datum.raw, datum.datasetName);
854
- },
855
- _onCursorRemoved: function onCursorRemoved() {
856
- this.input.resetInputValue();
857
- this._updateHint();
858
- },
859
- _onDatasetRendered: function onDatasetRendered() {
860
- this._updateHint();
861
- },
862
- _onOpened: function onOpened() {
863
- this._updateHint();
864
- this.eventBus.trigger("opened");
865
- },
866
- _onClosed: function onClosed() {
867
- this.input.clearHint();
868
- this.eventBus.trigger("closed");
869
- },
870
- _onFocused: function onFocused() {
871
- this.dropdown.empty();
872
- this.dropdown.open();
873
- },
874
- _onBlurred: function onBlurred() {
875
- this.dropdown.close();
876
- },
877
- _onEnterKeyed: function onEnterKeyed(type, $e) {
878
- var cursorDatum, topSuggestionDatum;
879
- cursorDatum = this.dropdown.getDatumForCursor();
880
- topSuggestionDatum = this.dropdown.getDatumForTopSuggestion();
881
- if (cursorDatum) {
882
- this._select(cursorDatum);
883
- $e.preventDefault();
884
- } else if (this.autoselect && topSuggestionDatum) {
885
- this._select(topSuggestionDatum);
886
- $e.preventDefault();
887
- }
888
- },
889
- _onTabKeyed: function onTabKeyed(type, $e) {
890
- var datum;
891
- if (datum = this.dropdown.getDatumForCursor()) {
892
- this._select(datum);
893
- $e.preventDefault();
894
- } else {
895
- this._autocomplete();
896
- }
897
- },
898
- _onEscKeyed: function onEscKeyed() {
899
- this.dropdown.close();
900
- this.input.resetInputValue();
901
- },
902
- _onUpKeyed: function onUpKeyed() {
903
- var query = this.input.getQuery();
904
- if (!this.dropdown.isOpen && query.length >= this.minLength) {
905
- this.dropdown.update(query);
906
- }
907
- this.dropdown.open();
908
- this.dropdown.moveCursorUp();
909
- },
910
- _onDownKeyed: function onDownKeyed() {
911
- var query = this.input.getQuery();
912
- if (!this.dropdown.isOpen && query.length >= this.minLength) {
913
- this.dropdown.update(query);
914
- }
915
- this.dropdown.open();
916
- this.dropdown.moveCursorDown();
917
- },
918
- _onLeftKeyed: function onLeftKeyed() {
919
- this.dir === "rtl" && this._autocomplete();
920
- },
921
- _onRightKeyed: function onRightKeyed() {
922
- this.dir === "ltr" && this._autocomplete();
923
- },
924
- _onQueryChanged: function onQueryChanged(e, query) {
925
- this.input.clearHint();
926
- this.dropdown.empty();
927
- query.length >= this.minLength && this.dropdown.update(query);
928
- this.dropdown.open();
929
- this._setLanguageDirection();
930
- },
931
- _onWhitespaceChanged: function onWhitespaceChanged() {
932
- this._updateHint();
933
- this.dropdown.open();
934
- },
935
- _setLanguageDirection: function setLanguageDirection() {
936
- var dir;
937
- if (this.dir !== (dir = this.input.getLanguageDirection())) {
938
- this.dir = dir;
939
- this.$node.css("direction", dir);
940
- this.dropdown.setLanguageDirection(dir);
941
- }
942
- },
943
- _updateHint: function updateHint() {
944
- var datum, inputValue, query, escapedQuery, frontMatchRegEx, match;
945
- datum = this.dropdown.getDatumForTopSuggestion();
946
- if (datum && this.dropdown.isVisible() && !this.input.hasOverflow()) {
947
- inputValue = this.input.getInputValue();
948
- query = Input.normalizeQuery(inputValue);
949
- escapedQuery = _.escapeRegExChars(query);
950
- frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.*$)", "i");
951
- match = frontMatchRegEx.exec(datum.value);
952
- this.input.setHintValue(inputValue + (match ? match[1] : ""));
953
- }
954
- },
955
- _autocomplete: function autocomplete() {
956
- var hint, query, datum;
957
- hint = this.input.getHintValue();
958
- query = this.input.getQuery();
959
- if (hint && query !== hint && this.input.isCursorAtEnd()) {
960
- datum = this.dropdown.getDatumForTopSuggestion();
961
- datum && this.input.setInputValue(datum.value);
962
- this.eventBus.trigger("autocompleted", datum.raw, datum.datasetName);
963
- }
964
- },
965
- _select: function select(datum) {
966
- this.input.clearHint();
967
- this.input.setQuery(datum.value);
968
- this.input.setInputValue(datum.value, true);
969
- this._setLanguageDirection();
970
- this.eventBus.trigger("selected", datum.raw, datum.datasetName);
971
- this.dropdown.close();
972
- _.defer(_.bind(this.dropdown.empty, this.dropdown));
973
- },
974
- open: function open() {
975
- this.dropdown.open();
976
- },
977
- close: function close() {
978
- this.dropdown.close();
979
- },
980
- getQuery: function getQuery() {
981
- return this.input.getQuery();
982
- },
983
- setQuery: function setQuery(val) {
984
- this.input.setInputValue(val);
985
- },
986
- destroy: function destroy() {
987
- this.input.destroy();
988
- this.dropdown.destroy();
989
- destroyDomStructure(this.$node);
990
- this.$node = null;
991
- }
992
- });
993
- return Typeahead;
994
- function buildDomStructure(input, withHint) {
995
- var $input, $wrapper, $dropdown, $hint;
996
- $input = $(input);
997
- $wrapper = $(html.wrapper).css(css.wrapper);
998
- $dropdown = $(html.dropdown).css(css.dropdown);
999
- $hint = $input.clone().css(css.hint).css(getBackgroundStyles($input));
1000
- $hint.val("").removeData().addClass("typeahead-hint").removeAttr("id name placeholder").prop("disabled", true).attr({
1001
- autocomplete: "off",
1002
- spellcheck: "false"
1003
- });
1004
- $input.data(attrsKey, {
1005
- dir: $input.attr("dir"),
1006
- autocomplete: $input.attr("autocomplete"),
1007
- spellcheck: $input.attr("spellcheck"),
1008
- style: $input.attr("style")
1009
- });
1010
- $input.addClass("typeahead-input").attr({
1011
- autocomplete: "off",
1012
- spellcheck: false
1013
- }).css(withHint ? css.input : css.inputWithNoHint);
1014
- try {
1015
- !$input.attr("dir") && $input.attr("dir", "auto");
1016
- } catch (e) {}
1017
- return $input.wrap($wrapper).parent().prepend(withHint ? $hint : null).append($dropdown);
1018
- }
1019
- function getBackgroundStyles($el) {
1020
- return {
1021
- backgroundAttachment: $el.css("background-attachment"),
1022
- backgroundClip: $el.css("background-clip"),
1023
- backgroundColor: $el.css("background-color"),
1024
- backgroundImage: $el.css("background-image"),
1025
- backgroundOrigin: $el.css("background-origin"),
1026
- backgroundPosition: $el.css("background-position"),
1027
- backgroundRepeat: $el.css("background-repeat"),
1028
- backgroundSize: $el.css("background-size")
1029
- };
43
+
44
+ , setSource: function (source) {
45
+ this.source = source;
46
+ }
47
+
48
+ , show: function () {
49
+ var pos = $.extend({}, this.$element.position(), {
50
+ height: this.$element[0].offsetHeight
51
+ }), scrollHeight;
52
+
53
+ scrollHeight = typeof this.options.scrollHeight == 'function' ?
54
+ this.options.scrollHeight.call() :
55
+ this.options.scrollHeight;
56
+
57
+ this.$menu
58
+ .insertAfter(this.$element)
59
+ .css({
60
+ top: pos.top + pos.height + scrollHeight
61
+ , left: pos.left
62
+ })
63
+ .show();
64
+
65
+ this.shown = true;
66
+ return this;
67
+ }
68
+
69
+ , hide: function () {
70
+ this.$menu.hide();
71
+ this.shown = false;
72
+ return this;
73
+ }
74
+
75
+ , lookup: function (query) {
76
+ var items;
77
+ if (typeof(query) != 'undefined' && query !== null) {
78
+ this.query = query;
79
+ } else {
80
+ this.query = this.$element.val() || '';
81
+ }
82
+
83
+ if (this.query.length < this.options.minLength) {
84
+ return this.shown ? this.hide() : this;
85
+ }
86
+
87
+ items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source;
88
+
89
+ return items ? this.process(items) : this;
90
+ }
91
+
92
+ , process: function (items) {
93
+ var that = this;
94
+
95
+ items = $.grep(items, function (item) {
96
+ return that.matcher(item);
97
+ });
98
+
99
+ items = this.sorter(items);
100
+
101
+ if (!items.length) {
102
+ return this.shown ? this.hide() : this;
103
+ }
104
+
105
+ if (this.options.items == 'all' || this.options.minLength === 0 && !this.$element.val()) {
106
+ return this.render(items).show();
107
+ } else {
108
+ return this.render(items.slice(0, this.options.items)).show();
109
+ }
110
+ }
111
+
112
+ , matcher: function (item) {
113
+ return ~item.toLowerCase().indexOf(this.query.toLowerCase());
114
+ }
115
+
116
+ , sorter: function (items) {
117
+ var beginswith = []
118
+ , caseSensitive = []
119
+ , caseInsensitive = []
120
+ , item;
121
+
122
+ while ((item = items.shift())) {
123
+ if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item);
124
+ else if (~item.indexOf(this.query)) caseSensitive.push(item);
125
+ else caseInsensitive.push(item);
126
+ }
127
+
128
+ return beginswith.concat(caseSensitive, caseInsensitive);
129
+ }
130
+
131
+ , highlighter: function (item) {
132
+ var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
133
+ return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
134
+ return '<b>' + match + '</b>';
135
+ });
136
+ }
137
+
138
+ , render: function (items) {
139
+ var that = this;
140
+
141
+ items = $(items).map(function (i, item) {
142
+ i = $(that.options.item).data('value', item);
143
+ i.find('a').html(that.highlighter(item));
144
+ return i[0];
145
+ });
146
+
147
+ if (this.autoSelect) {
148
+ items.first().addClass('active');
149
+ }
150
+ this.$menu.html(items);
151
+ return this;
152
+ }
153
+
154
+ , next: function (event) {
155
+ var active = this.$menu.find('.active').removeClass('active')
156
+ , next = active.next();
157
+
158
+ if (!next.length) {
159
+ next = $(this.$menu.find('li')[0]);
160
+ }
161
+
162
+ next.addClass('active');
163
+ }
164
+
165
+ , prev: function (event) {
166
+ var active = this.$menu.find('.active').removeClass('active')
167
+ , prev = active.prev();
168
+
169
+ if (!prev.length) {
170
+ prev = this.$menu.find('li').last();
171
+ }
172
+
173
+ prev.addClass('active');
174
+ }
175
+
176
+ , listen: function () {
177
+ this.$element
178
+ .on('focus', $.proxy(this.focus, this))
179
+ .on('blur', $.proxy(this.blur, this))
180
+ .on('keypress', $.proxy(this.keypress, this))
181
+ .on('keyup', $.proxy(this.keyup, this));
182
+
183
+ if (this.eventSupported('keydown')) {
184
+ this.$element.on('keydown', $.proxy(this.keydown, this));
185
+ }
186
+
187
+ this.$menu
188
+ .on('click', $.proxy(this.click, this))
189
+ .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
190
+ .on('mouseleave', 'li', $.proxy(this.mouseleave, this));
191
+ }
192
+ , destroy : function () {
193
+ this.$element.data('typeahead',null);
194
+ this.$element
195
+ .off('focus')
196
+ .off('blur')
197
+ .off('keypress')
198
+ .off('keyup');
199
+
200
+ if (this.eventSupported('keydown')) {
201
+ this.$element.off('keydown');
202
+ }
203
+
204
+ this.$menu.remove();
205
+ }
206
+ , eventSupported: function(eventName) {
207
+ var isSupported = eventName in this.$element;
208
+ if (!isSupported) {
209
+ this.$element.setAttribute(eventName, 'return;');
210
+ isSupported = typeof this.$element[eventName] === 'function';
211
+ }
212
+ return isSupported;
213
+ }
214
+
215
+ , move: function (e) {
216
+ if (!this.shown) return;
217
+
218
+ switch(e.keyCode) {
219
+ case 9: // tab
220
+ case 13: // enter
221
+ case 27: // escape
222
+ e.preventDefault();
223
+ break;
224
+
225
+ case 38: // up arrow
226
+ e.preventDefault();
227
+ this.prev();
228
+ break;
229
+
230
+ case 40: // down arrow
231
+ e.preventDefault();
232
+ this.next();
233
+ break;
234
+ }
235
+
236
+ e.stopPropagation();
237
+ }
238
+
239
+ , keydown: function (e) {
240
+ this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]);
241
+ if (!this.shown && e.keyCode == 40) {
242
+ this.lookup("");
243
+ } else {
244
+ this.move(e);
245
+ }
246
+ }
247
+
248
+ , keypress: function (e) {
249
+ if (this.suppressKeyPressRepeat) return;
250
+ this.move(e);
251
+ }
252
+
253
+ , keyup: function (e) {
254
+ switch(e.keyCode) {
255
+ case 40: // down arrow
256
+ case 38: // up arrow
257
+ case 16: // shift
258
+ case 17: // ctrl
259
+ case 18: // alt
260
+ break;
261
+
262
+ case 9: // tab
263
+ case 13: // enter
264
+ if (!this.shown) return;
265
+ this.select();
266
+ break;
267
+
268
+ case 27: // escape
269
+ if (!this.shown) return;
270
+ this.hide();
271
+ break;
272
+ default:
273
+ this.lookup();
274
+ }
275
+
276
+ e.stopPropagation();
277
+ e.preventDefault();
278
+ }
279
+
280
+ , focus: function (e) {
281
+ if (!this.focused) {
282
+ this.focused = true;
283
+ if (this.options.minLength === 0 && !this.$element.val() || this.options.showHintOnFocus) {
284
+ this.lookup();
1030
285
  }
1031
- function destroyDomStructure($node) {
1032
- var $input = $node.find(".typeahead-input");
1033
- _.each($input.data(attrsKey), function(val, key) {
1034
- _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val);
1035
- });
1036
- $input.detach().removeData(attrsKey).removeClass("typeahead-input").insertAfter($node);
1037
- $node.remove();
286
+ }
287
+ }
288
+
289
+ , blur: function (e) {
290
+ this.focused = false;
291
+ if (!this.mousedover && this.shown) this.hide();
292
+ }
293
+
294
+ , click: function (e) {
295
+ e.stopPropagation();
296
+ e.preventDefault();
297
+ this.select();
298
+ this.$element.focus();
299
+ }
300
+
301
+ , mouseenter: function (e) {
302
+ this.mousedover = true;
303
+ this.$menu.find('.active').removeClass('active');
304
+ $(e.currentTarget).addClass('active');
305
+ }
306
+
307
+ , mouseleave: function (e) {
308
+ this.mousedover = false;
309
+ if (!this.focused && this.shown) this.hide();
310
+ }
311
+
312
+ };
313
+
314
+
315
+ /* TYPEAHEAD PLUGIN DEFINITION
316
+ * =========================== */
317
+
318
+ var old = $.fn.typeahead;
319
+
320
+ $.fn.typeahead = function (option) {
321
+ var arg = arguments;
322
+ return this.each(function () {
323
+ var $this = $(this)
324
+ , data = $this.data('typeahead')
325
+ , options = typeof option == 'object' && option;
326
+ if (!data) $this.data('typeahead', (data = new Typeahead(this, options)));
327
+ if (typeof option == 'string') {
328
+ if (arg.length > 1) {
329
+ data[option].apply(data, Array.prototype.slice.call(arg ,1));
330
+ } else {
331
+ data[option]();
1038
332
  }
1039
- }();
1040
- (function() {
1041
- var old, typeaheadKey, methods;
1042
- old = $.fn.typeahead;
1043
- typeaheadKey = "ttTypeahead";
1044
- methods = {
1045
- initialize: function initialize(o, datasets) {
1046
- datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1);
1047
- o = o || {};
1048
- return this.each(attach);
1049
- function attach() {
1050
- var $input = $(this), eventBus, typeahead;
1051
- _.each(datasets, function(d) {
1052
- d.highlight = !!o.highlight;
1053
- });
1054
- typeahead = new Typeahead({
1055
- input: $input,
1056
- eventBus: eventBus = new EventBus({
1057
- el: $input
1058
- }),
1059
- withHint: _.isUndefined(o.hint) ? true : !!o.hint,
1060
- minLength: o.minLength,
1061
- autoselect: o.autoselect,
1062
- datasets: datasets
1063
- });
1064
- $input.data(typeaheadKey, typeahead);
1065
- }
1066
- },
1067
- open: function open() {
1068
- return this.each(openTypeahead);
1069
- function openTypeahead() {
1070
- var $input = $(this), typeahead;
1071
- if (typeahead = $input.data(typeaheadKey)) {
1072
- typeahead.open();
1073
- }
1074
- }
1075
- },
1076
- close: function close() {
1077
- return this.each(closeTypeahead);
1078
- function closeTypeahead() {
1079
- var $input = $(this), typeahead;
1080
- if (typeahead = $input.data(typeaheadKey)) {
1081
- typeahead.close();
1082
- }
1083
- }
1084
- },
1085
- val: function val(newVal) {
1086
- return !arguments.length ? getQuery(this.first()) : this.each(setQuery);
1087
- function setQuery() {
1088
- var $input = $(this), typeahead;
1089
- if (typeahead = $input.data(typeaheadKey)) {
1090
- typeahead.setQuery(newVal);
1091
- }
1092
- }
1093
- function getQuery($input) {
1094
- var typeahead, query;
1095
- if (typeahead = $input.data(typeaheadKey)) {
1096
- query = typeahead.getQuery();
1097
- }
1098
- return query;
1099
- }
1100
- },
1101
- destroy: function destroy() {
1102
- return this.each(unattach);
1103
- function unattach() {
1104
- var $input = $(this), typeahead;
1105
- if (typeahead = $input.data(typeaheadKey)) {
1106
- typeahead.destroy();
1107
- $input.removeData(typeaheadKey);
1108
- }
1109
- }
1110
- }
1111
- };
1112
- $.fn.typeahead = function(method) {
1113
- if (methods[method]) {
1114
- return methods[method].apply(this, [].slice.call(arguments, 1));
1115
- } else {
1116
- return methods.initialize.apply(this, arguments);
1117
- }
1118
- };
1119
- $.fn.typeahead.noConflict = function noConflict() {
1120
- $.fn.typeahead = old;
1121
- return this;
1122
- };
1123
- })();
1124
- })(window.jQuery);
333
+ }
334
+ });
335
+ };
336
+
337
+ $.fn.typeahead.defaults = {
338
+ source: []
339
+ , items: 8
340
+ , menu: '<ul class="typeahead dropdown-menu"></ul>'
341
+ , item: '<li><a href="#"></a></li>'
342
+ , minLength: 1
343
+ , scrollHeight: 0
344
+ , autoSelect: true
345
+ };
346
+
347
+ $.fn.typeahead.Constructor = Typeahead;
348
+
349
+
350
+ /* TYPEAHEAD NO CONFLICT
351
+ * =================== */
352
+
353
+ $.fn.typeahead.noConflict = function () {
354
+ $.fn.typeahead = old;
355
+ return this;
356
+ };
357
+
358
+
359
+ /* TYPEAHEAD DATA-API
360
+ * ================== */
361
+
362
+ $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
363
+ var $this = $(this);
364
+ if ($this.data('typeahead')) return;
365
+ $this.typeahead($this.data());
366
+ });
367
+
368
+ }(window.jQuery);