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