ucb_rails_user 6.1.0 → 6.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1538 @@
1
+ /*!
2
+ * typeahead.js 0.11.1
3
+ * https://github.com/twitter/typeahead.js
4
+ * Copyright 2013-2015 Twitter, Inc. and other contributors; Licensed MIT
5
+ */
6
+
7
+ /* hacked on by Darin Wilson to make it more ESM-friendly */
8
+
9
+ var _ = function() {
10
+ "use strict";
11
+ return {
12
+ isMsie: function() {
13
+ return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
14
+ },
15
+ isBlankString: function(str) {
16
+ return !str || /^\s*$/.test(str);
17
+ },
18
+ escapeRegExChars: function(str) {
19
+ return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
20
+ },
21
+ isString: function(obj) {
22
+ return typeof obj === "string";
23
+ },
24
+ isNumber: function(obj) {
25
+ return typeof obj === "number";
26
+ },
27
+ isArray: $.isArray,
28
+ isFunction: $.isFunction,
29
+ isObject: $.isPlainObject,
30
+ isUndefined: function(obj) {
31
+ return typeof obj === "undefined";
32
+ },
33
+ isElement: function(obj) {
34
+ return !!(obj && obj.nodeType === 1);
35
+ },
36
+ isJQuery: function(obj) {
37
+ return obj instanceof $;
38
+ },
39
+ toStr: function toStr(s) {
40
+ return _.isUndefined(s) || s === null ? "" : s + "";
41
+ },
42
+ bind: $.proxy,
43
+ each: function(collection, cb) {
44
+ $.each(collection, reverseArgs);
45
+ function reverseArgs(index, value) {
46
+ return cb(value, index);
47
+ }
48
+ },
49
+ map: $.map,
50
+ filter: $.grep,
51
+ every: function(obj, test) {
52
+ var result = true;
53
+ if (!obj) {
54
+ return result;
55
+ }
56
+ $.each(obj, function(key, val) {
57
+ if (!(result = test.call(null, val, key, obj))) {
58
+ return false;
59
+ }
60
+ });
61
+ return !!result;
62
+ },
63
+ some: function(obj, test) {
64
+ var result = false;
65
+ if (!obj) {
66
+ return result;
67
+ }
68
+ $.each(obj, function(key, val) {
69
+ if (result = test.call(null, val, key, obj)) {
70
+ return false;
71
+ }
72
+ });
73
+ return !!result;
74
+ },
75
+ mixin: $.extend,
76
+ identity: function(x) {
77
+ return x;
78
+ },
79
+ clone: function(obj) {
80
+ return $.extend(true, {}, obj);
81
+ },
82
+ getIdGenerator: function() {
83
+ var counter = 0;
84
+ return function() {
85
+ return counter++;
86
+ };
87
+ },
88
+ templatify: function templatify(obj) {
89
+ return $.isFunction(obj) ? obj : template;
90
+ function template() {
91
+ return String(obj);
92
+ }
93
+ },
94
+ defer: function(fn) {
95
+ setTimeout(fn, 0);
96
+ },
97
+ debounce: function(func, wait, immediate) {
98
+ var timeout, result;
99
+ return function() {
100
+ var context = this, args = arguments, later, callNow;
101
+ later = function() {
102
+ timeout = null;
103
+ if (!immediate) {
104
+ result = func.apply(context, args);
105
+ }
106
+ };
107
+ callNow = immediate && !timeout;
108
+ clearTimeout(timeout);
109
+ timeout = setTimeout(later, wait);
110
+ if (callNow) {
111
+ result = func.apply(context, args);
112
+ }
113
+ return result;
114
+ };
115
+ },
116
+ throttle: function(func, wait) {
117
+ var context, args, timeout, result, previous, later;
118
+ previous = 0;
119
+ later = function() {
120
+ previous = new Date();
121
+ timeout = null;
122
+ result = func.apply(context, args);
123
+ };
124
+ return function() {
125
+ var now = new Date(), remaining = wait - (now - previous);
126
+ context = this;
127
+ args = arguments;
128
+ if (remaining <= 0) {
129
+ clearTimeout(timeout);
130
+ timeout = null;
131
+ previous = now;
132
+ result = func.apply(context, args);
133
+ } else if (!timeout) {
134
+ timeout = setTimeout(later, remaining);
135
+ }
136
+ return result;
137
+ };
138
+ },
139
+ stringify: function(val) {
140
+ return _.isString(val) ? val : JSON.stringify(val);
141
+ },
142
+ noop: function() {}
143
+ };
144
+ }();
145
+
146
+ var WWW = function() {
147
+ "use strict";
148
+ var defaultClassNames = {
149
+ wrapper: "twitter-typeahead",
150
+ input: "tt-input",
151
+ hint: "tt-hint",
152
+ menu: "tt-menu",
153
+ dataset: "tt-dataset",
154
+ suggestion: "tt-suggestion",
155
+ selectable: "tt-selectable",
156
+ empty: "tt-empty",
157
+ open: "tt-open",
158
+ cursor: "tt-cursor",
159
+ highlight: "tt-highlight"
160
+ };
161
+ return build;
162
+ function build(o) {
163
+ var www, classes;
164
+ classes = _.mixin({}, defaultClassNames, o);
165
+ www = {
166
+ css: buildCss(),
167
+ classes: classes,
168
+ html: buildHtml(classes),
169
+ selectors: buildSelectors(classes)
170
+ };
171
+ return {
172
+ css: www.css,
173
+ html: www.html,
174
+ classes: www.classes,
175
+ selectors: www.selectors,
176
+ mixin: function(o) {
177
+ _.mixin(o, www);
178
+ }
179
+ };
180
+ }
181
+ function buildHtml(c) {
182
+ return {
183
+ wrapper: '<span class="' + c.wrapper + '"></span>',
184
+ menu: '<div class="' + c.menu + '"></div>'
185
+ };
186
+ }
187
+ function buildSelectors(classes) {
188
+ var selectors = {};
189
+ _.each(classes, function(v, k) {
190
+ selectors[k] = "." + v;
191
+ });
192
+ return selectors;
193
+ }
194
+ function buildCss() {
195
+ var css = {
196
+ wrapper: {
197
+ position: "relative",
198
+ display: "inline-block"
199
+ },
200
+ hint: {
201
+ position: "absolute",
202
+ top: "0",
203
+ left: "0",
204
+ borderColor: "transparent",
205
+ boxShadow: "none",
206
+ opacity: "1"
207
+ },
208
+ input: {
209
+ position: "relative",
210
+ verticalAlign: "top",
211
+ backgroundColor: "transparent"
212
+ },
213
+ inputWithNoHint: {
214
+ position: "relative",
215
+ verticalAlign: "top"
216
+ },
217
+ menu: {
218
+ position: "absolute",
219
+ top: "100%",
220
+ left: "0",
221
+ zIndex: "100",
222
+ display: "none"
223
+ },
224
+ ltr: {
225
+ left: "0",
226
+ right: "auto"
227
+ },
228
+ rtl: {
229
+ left: "auto",
230
+ right: " 0"
231
+ }
232
+ };
233
+ if (_.isMsie()) {
234
+ _.mixin(css.input, {
235
+ backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"
236
+ });
237
+ }
238
+ return css;
239
+ }
240
+ }();
241
+
242
+ var EventBus = function() {
243
+ "use strict";
244
+ var namespace, deprecationMap;
245
+ namespace = "typeahead:";
246
+ deprecationMap = {
247
+ render: "rendered",
248
+ cursorchange: "cursorchanged",
249
+ select: "selected",
250
+ autocomplete: "autocompleted"
251
+ };
252
+ function EventBus(o) {
253
+ if (!o || !o.el) {
254
+ $.error("EventBus initialized without el");
255
+ }
256
+ this.$el = $(o.el);
257
+ }
258
+ _.mixin(EventBus.prototype, {
259
+ _trigger: function(type, args) {
260
+ var $e;
261
+ $e = $.Event(namespace + type);
262
+ (args = args || []).unshift($e);
263
+ this.$el.trigger.apply(this.$el, args);
264
+ return $e;
265
+ },
266
+ before: function(type) {
267
+ var args, $e;
268
+ args = [].slice.call(arguments, 1);
269
+ $e = this._trigger("before" + type, args);
270
+ return $e.isDefaultPrevented();
271
+ },
272
+ trigger: function(type) {
273
+ var deprecatedType;
274
+ this._trigger(type, [].slice.call(arguments, 1));
275
+ if (deprecatedType = deprecationMap[type]) {
276
+ this._trigger(deprecatedType, [].slice.call(arguments, 1));
277
+ }
278
+ }
279
+ });
280
+ return EventBus;
281
+ }();
282
+
283
+ var EventEmitter = function() {
284
+ "use strict";
285
+ var splitter = /\s+/, nextTick = getNextTick();
286
+ return {
287
+ onSync: onSync,
288
+ onAsync: onAsync,
289
+ off: off,
290
+ trigger: trigger
291
+ };
292
+ function on(method, types, cb, context) {
293
+ var type;
294
+ if (!cb) {
295
+ return this;
296
+ }
297
+ types = types.split(splitter);
298
+ cb = context ? bindContext(cb, context) : cb;
299
+ this._callbacks = this._callbacks || {};
300
+ while (type = types.shift()) {
301
+ this._callbacks[type] = this._callbacks[type] || {
302
+ sync: [],
303
+ async: []
304
+ };
305
+ this._callbacks[type][method].push(cb);
306
+ }
307
+ return this;
308
+ }
309
+ function onAsync(types, cb, context) {
310
+ return on.call(this, "async", types, cb, context);
311
+ }
312
+ function onSync(types, cb, context) {
313
+ return on.call(this, "sync", types, cb, context);
314
+ }
315
+ function off(types) {
316
+ var type;
317
+ if (!this._callbacks) {
318
+ return this;
319
+ }
320
+ types = types.split(splitter);
321
+ while (type = types.shift()) {
322
+ delete this._callbacks[type];
323
+ }
324
+ return this;
325
+ }
326
+ function trigger(types) {
327
+ var type, callbacks, args, syncFlush, asyncFlush;
328
+ if (!this._callbacks) {
329
+ return this;
330
+ }
331
+ types = types.split(splitter);
332
+ args = [].slice.call(arguments, 1);
333
+ while ((type = types.shift()) && (callbacks = this._callbacks[type])) {
334
+ syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args));
335
+ asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args));
336
+ syncFlush() && nextTick(asyncFlush);
337
+ }
338
+ return this;
339
+ }
340
+ function getFlush(callbacks, context, args) {
341
+ return flush;
342
+ function flush() {
343
+ var cancelled;
344
+ for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) {
345
+ cancelled = callbacks[i].apply(context, args) === false;
346
+ }
347
+ return !cancelled;
348
+ }
349
+ }
350
+ function getNextTick() {
351
+ var nextTickFn;
352
+ if (window.setImmediate) {
353
+ nextTickFn = function nextTickSetImmediate(fn) {
354
+ setImmediate(function() {
355
+ fn();
356
+ });
357
+ };
358
+ } else {
359
+ nextTickFn = function nextTickSetTimeout(fn) {
360
+ setTimeout(function() {
361
+ fn();
362
+ }, 0);
363
+ };
364
+ }
365
+ return nextTickFn;
366
+ }
367
+ function bindContext(fn, context) {
368
+ return fn.bind ? fn.bind(context) : function() {
369
+ fn.apply(context, [].slice.call(arguments, 0));
370
+ };
371
+ }
372
+ }();
373
+
374
+ var highlight = function(doc) {
375
+ "use strict";
376
+ var defaults = {
377
+ node: null,
378
+ pattern: null,
379
+ tagName: "strong",
380
+ className: null,
381
+ wordsOnly: false,
382
+ caseSensitive: false
383
+ };
384
+ return function hightlight(o) {
385
+ var regex;
386
+ o = _.mixin({}, defaults, o);
387
+ if (!o.node || !o.pattern) {
388
+ return;
389
+ }
390
+ o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ];
391
+ regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly);
392
+ traverse(o.node, hightlightTextNode);
393
+ function hightlightTextNode(textNode) {
394
+ var match, patternNode, wrapperNode;
395
+ if (match = regex.exec(textNode.data)) {
396
+ wrapperNode = doc.createElement(o.tagName);
397
+ o.className && (wrapperNode.className = o.className);
398
+ patternNode = textNode.splitText(match.index);
399
+ patternNode.splitText(match[0].length);
400
+ wrapperNode.appendChild(patternNode.cloneNode(true));
401
+ textNode.parentNode.replaceChild(wrapperNode, patternNode);
402
+ }
403
+ return !!match;
404
+ }
405
+ function traverse(el, hightlightTextNode) {
406
+ var childNode, TEXT_NODE_TYPE = 3;
407
+ for (var i = 0; i < el.childNodes.length; i++) {
408
+ childNode = el.childNodes[i];
409
+ if (childNode.nodeType === TEXT_NODE_TYPE) {
410
+ i += hightlightTextNode(childNode) ? 1 : 0;
411
+ } else {
412
+ traverse(childNode, hightlightTextNode);
413
+ }
414
+ }
415
+ }
416
+ };
417
+ function getRegex(patterns, caseSensitive, wordsOnly) {
418
+ var escapedPatterns = [], regexStr;
419
+ for (var i = 0, len = patterns.length; i < len; i++) {
420
+ escapedPatterns.push(_.escapeRegExChars(patterns[i]));
421
+ }
422
+ regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")";
423
+ return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i");
424
+ }
425
+ }(window.document);
426
+
427
+ var Input = function() {
428
+ "use strict";
429
+ var specialKeyCodeMap;
430
+ specialKeyCodeMap = {
431
+ 9: "tab",
432
+ 27: "esc",
433
+ 37: "left",
434
+ 39: "right",
435
+ 13: "enter",
436
+ 38: "up",
437
+ 40: "down"
438
+ };
439
+ function Input(o, www) {
440
+ o = o || {};
441
+ if (!o.input) {
442
+ $.error("input is missing");
443
+ }
444
+ www.mixin(this);
445
+ this.$hint = $(o.hint);
446
+ this.$input = $(o.input);
447
+ this.query = this.$input.val();
448
+ this.queryWhenFocused = this.hasFocus() ? this.query : null;
449
+ this.$overflowHelper = buildOverflowHelper(this.$input);
450
+ this._checkLanguageDirection();
451
+ if (this.$hint.length === 0) {
452
+ this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop;
453
+ }
454
+ }
455
+ Input.normalizeQuery = function(str) {
456
+ return _.toStr(str).replace(/^\s*/g, "").replace(/\s{2,}/g, " ");
457
+ };
458
+ _.mixin(Input.prototype, EventEmitter, {
459
+ _onBlur: function onBlur() {
460
+ this.resetInputValue();
461
+ this.trigger("blurred");
462
+ },
463
+ _onFocus: function onFocus() {
464
+ this.queryWhenFocused = this.query;
465
+ this.trigger("focused");
466
+ },
467
+ _onKeydown: function onKeydown($e) {
468
+ var keyName = specialKeyCodeMap[$e.which || $e.keyCode];
469
+ this._managePreventDefault(keyName, $e);
470
+ if (keyName && this._shouldTrigger(keyName, $e)) {
471
+ this.trigger(keyName + "Keyed", $e);
472
+ }
473
+ },
474
+ _onInput: function onInput() {
475
+ this._setQuery(this.getInputValue());
476
+ this.clearHintIfInvalid();
477
+ this._checkLanguageDirection();
478
+ },
479
+ _managePreventDefault: function managePreventDefault(keyName, $e) {
480
+ var preventDefault;
481
+ switch (keyName) {
482
+ case "up":
483
+ case "down":
484
+ preventDefault = !withModifier($e);
485
+ break;
486
+
487
+ default:
488
+ preventDefault = false;
489
+ }
490
+ preventDefault && $e.preventDefault();
491
+ },
492
+ _shouldTrigger: function shouldTrigger(keyName, $e) {
493
+ var trigger;
494
+ switch (keyName) {
495
+ case "tab":
496
+ trigger = !withModifier($e);
497
+ break;
498
+
499
+ default:
500
+ trigger = true;
501
+ }
502
+ return trigger;
503
+ },
504
+ _checkLanguageDirection: function checkLanguageDirection() {
505
+ var dir = (this.$input.css("direction") || "ltr").toLowerCase();
506
+ if (this.dir !== dir) {
507
+ this.dir = dir;
508
+ this.$hint.attr("dir", dir);
509
+ this.trigger("langDirChanged", dir);
510
+ }
511
+ },
512
+ _setQuery: function setQuery(val, silent) {
513
+ var areEquivalent, hasDifferentWhitespace;
514
+ areEquivalent = areQueriesEquivalent(val, this.query);
515
+ hasDifferentWhitespace = areEquivalent ? this.query.length !== val.length : false;
516
+ this.query = val;
517
+ if (!silent && !areEquivalent) {
518
+ this.trigger("queryChanged", this.query);
519
+ } else if (!silent && hasDifferentWhitespace) {
520
+ this.trigger("whitespaceChanged", this.query);
521
+ }
522
+ },
523
+ bind: function() {
524
+ var that = this, onBlur, onFocus, onKeydown, onInput;
525
+ onBlur = _.bind(this._onBlur, this);
526
+ onFocus = _.bind(this._onFocus, this);
527
+ onKeydown = _.bind(this._onKeydown, this);
528
+ onInput = _.bind(this._onInput, this);
529
+ this.$input.on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown);
530
+ if (!_.isMsie() || _.isMsie() > 9) {
531
+ this.$input.on("input.tt", onInput);
532
+ } else {
533
+ this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) {
534
+ if (specialKeyCodeMap[$e.which || $e.keyCode]) {
535
+ return;
536
+ }
537
+ _.defer(_.bind(that._onInput, that, $e));
538
+ });
539
+ }
540
+ return this;
541
+ },
542
+ focus: function focus() {
543
+ this.$input.focus();
544
+ },
545
+ blur: function blur() {
546
+ this.$input.blur();
547
+ },
548
+ getLangDir: function getLangDir() {
549
+ return this.dir;
550
+ },
551
+ getQuery: function getQuery() {
552
+ return this.query || "";
553
+ },
554
+ setQuery: function setQuery(val, silent) {
555
+ this.setInputValue(val);
556
+ this._setQuery(val, silent);
557
+ },
558
+ hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() {
559
+ return this.query !== this.queryWhenFocused;
560
+ },
561
+ getInputValue: function getInputValue() {
562
+ return this.$input.val();
563
+ },
564
+ setInputValue: function setInputValue(value) {
565
+ this.$input.val(value);
566
+ this.clearHintIfInvalid();
567
+ this._checkLanguageDirection();
568
+ },
569
+ resetInputValue: function resetInputValue() {
570
+ this.setInputValue(this.query);
571
+ },
572
+ getHint: function getHint() {
573
+ return this.$hint.val();
574
+ },
575
+ setHint: function setHint(value) {
576
+ this.$hint.val(value);
577
+ },
578
+ clearHint: function clearHint() {
579
+ this.setHint("");
580
+ },
581
+ clearHintIfInvalid: function clearHintIfInvalid() {
582
+ var val, hint, valIsPrefixOfHint, isValid;
583
+ val = this.getInputValue();
584
+ hint = this.getHint();
585
+ valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;
586
+ isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow();
587
+ !isValid && this.clearHint();
588
+ },
589
+ hasFocus: function hasFocus() {
590
+ return this.$input.is(":focus");
591
+ },
592
+ hasOverflow: function hasOverflow() {
593
+ var constraint = this.$input.width() - 2;
594
+ this.$overflowHelper.text(this.getInputValue());
595
+ return this.$overflowHelper.width() >= constraint;
596
+ },
597
+ isCursorAtEnd: function() {
598
+ var valueLength, selectionStart, range;
599
+ valueLength = this.$input.val().length;
600
+ selectionStart = this.$input[0].selectionStart;
601
+ if (_.isNumber(selectionStart)) {
602
+ return selectionStart === valueLength;
603
+ } else if (document.selection) {
604
+ range = document.selection.createRange();
605
+ range.moveStart("character", -valueLength);
606
+ return valueLength === range.text.length;
607
+ }
608
+ return true;
609
+ },
610
+ destroy: function destroy() {
611
+ this.$hint.off(".tt");
612
+ this.$input.off(".tt");
613
+ this.$overflowHelper.remove();
614
+ this.$hint = this.$input = this.$overflowHelper = $("<div>");
615
+ }
616
+ });
617
+ return Input;
618
+ function buildOverflowHelper($input) {
619
+ return $('<pre aria-hidden="true"></pre>').css({
620
+ position: "absolute",
621
+ visibility: "hidden",
622
+ whiteSpace: "pre",
623
+ fontFamily: $input.css("font-family"),
624
+ fontSize: $input.css("font-size"),
625
+ fontStyle: $input.css("font-style"),
626
+ fontVariant: $input.css("font-variant"),
627
+ fontWeight: $input.css("font-weight"),
628
+ wordSpacing: $input.css("word-spacing"),
629
+ letterSpacing: $input.css("letter-spacing"),
630
+ textIndent: $input.css("text-indent"),
631
+ textRendering: $input.css("text-rendering"),
632
+ textTransform: $input.css("text-transform")
633
+ }).insertAfter($input);
634
+ }
635
+ function areQueriesEquivalent(a, b) {
636
+ return Input.normalizeQuery(a) === Input.normalizeQuery(b);
637
+ }
638
+ function withModifier($e) {
639
+ return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;
640
+ }
641
+ }();
642
+
643
+ var Dataset = function() {
644
+ "use strict";
645
+ var keys, nameGenerator;
646
+ keys = {
647
+ val: "tt-selectable-display",
648
+ obj: "tt-selectable-object"
649
+ };
650
+ nameGenerator = _.getIdGenerator();
651
+ function Dataset(o, www) {
652
+ o = o || {};
653
+ o.templates = o.templates || {};
654
+ o.templates.notFound = o.templates.notFound || o.templates.empty;
655
+ if (!o.source) {
656
+ $.error("missing source");
657
+ }
658
+ if (!o.node) {
659
+ $.error("missing node");
660
+ }
661
+ if (o.name && !isValidName(o.name)) {
662
+ $.error("invalid dataset name: " + o.name);
663
+ }
664
+ www.mixin(this);
665
+ this.highlight = !!o.highlight;
666
+ this.name = o.name || nameGenerator();
667
+ this.limit = o.limit || 5;
668
+ this.displayFn = getDisplayFn(o.display || o.displayKey);
669
+ this.templates = getTemplates(o.templates, this.displayFn);
670
+ this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source;
671
+ this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async;
672
+ this._resetLastSuggestion();
673
+ this.$el = $(o.node).addClass(this.classes.dataset).addClass(this.classes.dataset + "-" + this.name);
674
+ }
675
+ Dataset.extractData = function extractData(el) {
676
+ var $el = $(el);
677
+ if ($el.data(keys.obj)) {
678
+ return {
679
+ val: $el.data(keys.val) || "",
680
+ obj: $el.data(keys.obj) || null
681
+ };
682
+ }
683
+ return null;
684
+ };
685
+ _.mixin(Dataset.prototype, EventEmitter, {
686
+ _overwrite: function overwrite(query, suggestions) {
687
+ suggestions = suggestions || [];
688
+ if (suggestions.length) {
689
+ this._renderSuggestions(query, suggestions);
690
+ } else if (this.async && this.templates.pending) {
691
+ this._renderPending(query);
692
+ } else if (!this.async && this.templates.notFound) {
693
+ this._renderNotFound(query);
694
+ } else {
695
+ this._empty();
696
+ }
697
+ this.trigger("rendered", this.name, suggestions, false);
698
+ },
699
+ _append: function append(query, suggestions) {
700
+ suggestions = suggestions || [];
701
+ if (suggestions.length && this.$lastSuggestion.length) {
702
+ this._appendSuggestions(query, suggestions);
703
+ } else if (suggestions.length) {
704
+ this._renderSuggestions(query, suggestions);
705
+ } else if (!this.$lastSuggestion.length && this.templates.notFound) {
706
+ this._renderNotFound(query);
707
+ }
708
+ this.trigger("rendered", this.name, suggestions, true);
709
+ },
710
+ _renderSuggestions: function renderSuggestions(query, suggestions) {
711
+ var $fragment;
712
+ $fragment = this._getSuggestionsFragment(query, suggestions);
713
+ this.$lastSuggestion = $fragment.children().last();
714
+ this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions));
715
+ },
716
+ _appendSuggestions: function appendSuggestions(query, suggestions) {
717
+ var $fragment, $lastSuggestion;
718
+ $fragment = this._getSuggestionsFragment(query, suggestions);
719
+ $lastSuggestion = $fragment.children().last();
720
+ this.$lastSuggestion.after($fragment);
721
+ this.$lastSuggestion = $lastSuggestion;
722
+ },
723
+ _renderPending: function renderPending(query) {
724
+ var template = this.templates.pending;
725
+ this._resetLastSuggestion();
726
+ template && this.$el.html(template({
727
+ query: query,
728
+ dataset: this.name
729
+ }));
730
+ },
731
+ _renderNotFound: function renderNotFound(query) {
732
+ var template = this.templates.notFound;
733
+ this._resetLastSuggestion();
734
+ template && this.$el.html(template({
735
+ query: query,
736
+ dataset: this.name
737
+ }));
738
+ },
739
+ _empty: function empty() {
740
+ this.$el.empty();
741
+ this._resetLastSuggestion();
742
+ },
743
+ _getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) {
744
+ var that = this, fragment;
745
+ fragment = document.createDocumentFragment();
746
+ _.each(suggestions, function getSuggestionNode(suggestion) {
747
+ var $el, context;
748
+ context = that._injectQuery(query, suggestion);
749
+ $el = $(that.templates.suggestion(context)).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + " " + that.classes.selectable);
750
+ fragment.appendChild($el[0]);
751
+ });
752
+ this.highlight && highlight({
753
+ className: this.classes.highlight,
754
+ node: fragment,
755
+ pattern: query
756
+ });
757
+ return $(fragment);
758
+ },
759
+ _getFooter: function getFooter(query, suggestions) {
760
+ return this.templates.footer ? this.templates.footer({
761
+ query: query,
762
+ suggestions: suggestions,
763
+ dataset: this.name
764
+ }) : null;
765
+ },
766
+ _getHeader: function getHeader(query, suggestions) {
767
+ return this.templates.header ? this.templates.header({
768
+ query: query,
769
+ suggestions: suggestions,
770
+ dataset: this.name
771
+ }) : null;
772
+ },
773
+ _resetLastSuggestion: function resetLastSuggestion() {
774
+ this.$lastSuggestion = $();
775
+ },
776
+ _injectQuery: function injectQuery(query, obj) {
777
+ return _.isObject(obj) ? _.mixin({
778
+ _query: query
779
+ }, obj) : obj;
780
+ },
781
+ update: function update(query) {
782
+ var that = this, canceled = false, syncCalled = false, rendered = 0;
783
+ this.cancel();
784
+ this.cancel = function cancel() {
785
+ canceled = true;
786
+ that.cancel = $.noop;
787
+ that.async && that.trigger("asyncCanceled", query);
788
+ };
789
+ this.source(query, sync, async);
790
+ !syncCalled && sync([]);
791
+ function sync(suggestions) {
792
+ if (syncCalled) {
793
+ return;
794
+ }
795
+ syncCalled = true;
796
+ suggestions = (suggestions || []).slice(0, that.limit);
797
+ rendered = suggestions.length;
798
+ that._overwrite(query, suggestions);
799
+ if (rendered < that.limit && that.async) {
800
+ that.trigger("asyncRequested", query);
801
+ }
802
+ }
803
+ function async(suggestions) {
804
+ suggestions = suggestions || [];
805
+ if (!canceled && rendered < that.limit) {
806
+ that.cancel = $.noop;
807
+ rendered += suggestions.length;
808
+ that._append(query, suggestions.slice(0, that.limit - rendered));
809
+ that.async && that.trigger("asyncReceived", query);
810
+ }
811
+ }
812
+ },
813
+ cancel: $.noop,
814
+ clear: function clear() {
815
+ this._empty();
816
+ this.cancel();
817
+ this.trigger("cleared");
818
+ },
819
+ isEmpty: function isEmpty() {
820
+ return this.$el.is(":empty");
821
+ },
822
+ destroy: function destroy() {
823
+ this.$el = $("<div>");
824
+ }
825
+ });
826
+ return Dataset;
827
+ function getDisplayFn(display) {
828
+ display = display || _.stringify;
829
+ return _.isFunction(display) ? display : displayFn;
830
+ function displayFn(obj) {
831
+ return obj[display];
832
+ }
833
+ }
834
+ function getTemplates(templates, displayFn) {
835
+ return {
836
+ notFound: templates.notFound && _.templatify(templates.notFound),
837
+ pending: templates.pending && _.templatify(templates.pending),
838
+ header: templates.header && _.templatify(templates.header),
839
+ footer: templates.footer && _.templatify(templates.footer),
840
+ suggestion: templates.suggestion || suggestionTemplate
841
+ };
842
+ function suggestionTemplate(context) {
843
+ return $("<div>").text(displayFn(context));
844
+ }
845
+ }
846
+ function isValidName(str) {
847
+ return /^[_a-zA-Z0-9-]+$/.test(str);
848
+ }
849
+ }();
850
+
851
+ var Menu = function() {
852
+ "use strict";
853
+ function Menu(o, www) {
854
+ var that = this;
855
+ o = o || {};
856
+ if (!o.node) {
857
+ $.error("node is required");
858
+ }
859
+ www.mixin(this);
860
+ this.$node = $(o.node);
861
+ this.query = null;
862
+ this.datasets = _.map(o.datasets, initializeDataset);
863
+ function initializeDataset(oDataset) {
864
+ var node = that.$node.find(oDataset.node).first();
865
+ oDataset.node = node.length ? node : $("<div>").appendTo(that.$node);
866
+ return new Dataset(oDataset, www);
867
+ }
868
+ }
869
+ _.mixin(Menu.prototype, EventEmitter, {
870
+ _onSelectableClick: function onSelectableClick($e) {
871
+ this.trigger("selectableClicked", $($e.currentTarget));
872
+ },
873
+ _onRendered: function onRendered(type, dataset, suggestions, async) {
874
+ this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());
875
+ this.trigger("datasetRendered", dataset, suggestions, async);
876
+ },
877
+ _onCleared: function onCleared() {
878
+ this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());
879
+ this.trigger("datasetCleared");
880
+ },
881
+ _propagate: function propagate() {
882
+ this.trigger.apply(this, arguments);
883
+ },
884
+ _allDatasetsEmpty: function allDatasetsEmpty() {
885
+ return _.every(this.datasets, isDatasetEmpty);
886
+ function isDatasetEmpty(dataset) {
887
+ return dataset.isEmpty();
888
+ }
889
+ },
890
+ _getSelectables: function getSelectables() {
891
+ return this.$node.find(this.selectors.selectable);
892
+ },
893
+ _removeCursor: function _removeCursor() {
894
+ var $selectable = this.getActiveSelectable();
895
+ $selectable && $selectable.removeClass(this.classes.cursor);
896
+ },
897
+ _ensureVisible: function ensureVisible($el) {
898
+ var elTop, elBottom, nodeScrollTop, nodeHeight;
899
+ elTop = $el.position().top;
900
+ elBottom = elTop + $el.outerHeight(true);
901
+ nodeScrollTop = this.$node.scrollTop();
902
+ nodeHeight = this.$node.height() + parseInt(this.$node.css("paddingTop"), 10) + parseInt(this.$node.css("paddingBottom"), 10);
903
+ if (elTop < 0) {
904
+ this.$node.scrollTop(nodeScrollTop + elTop);
905
+ } else if (nodeHeight < elBottom) {
906
+ this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight));
907
+ }
908
+ },
909
+ bind: function() {
910
+ var that = this, onSelectableClick;
911
+ onSelectableClick = _.bind(this._onSelectableClick, this);
912
+ this.$node.on("click.tt", this.selectors.selectable, onSelectableClick);
913
+ _.each(this.datasets, function(dataset) {
914
+ dataset.onSync("asyncRequested", that._propagate, that).onSync("asyncCanceled", that._propagate, that).onSync("asyncReceived", that._propagate, that).onSync("rendered", that._onRendered, that).onSync("cleared", that._onCleared, that);
915
+ });
916
+ return this;
917
+ },
918
+ isOpen: function isOpen() {
919
+ return this.$node.hasClass(this.classes.open);
920
+ },
921
+ open: function open() {
922
+ this.$node.addClass(this.classes.open);
923
+ },
924
+ close: function close() {
925
+ this.$node.removeClass(this.classes.open);
926
+ this._removeCursor();
927
+ },
928
+ setLanguageDirection: function setLanguageDirection(dir) {
929
+ this.$node.attr("dir", dir);
930
+ },
931
+ selectableRelativeToCursor: function selectableRelativeToCursor(delta) {
932
+ var $selectables, $oldCursor, oldIndex, newIndex;
933
+ $oldCursor = this.getActiveSelectable();
934
+ $selectables = this._getSelectables();
935
+ oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1;
936
+ newIndex = oldIndex + delta;
937
+ newIndex = (newIndex + 1) % ($selectables.length + 1) - 1;
938
+ newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex;
939
+ return newIndex === -1 ? null : $selectables.eq(newIndex);
940
+ },
941
+ setCursor: function setCursor($selectable) {
942
+ this._removeCursor();
943
+ if ($selectable = $selectable && $selectable.first()) {
944
+ $selectable.addClass(this.classes.cursor);
945
+ this._ensureVisible($selectable);
946
+ }
947
+ },
948
+ getSelectableData: function getSelectableData($el) {
949
+ return $el && $el.length ? Dataset.extractData($el) : null;
950
+ },
951
+ getActiveSelectable: function getActiveSelectable() {
952
+ var $selectable = this._getSelectables().filter(this.selectors.cursor).first();
953
+ return $selectable.length ? $selectable : null;
954
+ },
955
+ getTopSelectable: function getTopSelectable() {
956
+ var $selectable = this._getSelectables().first();
957
+ return $selectable.length ? $selectable : null;
958
+ },
959
+ update: function update(query) {
960
+ var isValidUpdate = query !== this.query;
961
+ if (isValidUpdate) {
962
+ this.query = query;
963
+ _.each(this.datasets, updateDataset);
964
+ }
965
+ return isValidUpdate;
966
+ function updateDataset(dataset) {
967
+ dataset.update(query);
968
+ }
969
+ },
970
+ empty: function empty() {
971
+ _.each(this.datasets, clearDataset);
972
+ this.query = null;
973
+ this.$node.addClass(this.classes.empty);
974
+ function clearDataset(dataset) {
975
+ dataset.clear();
976
+ }
977
+ },
978
+ destroy: function destroy() {
979
+ this.$node.off(".tt");
980
+ this.$node = $("<div>");
981
+ _.each(this.datasets, destroyDataset);
982
+ function destroyDataset(dataset) {
983
+ dataset.destroy();
984
+ }
985
+ }
986
+ });
987
+ return Menu;
988
+ }();
989
+
990
+ var DefaultMenu = function() {
991
+ "use strict";
992
+ var s = Menu.prototype;
993
+ function DefaultMenu() {
994
+ Menu.apply(this, [].slice.call(arguments, 0));
995
+ }
996
+ _.mixin(DefaultMenu.prototype, Menu.prototype, {
997
+ open: function open() {
998
+ !this._allDatasetsEmpty() && this._show();
999
+ return s.open.apply(this, [].slice.call(arguments, 0));
1000
+ },
1001
+ close: function close() {
1002
+ this._hide();
1003
+ return s.close.apply(this, [].slice.call(arguments, 0));
1004
+ },
1005
+ _onRendered: function onRendered() {
1006
+ if (this._allDatasetsEmpty()) {
1007
+ this._hide();
1008
+ } else {
1009
+ this.isOpen() && this._show();
1010
+ }
1011
+ return s._onRendered.apply(this, [].slice.call(arguments, 0));
1012
+ },
1013
+ _onCleared: function onCleared() {
1014
+ if (this._allDatasetsEmpty()) {
1015
+ this._hide();
1016
+ } else {
1017
+ this.isOpen() && this._show();
1018
+ }
1019
+ return s._onCleared.apply(this, [].slice.call(arguments, 0));
1020
+ },
1021
+ setLanguageDirection: function setLanguageDirection(dir) {
1022
+ this.$node.css(dir === "ltr" ? this.css.ltr : this.css.rtl);
1023
+ return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0));
1024
+ },
1025
+ _hide: function hide() {
1026
+ this.$node.hide();
1027
+ },
1028
+ _show: function show() {
1029
+ this.$node.css("display", "block");
1030
+ }
1031
+ });
1032
+ return DefaultMenu;
1033
+ }();
1034
+
1035
+ var Typeahead = function() {
1036
+ "use strict";
1037
+ function Typeahead(o, www) {
1038
+ var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged, onWhitespaceChanged;
1039
+ o = o || {};
1040
+ if (!o.input) {
1041
+ $.error("missing input");
1042
+ }
1043
+ if (!o.menu) {
1044
+ $.error("missing menu");
1045
+ }
1046
+ if (!o.eventBus) {
1047
+ $.error("missing event bus");
1048
+ }
1049
+ www.mixin(this);
1050
+ this.eventBus = o.eventBus;
1051
+ this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;
1052
+ this.input = o.input;
1053
+ this.menu = o.menu;
1054
+ this.enabled = true;
1055
+ this.active = false;
1056
+ this.input.hasFocus() && this.activate();
1057
+ this.dir = this.input.getLangDir();
1058
+ this._hacks();
1059
+ this.menu.bind().onSync("selectableClicked", this._onSelectableClicked, this).onSync("asyncRequested", this._onAsyncRequested, this).onSync("asyncCanceled", this._onAsyncCanceled, this).onSync("asyncReceived", this._onAsyncReceived, this).onSync("datasetRendered", this._onDatasetRendered, this).onSync("datasetCleared", this._onDatasetCleared, this);
1060
+ onFocused = c(this, "activate", "open", "_onFocused");
1061
+ onBlurred = c(this, "deactivate", "_onBlurred");
1062
+ onEnterKeyed = c(this, "isActive", "isOpen", "_onEnterKeyed");
1063
+ onTabKeyed = c(this, "isActive", "isOpen", "_onTabKeyed");
1064
+ onEscKeyed = c(this, "isActive", "_onEscKeyed");
1065
+ onUpKeyed = c(this, "isActive", "open", "_onUpKeyed");
1066
+ onDownKeyed = c(this, "isActive", "open", "_onDownKeyed");
1067
+ onLeftKeyed = c(this, "isActive", "isOpen", "_onLeftKeyed");
1068
+ onRightKeyed = c(this, "isActive", "isOpen", "_onRightKeyed");
1069
+ onQueryChanged = c(this, "_openIfActive", "_onQueryChanged");
1070
+ onWhitespaceChanged = c(this, "_openIfActive", "_onWhitespaceChanged");
1071
+ this.input.bind().onSync("focused", onFocused, this).onSync("blurred", onBlurred, this).onSync("enterKeyed", onEnterKeyed, this).onSync("tabKeyed", onTabKeyed, this).onSync("escKeyed", onEscKeyed, this).onSync("upKeyed", onUpKeyed, this).onSync("downKeyed", onDownKeyed, this).onSync("leftKeyed", onLeftKeyed, this).onSync("rightKeyed", onRightKeyed, this).onSync("queryChanged", onQueryChanged, this).onSync("whitespaceChanged", onWhitespaceChanged, this).onSync("langDirChanged", this._onLangDirChanged, this);
1072
+ }
1073
+ _.mixin(Typeahead.prototype, {
1074
+ _hacks: function hacks() {
1075
+ var $input, $menu;
1076
+ $input = this.input.$input || $("<div>");
1077
+ $menu = this.menu.$node || $("<div>");
1078
+ $input.on("blur.tt", function($e) {
1079
+ var active, isActive, hasActive;
1080
+ active = document.activeElement;
1081
+ isActive = $menu.is(active);
1082
+ hasActive = $menu.has(active).length > 0;
1083
+ if (_.isMsie() && (isActive || hasActive)) {
1084
+ $e.preventDefault();
1085
+ $e.stopImmediatePropagation();
1086
+ _.defer(function() {
1087
+ $input.focus();
1088
+ });
1089
+ }
1090
+ });
1091
+ $menu.on("mousedown.tt", function($e) {
1092
+ $e.preventDefault();
1093
+ });
1094
+ },
1095
+ _onSelectableClicked: function onSelectableClicked(type, $el) {
1096
+ this.select($el);
1097
+ },
1098
+ _onDatasetCleared: function onDatasetCleared() {
1099
+ this._updateHint();
1100
+ },
1101
+ _onDatasetRendered: function onDatasetRendered(type, dataset, suggestions, async) {
1102
+ this._updateHint();
1103
+ this.eventBus.trigger("render", suggestions, async, dataset);
1104
+ },
1105
+ _onAsyncRequested: function onAsyncRequested(type, dataset, query) {
1106
+ this.eventBus.trigger("asyncrequest", query, dataset);
1107
+ },
1108
+ _onAsyncCanceled: function onAsyncCanceled(type, dataset, query) {
1109
+ this.eventBus.trigger("asynccancel", query, dataset);
1110
+ },
1111
+ _onAsyncReceived: function onAsyncReceived(type, dataset, query) {
1112
+ this.eventBus.trigger("asyncreceive", query, dataset);
1113
+ },
1114
+ _onFocused: function onFocused() {
1115
+ this._minLengthMet() && this.menu.update(this.input.getQuery());
1116
+ },
1117
+ _onBlurred: function onBlurred() {
1118
+ if (this.input.hasQueryChangedSinceLastFocus()) {
1119
+ this.eventBus.trigger("change", this.input.getQuery());
1120
+ }
1121
+ },
1122
+ _onEnterKeyed: function onEnterKeyed(type, $e) {
1123
+ var $selectable;
1124
+ if ($selectable = this.menu.getActiveSelectable()) {
1125
+ this.select($selectable) && $e.preventDefault();
1126
+ }
1127
+ },
1128
+ _onTabKeyed: function onTabKeyed(type, $e) {
1129
+ var $selectable;
1130
+ if ($selectable = this.menu.getActiveSelectable()) {
1131
+ this.select($selectable) && $e.preventDefault();
1132
+ } else if ($selectable = this.menu.getTopSelectable()) {
1133
+ this.autocomplete($selectable) && $e.preventDefault();
1134
+ }
1135
+ },
1136
+ _onEscKeyed: function onEscKeyed() {
1137
+ this.close();
1138
+ },
1139
+ _onUpKeyed: function onUpKeyed() {
1140
+ this.moveCursor(-1);
1141
+ },
1142
+ _onDownKeyed: function onDownKeyed() {
1143
+ this.moveCursor(+1);
1144
+ },
1145
+ _onLeftKeyed: function onLeftKeyed() {
1146
+ if (this.dir === "rtl" && this.input.isCursorAtEnd()) {
1147
+ this.autocomplete(this.menu.getTopSelectable());
1148
+ }
1149
+ },
1150
+ _onRightKeyed: function onRightKeyed() {
1151
+ if (this.dir === "ltr" && this.input.isCursorAtEnd()) {
1152
+ this.autocomplete(this.menu.getTopSelectable());
1153
+ }
1154
+ },
1155
+ _onQueryChanged: function onQueryChanged(e, query) {
1156
+ this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty();
1157
+ },
1158
+ _onWhitespaceChanged: function onWhitespaceChanged() {
1159
+ this._updateHint();
1160
+ },
1161
+ _onLangDirChanged: function onLangDirChanged(e, dir) {
1162
+ if (this.dir !== dir) {
1163
+ this.dir = dir;
1164
+ this.menu.setLanguageDirection(dir);
1165
+ }
1166
+ },
1167
+ _openIfActive: function openIfActive() {
1168
+ this.isActive() && this.open();
1169
+ },
1170
+ _minLengthMet: function minLengthMet(query) {
1171
+ query = _.isString(query) ? query : this.input.getQuery() || "";
1172
+ return query.length >= this.minLength;
1173
+ },
1174
+ _updateHint: function updateHint() {
1175
+ var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match;
1176
+ $selectable = this.menu.getTopSelectable();
1177
+ data = this.menu.getSelectableData($selectable);
1178
+ val = this.input.getInputValue();
1179
+ if (data && !_.isBlankString(val) && !this.input.hasOverflow()) {
1180
+ query = Input.normalizeQuery(val);
1181
+ escapedQuery = _.escapeRegExChars(query);
1182
+ frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i");
1183
+ match = frontMatchRegEx.exec(data.val);
1184
+ match && this.input.setHint(val + match[1]);
1185
+ } else {
1186
+ this.input.clearHint();
1187
+ }
1188
+ },
1189
+ isEnabled: function isEnabled() {
1190
+ return this.enabled;
1191
+ },
1192
+ enable: function enable() {
1193
+ this.enabled = true;
1194
+ },
1195
+ disable: function disable() {
1196
+ this.enabled = false;
1197
+ },
1198
+ isActive: function isActive() {
1199
+ return this.active;
1200
+ },
1201
+ activate: function activate() {
1202
+ if (this.isActive()) {
1203
+ return true;
1204
+ } else if (!this.isEnabled() || this.eventBus.before("active")) {
1205
+ return false;
1206
+ } else {
1207
+ this.active = true;
1208
+ this.eventBus.trigger("active");
1209
+ return true;
1210
+ }
1211
+ },
1212
+ deactivate: function deactivate() {
1213
+ if (!this.isActive()) {
1214
+ return true;
1215
+ } else if (this.eventBus.before("idle")) {
1216
+ return false;
1217
+ } else {
1218
+ this.active = false;
1219
+ this.close();
1220
+ this.eventBus.trigger("idle");
1221
+ return true;
1222
+ }
1223
+ },
1224
+ isOpen: function isOpen() {
1225
+ return this.menu.isOpen();
1226
+ },
1227
+ open: function open() {
1228
+ if (!this.isOpen() && !this.eventBus.before("open")) {
1229
+ this.menu.open();
1230
+ this._updateHint();
1231
+ this.eventBus.trigger("open");
1232
+ }
1233
+ return this.isOpen();
1234
+ },
1235
+ close: function close() {
1236
+ if (this.isOpen() && !this.eventBus.before("close")) {
1237
+ this.menu.close();
1238
+ this.input.clearHint();
1239
+ this.input.resetInputValue();
1240
+ this.eventBus.trigger("close");
1241
+ }
1242
+ return !this.isOpen();
1243
+ },
1244
+ setVal: function setVal(val) {
1245
+ this.input.setQuery(_.toStr(val));
1246
+ },
1247
+ getVal: function getVal() {
1248
+ return this.input.getQuery();
1249
+ },
1250
+ select: function select($selectable) {
1251
+ var data = this.menu.getSelectableData($selectable);
1252
+ if (data && !this.eventBus.before("select", data.obj)) {
1253
+ this.input.setQuery(data.val, true);
1254
+ this.eventBus.trigger("select", data.obj);
1255
+ this.close();
1256
+ return true;
1257
+ }
1258
+ return false;
1259
+ },
1260
+ autocomplete: function autocomplete($selectable) {
1261
+ var query, data, isValid;
1262
+ query = this.input.getQuery();
1263
+ data = this.menu.getSelectableData($selectable);
1264
+ isValid = data && query !== data.val;
1265
+ if (isValid && !this.eventBus.before("autocomplete", data.obj)) {
1266
+ this.input.setQuery(data.val);
1267
+ this.eventBus.trigger("autocomplete", data.obj);
1268
+ return true;
1269
+ }
1270
+ return false;
1271
+ },
1272
+ moveCursor: function moveCursor(delta) {
1273
+ var query, $candidate, data, payload, cancelMove;
1274
+ query = this.input.getQuery();
1275
+ $candidate = this.menu.selectableRelativeToCursor(delta);
1276
+ data = this.menu.getSelectableData($candidate);
1277
+ payload = data ? data.obj : null;
1278
+ cancelMove = this._minLengthMet() && this.menu.update(query);
1279
+ if (!cancelMove && !this.eventBus.before("cursorchange", payload)) {
1280
+ this.menu.setCursor($candidate);
1281
+ if (data) {
1282
+ this.input.setInputValue(data.val);
1283
+ } else {
1284
+ this.input.resetInputValue();
1285
+ this._updateHint();
1286
+ }
1287
+ this.eventBus.trigger("cursorchange", payload);
1288
+ return true;
1289
+ }
1290
+ return false;
1291
+ },
1292
+ destroy: function destroy() {
1293
+ this.input.destroy();
1294
+ this.menu.destroy();
1295
+ }
1296
+ });
1297
+ return Typeahead;
1298
+ function c(ctx) {
1299
+ var methods = [].slice.call(arguments, 1);
1300
+ return function() {
1301
+ var args = [].slice.call(arguments);
1302
+ _.each(methods, function(method) {
1303
+ return ctx[method].apply(ctx, args);
1304
+ });
1305
+ };
1306
+ }
1307
+ }();
1308
+
1309
+ (function() {
1310
+ "use strict";
1311
+ var old, keys, methods;
1312
+ old = $.fn.typeahead;
1313
+ keys = {
1314
+ www: "tt-www",
1315
+ attrs: "tt-attrs",
1316
+ typeahead: "tt-typeahead"
1317
+ };
1318
+ methods = {
1319
+ initialize: function initialize(o, datasets) {
1320
+ var www;
1321
+ datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1);
1322
+ o = o || {};
1323
+ www = WWW(o.classNames);
1324
+ return this.each(attach);
1325
+ function attach() {
1326
+ var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, typeahead, MenuConstructor;
1327
+ _.each(datasets, function(d) {
1328
+ d.highlight = !!o.highlight;
1329
+ });
1330
+ $input = $(this);
1331
+ $wrapper = $(www.html.wrapper);
1332
+ $hint = $elOrNull(o.hint);
1333
+ $menu = $elOrNull(o.menu);
1334
+ defaultHint = o.hint !== false && !$hint;
1335
+ defaultMenu = o.menu !== false && !$menu;
1336
+ defaultHint && ($hint = buildHintFromInput($input, www));
1337
+ defaultMenu && ($menu = $(www.html.menu).css(www.css.menu));
1338
+ $hint && $hint.val("");
1339
+ $input = prepInput($input, www);
1340
+ if (defaultHint || defaultMenu) {
1341
+ $wrapper.css(www.css.wrapper);
1342
+ $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint);
1343
+ $input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null);
1344
+ }
1345
+ MenuConstructor = defaultMenu ? DefaultMenu : Menu;
1346
+ eventBus = new EventBus({
1347
+ el: $input
1348
+ });
1349
+ input = new Input({
1350
+ hint: $hint,
1351
+ input: $input
1352
+ }, www);
1353
+ menu = new MenuConstructor({
1354
+ node: $menu,
1355
+ datasets: datasets
1356
+ }, www);
1357
+ typeahead = new Typeahead({
1358
+ input: input,
1359
+ menu: menu,
1360
+ eventBus: eventBus,
1361
+ minLength: o.minLength
1362
+ }, www);
1363
+ $input.data(keys.www, www);
1364
+ $input.data(keys.typeahead, typeahead);
1365
+ }
1366
+ },
1367
+ isEnabled: function isEnabled() {
1368
+ var enabled;
1369
+ ttEach(this.first(), function(t) {
1370
+ enabled = t.isEnabled();
1371
+ });
1372
+ return enabled;
1373
+ },
1374
+ enable: function enable() {
1375
+ ttEach(this, function(t) {
1376
+ t.enable();
1377
+ });
1378
+ return this;
1379
+ },
1380
+ disable: function disable() {
1381
+ ttEach(this, function(t) {
1382
+ t.disable();
1383
+ });
1384
+ return this;
1385
+ },
1386
+ isActive: function isActive() {
1387
+ var active;
1388
+ ttEach(this.first(), function(t) {
1389
+ active = t.isActive();
1390
+ });
1391
+ return active;
1392
+ },
1393
+ activate: function activate() {
1394
+ ttEach(this, function(t) {
1395
+ t.activate();
1396
+ });
1397
+ return this;
1398
+ },
1399
+ deactivate: function deactivate() {
1400
+ ttEach(this, function(t) {
1401
+ t.deactivate();
1402
+ });
1403
+ return this;
1404
+ },
1405
+ isOpen: function isOpen() {
1406
+ var open;
1407
+ ttEach(this.first(), function(t) {
1408
+ open = t.isOpen();
1409
+ });
1410
+ return open;
1411
+ },
1412
+ open: function open() {
1413
+ ttEach(this, function(t) {
1414
+ t.open();
1415
+ });
1416
+ return this;
1417
+ },
1418
+ close: function close() {
1419
+ ttEach(this, function(t) {
1420
+ t.close();
1421
+ });
1422
+ return this;
1423
+ },
1424
+ select: function select(el) {
1425
+ var success = false, $el = $(el);
1426
+ ttEach(this.first(), function(t) {
1427
+ success = t.select($el);
1428
+ });
1429
+ return success;
1430
+ },
1431
+ autocomplete: function autocomplete(el) {
1432
+ var success = false, $el = $(el);
1433
+ ttEach(this.first(), function(t) {
1434
+ success = t.autocomplete($el);
1435
+ });
1436
+ return success;
1437
+ },
1438
+ moveCursor: function moveCursoe(delta) {
1439
+ var success = false;
1440
+ ttEach(this.first(), function(t) {
1441
+ success = t.moveCursor(delta);
1442
+ });
1443
+ return success;
1444
+ },
1445
+ val: function val(newVal) {
1446
+ var query;
1447
+ if (!arguments.length) {
1448
+ ttEach(this.first(), function(t) {
1449
+ query = t.getVal();
1450
+ });
1451
+ return query;
1452
+ } else {
1453
+ ttEach(this, function(t) {
1454
+ t.setVal(newVal);
1455
+ });
1456
+ return this;
1457
+ }
1458
+ },
1459
+ destroy: function destroy() {
1460
+ ttEach(this, function(typeahead, $input) {
1461
+ revert($input);
1462
+ typeahead.destroy();
1463
+ });
1464
+ return this;
1465
+ }
1466
+ };
1467
+ $.fn.typeahead = function(method) {
1468
+ if (methods[method]) {
1469
+ return methods[method].apply(this, [].slice.call(arguments, 1));
1470
+ } else {
1471
+ return methods.initialize.apply(this, arguments);
1472
+ }
1473
+ };
1474
+ $.fn.typeahead.noConflict = function noConflict() {
1475
+ $.fn.typeahead = old;
1476
+ return this;
1477
+ };
1478
+ function ttEach($els, fn) {
1479
+ $els.each(function() {
1480
+ var $input = $(this), typeahead;
1481
+ (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input);
1482
+ });
1483
+ }
1484
+ function buildHintFromInput($input, www) {
1485
+ return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop("readonly", true).removeAttr("id name placeholder required").attr({
1486
+ autocomplete: "off",
1487
+ spellcheck: "false",
1488
+ tabindex: -1
1489
+ });
1490
+ }
1491
+ function prepInput($input, www) {
1492
+ $input.data(keys.attrs, {
1493
+ dir: $input.attr("dir"),
1494
+ autocomplete: $input.attr("autocomplete"),
1495
+ spellcheck: $input.attr("spellcheck"),
1496
+ style: $input.attr("style")
1497
+ });
1498
+ $input.addClass(www.classes.input).attr({
1499
+ autocomplete: "off",
1500
+ spellcheck: false
1501
+ });
1502
+ try {
1503
+ !$input.attr("dir") && $input.attr("dir", "auto");
1504
+ } catch (e) {}
1505
+ return $input;
1506
+ }
1507
+ function getBackgroundStyles($el) {
1508
+ return {
1509
+ backgroundAttachment: $el.css("background-attachment"),
1510
+ backgroundClip: $el.css("background-clip"),
1511
+ backgroundColor: $el.css("background-color"),
1512
+ backgroundImage: $el.css("background-image"),
1513
+ backgroundOrigin: $el.css("background-origin"),
1514
+ backgroundPosition: $el.css("background-position"),
1515
+ backgroundRepeat: $el.css("background-repeat"),
1516
+ backgroundSize: $el.css("background-size")
1517
+ };
1518
+ }
1519
+ function revert($input) {
1520
+ var www, $wrapper;
1521
+ www = $input.data(keys.www);
1522
+ $wrapper = $input.parent().filter(www.selectors.wrapper);
1523
+ _.each($input.data(keys.attrs), function(val, key) {
1524
+ _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val);
1525
+ });
1526
+ $input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input);
1527
+ if ($wrapper.length) {
1528
+ $input.detach().insertAfter($wrapper);
1529
+ $wrapper.remove();
1530
+ }
1531
+ }
1532
+ function $elOrNull(obj) {
1533
+ var isValid, $el;
1534
+ isValid = _.isJQuery(obj) || _.isElement(obj);
1535
+ $el = isValid ? $(obj).first() : [];
1536
+ return $el.length ? $el : null;
1537
+ }
1538
+ })();