vendor: 5,833 bytes, lines 1-161
1/*! 2 * typeahead.js 1.2.0 3 * https://github.com/twitter/typeahead.js 4 * Copyright 2013-2017 Twitter, Inc. and other contributors; Licensed MIT 5 */ 6 7(function(root, factory) { 8 if (typeof define === "function" && define.amd) { 9 define([ "jquery" ], function(a0) { 10 return root["Bloodhound"] = factory(a0); 11 }); 12 } else if (typeof exports === "object") { 13 module.exports = factory(require("jquery")); 14 } else { 15 root["Bloodhound"] = factory(root["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 guid: function() { 152 function _p8(s) { 153 var p = (Math.random().toString(16) + "000000000").substr(2, 8); 154 return s ? "-" + p.substr(0, 4) + "-" + p.substr(4, 4) : p; 155 } 156 return "tt-" + _p8() + _p8(true) + _p8(true) + _p8(); 157 }, 158 noop: function() {} 159 }; 160 }(); 161 var VERSION = "1.2.0
vendor: 28,763 bytes, lines 161-952
161"; 162 var tokenizers = function() { 163 "use strict"; 164 return { 165 nonword: nonword, 166 whitespace: whitespace, 167 ngram: ngram, 168 obj: { 169 nonword: getObjTokenizer(nonword), 170 whitespace: getObjTokenizer(whitespace), 171 ngram: getObjTokenizer(ngram) 172 } 173 }; 174 function whitespace(str) { 175 str = _.toStr(str); 176 return str ? str.split(/\s+/) : []; 177 } 178 function nonword(str) { 179 str = _.toStr(str); 180 return str ? str.split(/\W+/) : []; 181 } 182 function ngram(str) { 183 str = _.toStr(str); 184 var tokens = [], word = ""; 185 _.each(str.split(""), function(char) { 186 if (char.match(/\s+/)) { 187 word = ""; 188 } else { 189 tokens.push(word + char); 190 word += char; 191 } 192 }); 193 return tokens; 194 } 195 function getObjTokenizer(tokenizer) { 196 return function setKey(keys) { 197 keys = _.isArray(keys) ? keys : [].slice.call(arguments, 0); 198 return function tokenize(o) { 199 var tokens = []; 200 _.each(keys, function(k) { 201 tokens = tokens.concat(tokenizer(_.toStr(o[k]))); 202 }); 203 return tokens; 204 }; 205 }; 206 } 207 }(); 208 var LruCache = function() { 209 "use strict"; 210 function LruCache(maxSize) { 211 this.maxSize = _.isNumber(maxSize) ? maxSize : 100; 212 this.reset(); 213 if (this.maxSize <= 0) { 214 this.set = this.get = $.noop; 215 } 216 } 217 _.mixin(LruCache.prototype, { 218 set: function set(key, val) { 219 var tailItem = this.list.tail, node; 220 if (this.size >= this.maxSize) { 221 this.list.remove(tailItem); 222 delete this.hash[tailItem.key]; 223 this.size--; 224 } 225 if (node = this.hash[key]) { 226 node.val = val; 227 this.list.moveToFront(node); 228 } else { 229 node = new Node(key, val); 230 this.list.add(node); 231 this.hash[key] = node; 232 this.size++; 233 } 234 }, 235 get: function get(key) { 236 var node = this.hash[key]; 237 if (node) { 238 this.list.moveToFront(node); 239 return node.val; 240 } 241 }, 242 reset: function reset() { 243 this.size = 0; 244 this.hash = {}; 245 this.list = new List(); 246 } 247 }); 248 function List() { 249 this.head = this.tail = null; 250 } 251 _.mixin(List.prototype, { 252 add: function add(node) { 253 if (this.head) { 254 node.next = this.head; 255 this.head.prev = node; 256 } 257 this.head = node; 258 this.tail = this.tail || node; 259 }, 260 remove: function remove(node) { 261 node.prev ? node.prev.next = node.next : this.head = node.next; 262 node.next ? node.next.prev = node.prev : this.tail = node.prev; 263 }, 264 moveToFront: function(node) { 265 this.remove(node); 266 this.add(node); 267 } 268 }); 269 function Node(key, val) { 270 this.key = key; 271 this.val = val; 272 this.prev = this.next = null; 273 } 274 return LruCache; 275 }(); 276 var PersistentStorage = function() { 277 "use strict"; 278 var LOCAL_STORAGE; 279 try { 280 LOCAL_STORAGE = window.localStorage; 281 LOCAL_STORAGE.setItem("~~~", "!"); 282 LOCAL_STORAGE.removeItem("~~~"); 283 } catch (err) { 284 LOCAL_STORAGE = null; 285 } 286 function PersistentStorage(namespace, override) { 287 this.prefix = [ "__", namespace, "__" ].join(""); 288 this.ttlKey = "__ttl__"; 289 this.keyMatcher = new RegExp("^" + _.escapeRegExChars(this.prefix)); 290 this.ls = override || LOCAL_STORAGE; 291 !this.ls && this._noop(); 292 } 293 _.mixin(PersistentStorage.prototype, { 294 _prefix: function(key) { 295 return this.prefix + key; 296 }, 297 _ttlKey: function(key) { 298 return this._prefix(key) + this.ttlKey; 299 }, 300 _noop: function() { 301 this.get = this.set = this.remove = this.clear = this.isExpired = _.noop; 302 }, 303 _safeSet: function(key, val) { 304 try { 305 this.ls.setItem(key, val); 306 } catch (err) { 307 if (err.name === "QuotaExceededError") { 308 this.clear(); 309 this._noop(); 310 } 311 } 312 }, 313 get: function(key) { 314 if (this.isExpired(key)) { 315 this.remove(key); 316 } 317 return decode(this.ls.getItem(this._prefix(key))); 318 }, 319 set: function(key, val, ttl) { 320 if (_.isNumber(ttl)) { 321 this._safeSet(this._ttlKey(key), encode(now() + ttl)); 322 } else { 323 this.ls.removeItem(this._ttlKey(key)); 324 } 325 return this._safeSet(this._prefix(key), encode(val)); 326 }, 327 remove: function(key) { 328 this.ls.removeItem(this._ttlKey(key)); 329 this.ls.removeItem(this._prefix(key)); 330 return this; 331 }, 332 clear: function() { 333 var i, keys = gatherMatchingKeys(this.keyMatcher); 334 for (i = keys.length; i--; ) { 335 this.remove(keys[i]); 336 } 337 return this; 338 }, 339 isExpired: function(key) { 340 var ttl = decode(this.ls.getItem(this._ttlKey(key))); 341 return _.isNumber(ttl) && now() > ttl ? true : false; 342 } 343 }); 344 return PersistentStorage; 345 function now() { 346 return new Date().getTime(); 347 } 348 function encode(val) { 349 return JSON.stringify(_.isUndefined(val) ? null : val); 350 } 351 function decode(val) { 352 return $.parseJSON(val); 353 } 354 function gatherMatchingKeys(keyMatcher) { 355 var i, key, keys = [], len = LOCAL_STORAGE.length; 356 for (i = 0; i < len; i++) { 357 if ((key = LOCAL_STORAGE.key(i)).match(keyMatcher)) { 358 keys.push(key.replace(keyMatcher, "")); 359 } 360 } 361 return keys; 362 } 363 }(); 364 var Transport = function() { 365 "use strict"; 366 var pendingRequestsCount = 0, pendingRequests = {}, sharedCache = new LruCache(10); 367 function Transport(o) { 368 o = o || {}; 369 this.maxPendingRequests = o.maxPendingRequests || 6; 370 this.cancelled = false; 371 this.lastReq = null; 372 this._send = o.transport; 373 this._get = o.limiter ? o.limiter(this._get) : this._get; 374 this._cache = o.cache === false ? new LruCache(0) : sharedCache; 375 } 376 Transport.setMaxPendingRequests = function setMaxPendingRequests(num) { 377 this.maxPendingRequests = num; 378 }; 379 Transport.resetCache = function resetCache() { 380 sharedCache.reset(); 381 }; 382 _.mixin(Transport.prototype, { 383 _fingerprint: function fingerprint(o) { 384 o = o || {}; 385 return o.url + o.type + $.param(o.data || {}); 386 }, 387 _get: function(o, cb) { 388 var that = this, fingerprint, jqXhr; 389 fingerprint = this._fingerprint(o); 390 if (this.cancelled || fingerprint !== this.lastReq) { 391 return; 392 } 393 if (jqXhr = pendingRequests[fingerprint]) { 394 jqXhr.done(done).fail(fail); 395 } else if (pendingRequestsCount < this.maxPendingRequests) { 396 pendingRequestsCount++; 397 pendingRequests[fingerprint] = this._send(o).done(done).fail(fail).always(always); 398 } else { 399 this.onDeckRequestArgs = [].slice.call(arguments, 0); 400 } 401 function done(resp) { 402 cb(null, resp); 403 that._cache.set(fingerprint, resp); 404 } 405 function fail() { 406 cb(true); 407 } 408 function always() { 409 pendingRequestsCount--; 410 delete pendingRequests[fingerprint]; 411 if (that.onDeckRequestArgs) { 412 that._get.apply(that, that.onDeckRequestArgs); 413 that.onDeckRequestArgs = null; 414 } 415 } 416 }, 417 get: function(o, cb) { 418 var resp, fingerprint; 419 cb = cb || $.noop; 420 o = _.isString(o) ? { 421 url: o 422 } : o || {}; 423 fingerprint = this._fingerprint(o); 424 this.cancelled = false; 425 this.lastReq = fingerprint; 426 if (resp = this._cache.get(fingerprint)) { 427 cb(null, resp); 428 } else { 429 this._get(o, cb); 430 } 431 }, 432 cancel: function() { 433 this.cancelled = true; 434 } 435 }); 436 return Transport; 437 }(); 438 var SearchIndex = window.SearchIndex = function() { 439 "use strict"; 440 var CHILDREN = "c", IDS = "i"; 441 function SearchIndex(o) { 442 o = o || {}; 443 if (!o.datumTokenizer || !o.queryTokenizer) { 444 $.error("datumTokenizer and queryTokenizer are both required"); 445 } 446 this.identify = o.identify || _.stringify; 447 this.datumTokenizer = o.datumTokenizer; 448 this.queryTokenizer = o.queryTokenizer; 449 this.matchAnyQueryToken = o.matchAnyQueryToken; 450 this.reset(); 451 } 452 _.mixin(SearchIndex.prototype, { 453 bootstrap: function bootstrap(o) { 454 this.datums = o.datums; 455 this.trie = o.trie; 456 }, 457 add: function(data) { 458 var that = this; 459 data = _.isArray(data) ? data : [ data ]; 460 _.each(data, function(datum) { 461 var id, tokens; 462 that.datums[id = that.identify(datum)] = datum; 463 tokens = normalizeTokens(that.datumTokenizer(datum)); 464 _.each(tokens, function(token) { 465 var node, chars, ch; 466 node = that.trie; 467 chars = token.split(""); 468 while (ch = chars.shift()) { 469 node = node[CHILDREN][ch] || (node[CHILDREN][ch] = newNode()); 470 node[IDS].push(id); 471 } 472 }); 473 }); 474 }, 475 get: function get(ids) { 476 var that = this; 477 return _.map(ids, function(id) { 478 return that.datums[id]; 479 }); 480 }, 481 search: function search(query) { 482 var that = this, tokens, matches; 483 tokens = normalizeTokens(this.queryTokenizer(query)); 484 _.each(tokens, function(token) { 485 var node, chars, ch, ids; 486 if (matches && matches.length === 0 && !that.matchAnyQueryToken) { 487 return false; 488 } 489 node = that.trie; 490 chars = token.split(""); 491 while (node && (ch = chars.shift())) { 492 node = node[CHILDREN][ch]; 493 } 494 if (node && chars.length === 0) { 495 ids = node[IDS].slice(0); 496 matches = matches ? getIntersection(matches, ids) : ids; 497 } else { 498 if (!that.matchAnyQueryToken) { 499 matches = []; 500 return false; 501 } 502 } 503 }); 504 return matches ? _.map(unique(matches), function(id) { 505 return that.datums[id]; 506 }) : []; 507 }, 508 all: function all() { 509 var values = []; 510 for (var key in this.datums) { 511 values.push(this.datums[key]); 512 } 513 return values; 514 }, 515 reset: function reset() { 516 this.datums = {}; 517 this.trie = newNode(); 518 }, 519 serialize: function serialize() { 520 return { 521 datums: this.datums, 522 trie: this.trie 523 }; 524 } 525 }); 526 return SearchIndex; 527 function normalizeTokens(tokens) { 528 tokens = _.filter(tokens, function(token) { 529 return !!token; 530 }); 531 tokens = _.map(tokens, function(token) { 532 return token.toLowerCase(); 533 }); 534 return tokens; 535 } 536 function newNode() { 537 var node = {}; 538 node[IDS] = []; 539 node[CHILDREN] = {}; 540 return node; 541 } 542 function unique(array) { 543 var seen = {}, uniques = []; 544 for (var i = 0, len = array.length; i < len; i++) { 545 if (!seen[array[i]]) { 546 seen[array[i]] = true; 547 uniques.push(array[i]); 548 } 549 } 550 return uniques; 551 } 552 function getIntersection(arrayA, arrayB) { 553 var ai = 0, bi = 0, intersection = []; 554 arrayA = arrayA.sort(); 555 arrayB = arrayB.sort(); 556 var lenArrayA = arrayA.length, lenArrayB = arrayB.length; 557 while (ai < lenArrayA && bi < lenArrayB) { 558 if (arrayA[ai] < arrayB[bi]) { 559 ai++; 560 } else if (arrayA[ai] > arrayB[bi]) { 561 bi++; 562 } else { 563 intersection.push(arrayA[ai]); 564 ai++; 565 bi++; 566 } 567 } 568 return intersection; 569 } 570 }(); 571 var Prefetch = function() { 572 "use strict"; 573 var keys; 574 keys = { 575 data: "data", 576 protocol: "protocol", 577 thumbprint: "thumbprint" 578 }; 579 function Prefetch(o) { 580 this.url = o.url; 581 this.ttl = o.ttl; 582 this.cache = o.cache; 583 this.prepare = o.prepare; 584 this.transform = o.transform; 585 this.transport = o.transport; 586 this.thumbprint = o.thumbprint; 587 this.storage = new PersistentStorage(o.cacheKey); 588 } 589 _.mixin(Prefetch.prototype, { 590 _settings: function settings() { 591 return { 592 url: this.url, 593 type: "GET", 594 dataType: "json" 595 }; 596 }, 597 store: function store(data) { 598 if (!this.cache) { 599 return; 600 } 601 this.storage.set(keys.data, data, this.ttl); 602 this.storage.set(keys.protocol, location.protocol, this.ttl); 603 this.storage.set(keys.thumbprint, this.thumbprint, this.ttl); 604 }, 605 fromCache: function fromCache() { 606 var stored = {}, isExpired; 607 if (!this.cache) { 608 return null; 609 } 610 stored.data = this.storage.get(keys.data); 611 stored.protocol = this.storage.get(keys.protocol); 612 stored.thumbprint = this.storage.get(keys.thumbprint); 613 isExpired = stored.thumbprint !== this.thumbprint || stored.protocol !== location.protocol; 614 return stored.data && !isExpired ? stored.data : null; 615 }, 616 fromNetwork: function(cb) { 617 var that = this, settings; 618 if (!cb) { 619 return; 620 } 621 settings = this.prepare(this._settings()); 622 this.transport(settings).fail(onError).done(onResponse); 623 function onError() { 624 cb(true); 625 } 626 function onResponse(resp) { 627 cb(null, that.transform(resp)); 628 } 629 }, 630 clear: function clear() { 631 this.storage.clear(); 632 return this; 633 } 634 }); 635 return Prefetch; 636 }(); 637 var Remote = function() { 638 "use strict"; 639 function Remote(o) { 640 this.url = o.url; 641 this.prepare = o.prepare; 642 this.transform = o.transform; 643 this.indexResponse = o.indexResponse; 644 this.transport = new Transport({ 645 cache: o.cache, 646 limiter: o.limiter, 647 transport: o.transport, 648 maxPendingRequests: o.maxPendingRequests 649 }); 650 } 651 _.mixin(Remote.prototype, { 652 _settings: function settings() { 653 return { 654 url: this.url, 655 type: "GET", 656 dataType: "json" 657 }; 658 }, 659 get: function get(query, cb) { 660 var that = this, settings; 661 if (!cb) { 662 return; 663 } 664 query = query || ""; 665 settings = this.prepare(query, this._settings()); 666 return this.transport.get(settings, onResponse); 667 function onResponse(err, resp) { 668 err ? cb([]) : cb(that.transform(resp)); 669 } 670 }, 671 cancelLastRequest: function cancelLastRequest() { 672 this.transport.cancel(); 673 } 674 }); 675 return Remote; 676 }(); 677 var oParser = function() { 678 "use strict"; 679 return function parse(o) { 680 var defaults, sorter; 681 defaults = { 682 initialize: true, 683 identify: _.stringify, 684 datumTokenizer: null, 685 queryTokenizer: null, 686 matchAnyQueryToken: false, 687 sufficient: 5, 688 indexRemote: false, 689 sorter: null, 690 local: [], 691 prefetch: null, 692 remote: null 693 }; 694 o = _.mixin(defaults, o || {}); 695 !o.datumTokenizer && $.error("datumTokenizer is required"); 696 !o.queryTokenizer && $.error("queryTokenizer is required"); 697 sorter = o.sorter; 698 o.sorter = sorter ? function(x) { 699 return x.sort(sorter); 700 } : _.identity; 701 o.local = _.isFunction(o.local) ? o.local() : o.local; 702 o.prefetch = parsePrefetch(o.prefetch); 703 o.remote = parseRemote(o.remote); 704 return o; 705 }; 706 function parsePrefetch(o) { 707 var defaults; 708 if (!o) { 709 return null; 710 } 711 defaults = { 712 url: null, 713 ttl: 24 * 60 * 60 * 1e3, 714 cache: true, 715 cacheKey: null, 716 thumbprint: "", 717 prepare: _.identity, 718 transform: _.identity, 719 transport: null 720 }; 721 o = _.isString(o) ? { 722 url: o 723 } : o; 724 o = _.mixin(defaults, o); 725 !o.url && $.error("prefetch requires url to be set"); 726 o.transform = o.filter || o.transform; 727 o.cacheKey = o.cacheKey || o.url; 728 o.thumbprint = VERSION + o.thumbprint; 729 o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax; 730 return o; 731 } 732 function parseRemote(o) { 733 var defaults; 734 if (!o) { 735 return; 736 } 737 defaults = { 738 url: null, 739 cache: true, 740 prepare: null, 741 replace: null, 742 wildcard: null, 743 limiter: null, 744 rateLimitBy: "debounce", 745 rateLimitWait: 300, 746 transform: _.identity, 747 transport: null 748 }; 749 o = _.isString(o) ? { 750 url: o 751 } : o; 752 o = _.mixin(defaults, o); 753 !o.url && $.error("remote requires url to be set"); 754 o.transform = o.filter || o.transform; 755 o.prepare = toRemotePrepare(o); 756 o.limiter = toLimiter(o); 757 o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax; 758 delete o.replace; 759 delete o.wildcard; 760 delete o.rateLimitBy; 761 delete o.rateLimitWait; 762 return o; 763 } 764 function toRemotePrepare(o) { 765 var prepare, replace, wildcard; 766 prepare = o.prepare; 767 replace = o.replace; 768 wildcard = o.wildcard; 769 if (prepare) { 770 return prepare; 771 } 772 if (replace) { 773 prepare = prepareByReplace; 774 } else if (o.wildcard) { 775 prepare = prepareByWildcard; 776 } else { 777 prepare = identityPrepare; 778 } 779 return prepare; 780 function prepareByReplace(query, settings) { 781 settings.url = replace(settings.url, query); 782 return settings; 783 } 784 function prepareByWildcard(query, settings) { 785 settings.url = settings.url.replace(wildcard, encodeURIComponent(query)); 786 return settings; 787 } 788 function identityPrepare(query, settings) { 789 return settings; 790 } 791 } 792 function toLimiter(o) { 793 var limiter, method, wait; 794 limiter = o.limiter; 795 method = o.rateLimitBy; 796 wait = o.rateLimitWait; 797 if (!limiter) { 798 limiter = /^throttle$/i.test(method) ? throttle(wait) : debounce(wait); 799 } 800 return limiter; 801 function debounce(wait) { 802 return function debounce(fn) { 803 return _.debounce(fn, wait); 804 }; 805 } 806 function throttle(wait) { 807 return function throttle(fn) { 808 return _.throttle(fn, wait); 809 }; 810 } 811 } 812 function callbackToDeferred(fn) { 813 return function wrapper(o) { 814 var deferred = $.Deferred(); 815 fn(o, onSuccess, onError); 816 return deferred; 817 function onSuccess(resp) { 818 _.defer(function() { 819 deferred.resolve(resp); 820 }); 821 } 822 function onError(err) { 823 _.defer(function() { 824 deferred.reject(err); 825 }); 826 } 827 }; 828 } 829 }(); 830 var Bloodhound = function() { 831 "use strict"; 832 var old; 833 old = window && window.Bloodhound; 834 function Bloodhound(o) { 835 o = oParser(o); 836 this.sorter = o.sorter; 837 this.identify = o.identify; 838 this.sufficient = o.sufficient; 839 this.indexRemote = o.indexRemote; 840 this.local = o.local; 841 this.remote = o.remote ? new Remote(o.remote) : null; 842 this.prefetch = o.prefetch ? new Prefetch(o.prefetch) : null; 843 this.index = new SearchIndex({ 844 identify: this.identify, 845 datumTokenizer: o.datumTokenizer, 846 queryTokenizer: o.queryTokenizer 847 }); 848 o.initialize !== false && this.initialize(); 849 } 850 Bloodhound.noConflict = function noConflict() { 851 window && (window.Bloodhound = old); 852 return Bloodhound; 853 }; 854 Bloodhound.tokenizers = tokenizers; 855 _.mixin(Bloodhound.prototype, { 856 __ttAdapter: function ttAdapter() { 857 var that = this; 858 return this.remote ? withAsync : withoutAsync; 859 function withAsync(query, sync, async) { 860 return that.search(query, sync, async); 861 } 862 function withoutAsync(query, sync) { 863 return that.search(query, sync); 864 } 865 }, 866 _loadPrefetch: function loadPrefetch() { 867 var that = this, deferred, serialized; 868 deferred = $.Deferred(); 869 if (!this.prefetch) { 870 deferred.resolve(); 871 } else if (serialized = this.prefetch.fromCache()) { 872 this.index.bootstrap(serialized); 873 deferred.resolve(); 874 } else { 875 this.prefetch.fromNetwork(done); 876 } 877 return deferred.promise(); 878 function done(err, data) { 879 if (err) { 880 return deferred.reject(); 881 } 882 that.add(data); 883 that.prefetch.store(that.index.serialize()); 884 deferred.resolve(); 885 } 886 }, 887 _initialize: function initialize() { 888 var that = this, deferred; 889 this.clear(); 890 (this.initPromise = this._loadPrefetch()).done(addLocalToIndex); 891 return this.initPromise; 892 function addLocalToIndex() { 893 that.add(that.local); 894 } 895 }, 896 initialize: function initialize(force) { 897 return !this.initPromise || force ? this._initialize() : this.initPromise; 898 }, 899 add: function add(data) { 900 this.index.add(data); 901 return this; 902 }, 903 get: function get(ids) { 904 ids = _.isArray(ids) ? ids : [].slice.call(arguments); 905 return this.index.get(ids); 906 }, 907 search: function search(query, sync, async) { 908 var that = this, local; 909 sync = sync || _.noop; 910 async = async || _.noop; 911 local = this.sorter(this.index.search(query)); 912 sync(this.remote ? local.slice() : local); 913 if (this.remote && local.length < this.sufficient) { 914 this.remote.get(query, processRemote); 915 } else if (this.remote) { 916 this.remote.cancelLastRequest(); 917 } 918 return this; 919 function processRemote(remote) { 920 var nonDuplicates = []; 921 _.each(remote, function(r) { 922 !_.some(local, function(l) { 923 return that.identify(r) === that.identify(l); 924 }) && nonDuplicates.push(r); 925 }); 926 that.indexRemote && that.add(nonDuplicates); 927 async(nonDuplicates); 928 } 929 }, 930 all: function all() { 931 return this.index.all(); 932 }, 933 clear: function clear() { 934 this.index.reset(); 935 return this; 936 }, 937 clearPrefetchCache: function clearPrefetchCache() { 938 this.prefetch && this.prefetch.clear(); 939 return this; 940 }, 941 clearRemoteCache: function clearRemoteCache() { 942 Transport.resetCache(); 943 return this; 944 }, 945 ttAdapter: function ttAdapter() { 946 return this.__ttAdapter(); 947 } 948 }); 949 return Bloodhound; 950 }(); 951 return Bloodhound; 952});
952 953 954(function(root, factory) { 955 if (typeof define === "function" && define.amd) { 956 define([ "jquery" ], function(a0) { 957 return factory(a0); 958 }); 959 } else if (typeof exports === "object"
vendor: 18,407 bytes, lines 959-1432
959) { 960 module.exports = factory(require("jquery")); 961 } else { 962 factory(root["jQuery"]); 963 } 964})(this, function($) { 965 var _ = function() { 966 "use strict"; 967 return { 968 isMsie: function() { 969 return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false; 970 }, 971 isBlankString: function(str) { 972 return !str || /^\s*$/.test(str); 973 }, 974 escapeRegExChars: function(str) { 975 return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); 976 }, 977 isString: function(obj) { 978 return typeof obj === "string"; 979 }, 980 isNumber: function(obj) { 981 return typeof obj === "number"; 982 }, 983 isArray: $.isArray, 984 isFunction: $.isFunction, 985 isObject: $.isPlainObject, 986 isUndefined: function(obj) { 987 return typeof obj === "undefined"; 988 }, 989 isElement: function(obj) { 990 return !!(obj && obj.nodeType === 1); 991 }, 992 isJQuery: function(obj) { 993 return obj instanceof $; 994 }, 995 toStr: function toStr(s) { 996 return _.isUndefined(s) || s === null ? "" : s + ""; 997 }, 998 bind: $.proxy, 999 each: function(collection, cb) { 1000 $.each(collection, reverseArgs); 1001 function reverseArgs(index, value) { 1002 return cb(value, index); 1003 } 1004 }, 1005 map: $.map, 1006 filter: $.grep, 1007 every: function(obj, test) { 1008 var result = true; 1009 if (!obj) { 1010 return result; 1011 } 1012 $.each(obj, function(key, val) { 1013 if (!(result = test.call(null, val, key, obj))) { 1014 return false; 1015 } 1016 }); 1017 return !!result; 1018 }, 1019 some: function(obj, test) { 1020 var result = false; 1021 if (!obj) { 1022 return result; 1023 } 1024 $.each(obj, function(key, val) { 1025 if (result = test.call(null, val, key, obj)) { 1026 return false; 1027 } 1028 }); 1029 return !!result; 1030 }, 1031 mixin: $.extend, 1032 identity: function(x) { 1033 return x; 1034 }, 1035 clone: function(obj) { 1036 return $.extend(true, {}, obj); 1037 }, 1038 getIdGenerator: function() { 1039 var counter = 0; 1040 return function() { 1041 return counter++; 1042 }; 1043 }, 1044 templatify: function templatify(obj) { 1045 return $.isFunction(obj) ? obj : template; 1046 function template() { 1047 return String(obj); 1048 } 1049 }, 1050 defer: function(fn) { 1051 setTimeout(fn, 0); 1052 }, 1053 debounce: function(func, wait, immediate) { 1054 var timeout, result; 1055 return function() { 1056 var context = this, args = arguments, later, callNow; 1057 later = function() { 1058 timeout = null; 1059 if (!immediate) { 1060 result = func.apply(context, args); 1061 } 1062 }; 1063 callNow = immediate && !timeout; 1064 clearTimeout(timeout); 1065 timeout = setTimeout(later, wait); 1066 if (callNow) { 1067 result = func.apply(context, args); 1068 } 1069 return result; 1070 }; 1071 }, 1072 throttle: function(func, wait) { 1073 var context, args, timeout, result, previous, later; 1074 previous = 0; 1075 later = function() { 1076 previous = new Date(); 1077 timeout = null; 1078 result = func.apply(context, args); 1079 }; 1080 return function() { 1081 var now = new Date(), remaining = wait - (now - previous); 1082 context = this; 1083 args = arguments; 1084 if (remaining <= 0) { 1085 clearTimeout(timeout); 1086 timeout = null; 1087 previous = now; 1088 result = func.apply(context, args); 1089 } else if (!timeout) { 1090 timeout = setTimeout(later, remaining); 1091 } 1092 return result; 1093 }; 1094 }, 1095 stringify: function(val) { 1096 return _.isString(val) ? val : JSON.stringify(val); 1097 }, 1098 guid: function() { 1099 function _p8(s) { 1100 var p = (Math.random().toString(16) + "000000000").substr(2, 8); 1101 return s ? "-" + p.substr(0, 4) + "-" + p.substr(4, 4) : p; 1102 } 1103 return "tt-" + _p8() + _p8(true) + _p8(true) + _p8(); 1104 }, 1105 noop: function() {} 1106 }; 1107 }(); 1108 var WWW = function() { 1109 "use strict"; 1110 var defaultClassNames = { 1111 wrapper: "twitter-typeahead", 1112 input: "tt-input", 1113 hint: "tt-hint", 1114 menu: "tt-menu", 1115 dataset: "tt-dataset", 1116 suggestion: "tt-suggestion", 1117 selectable: "tt-selectable", 1118 empty: "tt-empty", 1119 open: "tt-open", 1120 cursor: "tt-cursor", 1121 highlight: "tt-highlight" 1122 }; 1123 return build; 1124 function build(o) { 1125 var www, classes; 1126 classes = _.mixin({}, defaultClassNames, o); 1127 www = { 1128 css: buildCss(), 1129 classes: classes, 1130 html: buildHtml(classes), 1131 selectors: buildSelectors(classes) 1132 }; 1133 return { 1134 css: www.css, 1135 html: www.html, 1136 classes: www.classes, 1137 selectors: www.selectors, 1138 mixin: function(o) { 1139 _.mixin(o, www); 1140 } 1141 }; 1142 } 1143 function buildHtml(c) { 1144 return { 1145 wrapper: '<span class="' + c.wrapper + '"></span>', 1146 menu: '<div role="listbox" class="' + c.menu + '"></div>' 1147 }; 1148 } 1149 function buildSelectors(classes) { 1150 var selectors = {}; 1151 _.each(classes, function(v, k) { 1152 selectors[k] = "." + v; 1153 }); 1154 return selectors; 1155 } 1156 function buildCss() { 1157 var css = { 1158 wrapper: { 1159 position: "relative", 1160 display: "inline-block" 1161 }, 1162 hint: { 1163 position: "absolute", 1164 top: "0", 1165 left: "0", 1166 borderColor: "transparent", 1167 boxShadow: "none", 1168 opacity: "1" 1169 }, 1170 input: { 1171 position: "relative", 1172 verticalAlign: "top", 1173 backgroundColor: "transparent" 1174 }, 1175 inputWithNoHint: { 1176 position: "relative", 1177 verticalAlign: "top" 1178 }, 1179 menu: { 1180 position: "absolute", 1181 top: "100%", 1182 left: "0", 1183 zIndex: "100", 1184 display: "none" 1185 }, 1186 ltr: { 1187 left: "0", 1188 right: "auto" 1189 }, 1190 rtl: { 1191 left: "auto", 1192 right: " 0" 1193 } 1194 }; 1195 if (_.isMsie()) { 1196 _.mixin(css.input, { 1197 backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)" 1198 }); 1199 } 1200 return css; 1201 } 1202 }(); 1203 var EventBus = function() { 1204 "use strict"; 1205 var namespace, deprecationMap; 1206 namespace = "typeahead:"; 1207 deprecationMap = { 1208 render: "rendered", 1209 cursorchange: "cursorchanged", 1210 select: "selected", 1211 autocomplete: "autocompleted" 1212 }; 1213 function EventBus(o) { 1214 if (!o || !o.el) { 1215 $.error("EventBus initialized without el"); 1216 } 1217 this.$el = $(o.el); 1218 } 1219 _.mixin(EventBus.prototype, { 1220 _trigger: function(type, args) { 1221 var $e = $.Event(namespace + type); 1222 this.$el.trigger.call(this.$el, $e, args || []); 1223 return $e; 1224 }, 1225 before: function(type) { 1226 var args, $e; 1227 args = [].slice.call(arguments, 1); 1228 $e = this._trigger("before" + type, args); 1229 return $e.isDefaultPrevented(); 1230 }, 1231 trigger: function(type) { 1232 var deprecatedType; 1233 this._trigger(type, [].slice.call(arguments, 1)); 1234 if (deprecatedType = deprecationMap[type]) { 1235 this._trigger(deprecatedType, [].slice.call(arguments, 1)); 1236 } 1237 } 1238 }); 1239 return EventBus; 1240 }(); 1241 var EventEmitter = function() { 1242 "use strict"; 1243 var splitter = /\s+/, nextTick = getNextTick(); 1244 return { 1245 onSync: onSync, 1246 onAsync: onAsync, 1247 off: off, 1248 trigger: trigger 1249 }; 1250 function on(method, types, cb, context) { 1251 var type; 1252 if (!cb) { 1253 return this; 1254 } 1255 types = types.split(splitter); 1256 cb = context ? bindContext(cb, context) : cb; 1257 this._callbacks = this._callbacks || {}; 1258 while (type = types.shift()) { 1259 this._callbacks[type] = this._callbacks[type] || { 1260 sync: [], 1261 async: [] 1262 }; 1263 this._callbacks[type][method].push(cb); 1264 } 1265 return this; 1266 } 1267 function onAsync(types, cb, context) { 1268 return on.call(this, "async", types, cb, context); 1269 } 1270 function onSync(types, cb, context) { 1271 return on.call(this, "sync", types, cb, context); 1272 } 1273 function off(types) { 1274 var type; 1275 if (!this._callbacks) { 1276 return this; 1277 } 1278 types = types.split(splitter); 1279 while (type = types.shift()) { 1280 delete this._callbacks[type]; 1281 } 1282 return this; 1283 } 1284 function trigger(types) { 1285 var type, callbacks, args, syncFlush, asyncFlush; 1286 if (!this._callbacks) { 1287 return this; 1288 } 1289 types = types.split(splitter); 1290 args = [].slice.call(arguments, 1); 1291 while ((type = types.shift()) && (callbacks = this._callbacks[type])) { 1292 syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args)); 1293 asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args)); 1294 syncFlush() && nextTick(asyncFlush); 1295 } 1296 return this; 1297 } 1298 function getFlush(callbacks, context, args) { 1299 return flush; 1300 function flush() { 1301 var cancelled; 1302 for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) { 1303 cancelled = callbacks[i].apply(context, args) === false; 1304 } 1305 return !cancelled; 1306 } 1307 } 1308 function getNextTick() { 1309 var nextTickFn; 1310 if (window.setImmediate) { 1311 nextTickFn = function nextTickSetImmediate(fn) { 1312 setImmediate(function() { 1313 fn(); 1314 }); 1315 }; 1316 } else { 1317 nextTickFn = function nextTickSetTimeout(fn) { 1318 setTimeout(function() { 1319 fn(); 1320 }, 0); 1321 }; 1322 } 1323 return nextTickFn; 1324 } 1325 function bindContext(fn, context) { 1326 return fn.bind ? fn.bind(context) : function() { 1327 fn.apply(context, [].slice.call(arguments, 0)); 1328 }; 1329 } 1330 }(); 1331 var highlight = function(doc) { 1332 "use strict"; 1333 var defaults = { 1334 node: null, 1335 pattern: null, 1336 tagName: "strong", 1337 className: null, 1338 wordsOnly: false, 1339 caseSensitive: false, 1340 diacriticInsensitive: false 1341 }; 1342 var accented = { 1343 A: "[AaªÃ-à à -Ã¥Ä-Ä ÇÇÈ-ÈȦȧᴬáµá¸á¸áºáº -ảââââ»ââ¶âã±-ã´ã-ãããã©-ã¯ãããã¿ï¼¡ï½]", 1344 B: "[Bbá´®áµá¸-á¸â¬ââ·âã´ã -ãããããï¼¢ï½]", 1345 C: "[CcÃçÄ-Äá¶ââââ âââ â ½ââ¸âã¶ãããã ã¤ã-ãï¼£ï½]", 1346 D: "[DdÄÄÇ-ÇDZ-dzᴰáµá¸-á¸â â ⠮⠾ââ¹âãã²ã·-ã¹ãã-ã¯ã ãDï½]", 1347 E: "[EeÃ-Ãè-ëÄ-ÄÈ-ÈȨȩᴱáµá¸-á¸áº¸-ẽââ¡â¯â°â â âºâãããï¼¥ï½ ]", 1348 F: "[Ffá¶ á¸á¸ââ±â»â¡â»âã-ããï¬-ï¬ï¼¦ï½]", 1349 G: "[GgÄ-ģǦǧǴǵᴳáµá¸ ḡââ¢â¼âãããã-ããã¬ãããã¿ï¼§ï½]", 1350 H: "[HhĤĥÈÈʰᴴḢ-ḫáºâ-ââ£â½âãã±ã-ããããHï½]", 1351 I: "[IiÃ-Ãì-ïĨ-İIJijÇÇÈ-ÈᴵᵢḬá¸á»-á»â±âââ¹â â -⠣⠥-⠨⠪⠫⠰-⠳⠵-⠸⠺⠻â¤â¾âãºããï¬ï¬ï¼©ï½]", 1352 J: "[JjIJ-ĵÇ-Çǰʲᴶâ â¥â¿âⱼJï½]", 1353 K: "[KkĶķǨǩᴷáµá¸°-ḵâªâ¦ââãã ãããããã¢ã¦ãªã¸ã¾ããã-ãKï½]", 1354 L: "[LlĹ-ÅÇ-ÇˡᴸḶḷḺ-ḽâââ¡â ¬â ¼â§ââãããã-ãããã¿ï¬ï¬ï¼¬ï½]", 1355 M: "[Mmá´¹áµá¸¾-á¹â â¢â³â ¯â ¿â¨ââã·-ã¹ãããããã-ã¨ã«ã³ã·ã¹ã½ã¿ããããã-ãããããï¼ï½]", 1356 N: "[NnÃñÅ-ÅÇ-ÇǸǹᴺá¹-á¹â¿âââ©ââãããã±ãµã»ããï¼®ï½]", 1357 O: "[OoºÃ-Ãò-öÅ-ÅÆ Æ¡ÇÇǪǫÈ-ÈȮȯᴼáµá»-á»ââ ââ´âªââãµãããOï½]", 1358 P: "[Ppá´¾áµá¹-á¹ââ«â âãã±ã¶ããã©-ã¬ã°ã´ãºãã-ãï¼°ï½]", 1359 Q: "[Qqââ¬ââ ãï¼±ï½]", 1360 R: "[RrÅ-ÅÈ-Èʳᴿᵣá¹-á¹á¹á¹â¨â-ââââ¡ãã´ã-ã¯ããï¼²ï½]", 1361 S: "[SsÅ-šſÈÈˢṠ-á¹£â¨ââ â®ââ¢ã§ã¨ã®-ã³ããï¬ï¼³ï½]", 1362 T: "[TtÅ¢-Å¥ÈÈáµáµá¹ª-á¹±áºâ¡â¢â¯ââ£ããããï¬ ï¬ï¼´ï½]", 1363 U: "[UuÃ-Ãù-üŨ-ųƯưÇÇÈ-Èáµáµáµ¤á¹²-ṷỤ-á»§ââ°ââ¤ã³ãºï¼µï½]", 1364 V: "[Vváµáµ¥á¹¼-ṿ⠣-â §â ³-â ·â±ââ¥â±½ããµã´-ã¹ããï¼¶ï½]", 1365 W: "[WwŴŵʷáµáº-áºáºâ²ââ¦ãº-ã¿ãï¼·ï½]", 1366 X: "[XxË£áº-áºââ»â ¨-â «â ¸-â »â³ââ§ãXï½]", 1367 Y: "[YyÃýÿŶ-ŸȲȳʸáºáºáºá»²-ỹâ´ââ¨ãï¼¹ï½]", 1368 Z: "[ZzŹ-žDZ-dzᶻáº-áºâ¤â¨âµââ©ã-ãZï½]" 1369 }; 1370 return function hightlight(o) { 1371 var regex; 1372 o = _.mixin({}, defaults, o); 1373 if (!o.node || !o.pattern) { 1374 return; 1375 } 1376 o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ]; 1377 regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly, o.diacriticInsensitive); 1378 traverse(o.node, hightlightTextNode); 1379 function hightlightTextNode(textNode) { 1380 var match, patternNode, wrapperNode; 1381 if (match = regex.exec(textNode.data)) { 1382 wrapperNode = doc.createElement(o.tagName); 1383 o.className && (wrapperNode.className = o.className); 1384 patternNode = textNode.splitText(match.index); 1385 patternNode.splitText(match[0].length); 1386 wrapperNode.appendChild(patternNode.cloneNode(true)); 1387 textNode.parentNode.replaceChild(wrapperNode, patternNode); 1388 } 1389 return !!match; 1390 } 1391 function traverse(el, hightlightTextNode) { 1392 var childNode, TEXT_NODE_TYPE = 3; 1393 for (var i = 0; i < el.childNodes.length; i++) { 1394 childNode = el.childNodes[i]; 1395 if (childNode.nodeType === TEXT_NODE_TYPE) { 1396 i += hightlightTextNode(childNode) ? 1 : 0; 1397 } else { 1398 traverse(childNode, hightlightTextNode); 1399 } 1400 } 1401 } 1402 }; 1403 function accent_replacer(chr) { 1404 return accented[chr.toUpperCase()] || chr; 1405 } 1406 function getRegex(patterns, caseSensitive, wordsOnly, diacriticInsensitive) { 1407 var escapedPatterns = [], regexStr; 1408 for (var i = 0, len = patterns.length; i < len; i++) { 1409 var escapedWord = _.escapeRegExChars(patterns[i]); 1410 if (diacriticInsensitive) { 1411 escapedWord = escapedWord.replace(/\S/g, accent_replacer); 1412 } 1413 escapedPatterns.push(escapedWord); 1414 } 1415 regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")"; 1416 return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i"); 1417 } 1418 }(window.document); 1419 var Input = function() { 1420 "use strict"; 1421 var specialKeyCodeMap; 1422 specialKeyCodeMap = { 1423 9: "tab", 1424 27: "esc", 1425 37: "left", 1426 39: "right", 1427 13: "enter", 1428 38: "up", 1429 40: "down" 1430 }; 1431 function Input(o, www) { 1432
1432o = o || {}; 1433 if (!o.input) { 1434 $.error("input is missing"); 1435 } 1436 www.mixin(this); 1437 this.$hint = $(o.hint); 1438 this.$input = $(o.input); 1439 this.$input.attr({ 1440 "aria-activedescendant": "", 1441 "aria-owns": this.$input.attr("id") + "_listbox", 1442 role: "combobox", 1443 "aria-readonly": "true", 1444 "aria-autocomplete": "list" 1445 }); 1446 $(www.menu).attr("id", this.$input.attr("id") + "_listbox"); 1447 this.query = this.$input.val(); 1448 this.queryWhenFocused = this.hasFocus() ? this.query : null; 1449 this.$overflowHelper = buildOverflowHelper(this.$input); 1450 this._checkLanguageDirection(); 1451 if (this.$hint.length === 0) { 1452 this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop; 1453 } 1454 this.onSync("cursorchange", this._updateDescendent); 1455 } 1456 Input.normalizeQuery = function(str) { 1457 return _.toStr(str).replace(/^\s*/g, "").replace(/\s{2,}/g, " "); 1458 }; 1459 _.mixin(Input.prototype, EventEmitter, { 1460 _onBlur: function onBlur() { 1461 this.resetInputValue(); 1462 this.trigger("blurred"); 1463 }, 1464 _onFocus: function onFocus() { 1465 this.queryWhenFocused = this.query; 1466 this.trigger("focused"); 1467 }, 1468 _onKeydown: function onKeydown($e) { 1469 var keyName = specialKeyCodeMap[$e.which || $e.keyCode]; 1470 this._managePreventDefault(keyName, $e); 1471 if (keyName && this._shouldTrigger(keyName, $e)) { 1472 this.trigger(keyName + "Keyed", $e); 1473 } 1474 }, 1475 _onInput: function onInput() { 1476 this._setQuery(this.getInputValue()); 1477 this.clearHintIfInvalid(); 1478 this._checkLanguageDirection(); 1479 }, 1480 _managePreventDefault: function managePreventDefault(keyName, $e) { 1481 var preventDefault; 1482 switch (keyName) { 1483 case "up": 1484 case "down": 1485 preventDefault = !withModifier($e); 1486 break; 1487 1488 default: 1489 preventDefault = false;
vendor: 15,913 bytes, lines 1490-1847
1490 } 1491 preventDefault && $e.preventDefault(); 1492 }, 1493 _shouldTrigger: function shouldTrigger(keyName, $e) { 1494 var trigger; 1495 switch (keyName) { 1496 case "tab": 1497 trigger = !withModifier($e); 1498 break; 1499 1500 default: 1501 trigger = true; 1502 } 1503 return trigger; 1504 }, 1505 _checkLanguageDirection: function checkLanguageDirection() { 1506 var dir = (this.$input.css("direction") || "ltr").toLowerCase(); 1507 if (this.dir !== dir) { 1508 this.dir = dir; 1509 this.$hint.attr("dir", dir); 1510 this.trigger("langDirChanged", dir); 1511 } 1512 }, 1513 _setQuery: function setQuery(val, silent) { 1514 var areEquivalent, hasDifferentWhitespace; 1515 areEquivalent = areQueriesEquivalent(val, this.query); 1516 hasDifferentWhitespace = areEquivalent ? this.query.length !== val.length : false; 1517 this.query = val; 1518 if (!silent && !areEquivalent) { 1519 this.trigger("queryChanged", this.query); 1520 } else if (!silent && hasDifferentWhitespace) { 1521 this.trigger("whitespaceChanged", this.query); 1522 } 1523 }, 1524 _updateDescendent: function updateDescendent(event, id) { 1525 this.$input.attr("aria-activedescendant", id); 1526 }, 1527 bind: function() { 1528 var that = this, onBlur, onFocus, onKeydown, onInput; 1529 onBlur = _.bind(this._onBlur, this); 1530 onFocus = _.bind(this._onFocus, this); 1531 onKeydown = _.bind(this._onKeydown, this); 1532 onInput = _.bind(this._onInput, this); 1533 this.$input.on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown); 1534 if (!_.isMsie() || _.isMsie() > 9) { 1535 this.$input.on("input.tt", onInput); 1536 } else { 1537 this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) { 1538 if (specialKeyCodeMap[$e.which || $e.keyCode]) { 1539 return; 1540 } 1541 _.defer(_.bind(that._onInput, that, $e)); 1542 }); 1543 } 1544 return this; 1545 }, 1546 focus: function focus() { 1547 this.$input.focus(); 1548 }, 1549 blur: function blur() { 1550 this.$input.blur(); 1551 }, 1552 getLangDir: function getLangDir() { 1553 return this.dir; 1554 }, 1555 getQuery: function getQuery() { 1556 return this.query || ""; 1557 }, 1558 setQuery: function setQuery(val, silent) { 1559 this.setInputValue(val); 1560 this._setQuery(val, silent); 1561 }, 1562 hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() { 1563 return this.query !== this.queryWhenFocused; 1564 }, 1565 getInputValue: function getInputValue() { 1566 return this.$input.val(); 1567 }, 1568 setInputValue: function setInputValue(value) { 1569 this.$input.val(value); 1570 this.clearHintIfInvalid(); 1571 this._checkLanguageDirection(); 1572 }, 1573 resetInputValue: function resetInputValue() { 1574 this.setInputValue(this.query); 1575 }, 1576 getHint: function getHint() { 1577 return this.$hint.val(); 1578 }, 1579 setHint: function setHint(value) { 1580 this.$hint.val(value); 1581 }, 1582 clearHint: function clearHint() { 1583 this.setHint(""); 1584 }, 1585 clearHintIfInvalid: function clearHintIfInvalid() { 1586 var val, hint, valIsPrefixOfHint, isValid; 1587 val = this.getInputValue(); 1588 hint = this.getHint(); 1589 valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0; 1590 isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow(); 1591 !isValid && this.clearHint(); 1592 }, 1593 hasFocus: function hasFocus() { 1594 return this.$input.is(":focus"); 1595 }, 1596 hasOverflow: function hasOverflow() { 1597 var constraint = this.$input.width() - 2; 1598 this.$overflowHelper.text(this.getInputValue()); 1599 return this.$overflowHelper.width() >= constraint; 1600 }, 1601 isCursorAtEnd: function() { 1602 var valueLength, selectionStart, range; 1603 valueLength = this.$input.val().length; 1604 selectionStart = this.$input[0].selectionStart; 1605 if (_.isNumber(selectionStart)) { 1606 return selectionStart === valueLength; 1607 } else if (document.selection) { 1608 range = document.selection.createRange(); 1609 range.moveStart("character", -valueLength); 1610 return valueLength === range.text.length; 1611 } 1612 return true; 1613 }, 1614 destroy: function destroy() { 1615 this.$hint.off(".tt"); 1616 this.$input.off(".tt"); 1617 this.$overflowHelper.remove(); 1618 this.$hint = this.$input = this.$overflowHelper = $("<div>"); 1619 } 1620 }); 1621 return Input; 1622 function buildOverflowHelper($input) { 1623 return $('<pre aria-hidden="true"></pre>').css({ 1624 position: "absolute", 1625 visibility: "hidden", 1626 whiteSpace: "pre", 1627 fontFamily: $input.css("font-family"), 1628 fontSize: $input.css("font-size"), 1629 fontStyle: $input.css("font-style"), 1630 fontVariant: $input.css("font-variant"), 1631 fontWeight: $input.css("font-weight"), 1632 wordSpacing: $input.css("word-spacing"), 1633 letterSpacing: $input.css("letter-spacing"), 1634 textIndent: $input.css("text-indent"), 1635 textRendering: $input.css("text-rendering"), 1636 textTransform: $input.css("text-transform") 1637 }).insertAfter($input); 1638 } 1639 function areQueriesEquivalent(a, b) { 1640 return Input.normalizeQuery(a) === Input.normalizeQuery(b); 1641 } 1642 function withModifier($e) { 1643 return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey; 1644 } 1645 }(); 1646 var Dataset = function() { 1647 "use strict"; 1648 var keys, nameGenerator; 1649 keys = { 1650 dataset: "tt-selectable-dataset", 1651 val: "tt-selectable-display", 1652 obj: "tt-selectable-object" 1653 }; 1654 nameGenerator = _.getIdGenerator(); 1655 function Dataset(o, www) { 1656 o = o || {}; 1657 o.templates = o.templates || {}; 1658 o.templates.notFound = o.templates.notFound || o.templates.empty; 1659 if (!o.source) { 1660 $.error("missing source"); 1661 } 1662 if (!o.node) { 1663 $.error("missing node"); 1664 } 1665 if (o.name && !isValidName(o.name)) { 1666 $.error("invalid dataset name: " + o.name); 1667 } 1668 www.mixin(this); 1669 this.highlight = !!o.highlight; 1670 this.name = _.toStr(o.name || nameGenerator()); 1671 this.limit = o.limit || 5; 1672 this.displayFn = getDisplayFn(o.display || o.displayKey); 1673 this.templates = getTemplates(o.templates, this.displayFn); 1674 this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source; 1675 this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async; 1676 this._resetLastSuggestion(); 1677 this.$el = $(o.node).attr("role", "presentation").addClass(this.classes.dataset).addClass(this.classes.dataset + "-" + this.name); 1678 } 1679 Dataset.extractData = function extractData(el) { 1680 var $el = $(el); 1681 if ($el.data(keys.obj)) { 1682 return { 1683 dataset: $el.data(keys.dataset) || "", 1684 val: $el.data(keys.val) || "", 1685 obj: $el.data(keys.obj) || null 1686 }; 1687 } 1688 return null; 1689 }; 1690 _.mixin(Dataset.prototype, EventEmitter, { 1691 _overwrite: function overwrite(query, suggestions) { 1692 suggestions = suggestions || []; 1693 if (suggestions.length) { 1694 this._renderSuggestions(query, suggestions); 1695 } else if (this.async && this.templates.pending) { 1696 this._renderPending(query); 1697 } else if (!this.async && this.templates.notFound) { 1698 this._renderNotFound(query); 1699 } else { 1700 this._empty(); 1701 } 1702 this.trigger("rendered", suggestions, false, this.name); 1703 }, 1704 _append: function append(query, suggestions) { 1705 suggestions = suggestions || []; 1706 if (suggestions.length && this.$lastSuggestion.length) { 1707 this._appendSuggestions(query, suggestions); 1708 } else if (suggestions.length) { 1709 this._renderSuggestions(query, suggestions); 1710 } else if (!this.$lastSuggestion.length && this.templates.notFound) { 1711 this._renderNotFound(query); 1712 } 1713 this.trigger("rendered", suggestions, true, this.name); 1714 }, 1715 _renderSuggestions: function renderSuggestions(query, suggestions) { 1716 var $fragment; 1717 $fragment = this._getSuggestionsFragment(query, suggestions); 1718 this.$lastSuggestion = $fragment.children().last(); 1719 this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions)); 1720 }, 1721 _appendSuggestions: function appendSuggestions(query, suggestions) { 1722 var $fragment, $lastSuggestion; 1723 $fragment = this._getSuggestionsFragment(query, suggestions); 1724 $lastSuggestion = $fragment.children().last(); 1725 this.$lastSuggestion.after($fragment); 1726 this.$lastSuggestion = $lastSuggestion; 1727 }, 1728 _renderPending: function renderPending(query) { 1729 var template = this.templates.pending; 1730 this._resetLastSuggestion(); 1731 template && this.$el.html(template({ 1732 query: query, 1733 dataset: this.name 1734 })); 1735 }, 1736 _renderNotFound: function renderNotFound(query) { 1737 var template = this.templates.notFound; 1738 this._resetLastSuggestion(); 1739 template && this.$el.html(template({ 1740 query: query, 1741 dataset: this.name 1742 })); 1743 }, 1744 _empty: function empty() { 1745 this.$el.empty(); 1746 this._resetLastSuggestion(); 1747 }, 1748 _getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) { 1749 var that = this, fragment; 1750 fragment = document.createDocumentFragment(); 1751 _.each(suggestions, function getSuggestionNode(suggestion) { 1752 var $el, context; 1753 context = that._injectQuery(query, suggestion); 1754 $el = $(that.templates.suggestion(context)).data(keys.dataset, that.name).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + " " + that.classes.selectable); 1755 fragment.appendChild($el[0]); 1756 }); 1757 this.highlight && highlight({ 1758 className: this.classes.highlight, 1759 node: fragment, 1760 pattern: query 1761 }); 1762 return $(fragment); 1763 }, 1764 _getFooter: function getFooter(query, suggestions) { 1765 return this.templates.footer ? this.templates.footer({ 1766 query: query, 1767 suggestions: suggestions, 1768 dataset: this.name 1769 }) : null; 1770 }, 1771 _getHeader: function getHeader(query, suggestions) { 1772 return this.templates.header ? this.templates.header({ 1773 query: query, 1774 suggestions: suggestions, 1775 dataset: this.name 1776 }) : null; 1777 }, 1778 _resetLastSuggestion: function resetLastSuggestion() { 1779 this.$lastSuggestion = $(); 1780 }, 1781 _injectQuery: function injectQuery(query, obj) { 1782 return _.isObject(obj) ? _.mixin({ 1783 _query: query 1784 }, obj) : obj; 1785 }, 1786 update: function update(query) { 1787 var that = this, canceled = false, syncCalled = false, rendered = 0; 1788 this.cancel(); 1789 this.cancel = function cancel() { 1790 canceled = true; 1791 that.cancel = $.noop; 1792 that.async && that.trigger("asyncCanceled", query, that.name); 1793 }; 1794 this.source(query, sync, async); 1795 !syncCalled && sync([]); 1796 function sync(suggestions) { 1797 if (syncCalled) { 1798 return; 1799 } 1800 syncCalled = true; 1801 suggestions = (suggestions || []).slice(0, that.limit); 1802 rendered = suggestions.length; 1803 that._overwrite(query, suggestions); 1804 if (rendered < that.limit && that.async) { 1805 that.trigger("asyncRequested", query, that.name); 1806 } 1807 } 1808 function async(suggestions) { 1809 suggestions = suggestions || []; 1810 if (!canceled && rendered < that.limit) { 1811 that.cancel = $.noop; 1812 var idx = Math.abs(rendered - that.limit); 1813 rendered += idx; 1814 that._append(query, suggestions.slice(0, idx)); 1815 that.async && that.trigger("asyncReceived", query, that.name); 1816 } 1817 } 1818 }, 1819 cancel: $.noop, 1820 clear: function clear() { 1821 this._empty(); 1822 this.cancel(); 1823 this.trigger("cleared"); 1824 }, 1825 isEmpty: function isEmpty() { 1826 return this.$el.is(":empty"); 1827 }, 1828 destroy: function destroy() { 1829 this.$el = $("<div>"); 1830 } 1831 }); 1832 return Dataset; 1833 function getDisplayFn(display) { 1834 display = display || _.stringify; 1835 return _.isFunction(display) ? display : displayFn; 1836 function displayFn(obj) { 1837 return obj[display]; 1838 } 1839 } 1840 function getTemplates(templates, displayFn) { 1841 return { 1842 notFound: templates.notFound && _.templatify(templates.notFound), 1843 pending: templates.pending && _.templatify(templates.pending), 1844 header: templates.header && _.templatify(templates.header), 1845 footer: templates.footer && _.templatify(templates.footer), 1846 suggestion: templates.suggestion || suggestionTemplate 1847 };
vendor: 16,642 bytes, lines 1847-2206
1847 1848 function suggestionTemplate(context) { 1849 return $('<div role="option">').attr("id", _.guid()).text(displayFn(context)); 1850 } 1851 } 1852 function isValidName(str) { 1853 return /^[_a-zA-Z0-9-]+$/.test(str); 1854 } 1855 }(); 1856 var Menu = function() { 1857 "use strict"; 1858 function Menu(o, www) { 1859 var that = this; 1860 o = o || {}; 1861 if (!o.node) { 1862 $.error("node is required"); 1863 } 1864 www.mixin(this); 1865 this.$node = $(o.node); 1866 this.query = null; 1867 this.datasets = _.map(o.datasets, initializeDataset); 1868 function initializeDataset(oDataset) { 1869 var node = that.$node.find(oDataset.node).first(); 1870 oDataset.node = node.length ? node : $("<div>").appendTo(that.$node); 1871 return new Dataset(oDataset, www); 1872 } 1873 } 1874 _.mixin(Menu.prototype, EventEmitter, { 1875 _onSelectableClick: function onSelectableClick($e) { 1876 this.trigger("selectableClicked", $($e.currentTarget)); 1877 }, 1878 _onRendered: function onRendered(type, dataset, suggestions, async) { 1879 this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty()); 1880 this.trigger("datasetRendered", dataset, suggestions, async); 1881 }, 1882 _onCleared: function onCleared() { 1883 this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty()); 1884 this.trigger("datasetCleared"); 1885 }, 1886 _propagate: function propagate() { 1887 this.trigger.apply(this, arguments); 1888 }, 1889 _allDatasetsEmpty: function allDatasetsEmpty() { 1890 return _.every(this.datasets, _.bind(function isDatasetEmpty(dataset) { 1891 var isEmpty = dataset.isEmpty(); 1892 this.$node.attr("aria-expanded", !isEmpty); 1893 return isEmpty; 1894 }, this)); 1895 }, 1896 _getSelectables: function getSelectables() { 1897 return this.$node.find(this.selectors.selectable); 1898 }, 1899 _removeCursor: function _removeCursor() { 1900 var $selectable = this.getActiveSelectable(); 1901 $selectable && $selectable.removeClass(this.classes.cursor); 1902 }, 1903 _ensureVisible: function ensureVisible($el) { 1904 var elTop, elBottom, nodeScrollTop, nodeHeight; 1905 elTop = $el.position().top; 1906 elBottom = elTop + $el.outerHeight(true); 1907 nodeScrollTop = this.$node.scrollTop(); 1908 nodeHeight = this.$node.height() + parseInt(this.$node.css("paddingTop"), 10) + parseInt(this.$node.css("paddingBottom"), 10); 1909 if (elTop < 0) { 1910 this.$node.scrollTop(nodeScrollTop + elTop); 1911 } else if (nodeHeight < elBottom) { 1912 this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight)); 1913 } 1914 }, 1915 bind: function() { 1916 var that = this, onSelectableClick; 1917 onSelectableClick = _.bind(this._onSelectableClick, this); 1918 this.$node.on("click.tt", this.selectors.selectable, onSelectableClick); 1919 this.$node.on("mouseover", this.selectors.selectable, function() { 1920 that.setCursor($(this)); 1921 }); 1922 this.$node.on("mouseleave", function() { 1923 that._removeCursor(); 1924 }); 1925 _.each(this.datasets, function(dataset) { 1926 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); 1927 }); 1928 return this; 1929 }, 1930 isOpen: function isOpen() { 1931 return this.$node.hasClass(this.classes.open); 1932 }, 1933 open: function open() { 1934 this.$node.scrollTop(0); 1935 this.$node.addClass(this.classes.open); 1936 }, 1937 close: function close() { 1938 this.$node.attr("aria-expanded", false); 1939 this.$node.removeClass(this.classes.open); 1940 this._removeCursor(); 1941 }, 1942 setLanguageDirection: function setLanguageDirection(dir) { 1943 this.$node.attr("dir", dir); 1944 }, 1945 selectableRelativeToCursor: function selectableRelativeToCursor(delta) { 1946 var $selectables, $oldCursor, oldIndex, newIndex; 1947 $oldCursor = this.getActiveSelectable(); 1948 $selectables = this._getSelectables(); 1949 oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1; 1950 newIndex = oldIndex + delta; 1951 newIndex = (newIndex + 1) % ($selectables.length + 1) - 1; 1952 newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex; 1953 return newIndex === -1 ? null : $selectables.eq(newIndex); 1954 }, 1955 setCursor: function setCursor($selectable) { 1956 this._removeCursor(); 1957 if ($selectable = $selectable && $selectable.first()) { 1958 $selectable.addClass(this.classes.cursor); 1959 this._ensureVisible($selectable); 1960 } 1961 }, 1962 getSelectableData: function getSelectableData($el) { 1963 return $el && $el.length ? Dataset.extractData($el) : null; 1964 }, 1965 getActiveSelectable: function getActiveSelectable() { 1966 var $selectable = this._getSelectables().filter(this.selectors.cursor).first(); 1967 return $selectable.length ? $selectable : null; 1968 }, 1969 getTopSelectable: function getTopSelectable() { 1970 var $selectable = this._getSelectables().first(); 1971 return $selectable.length ? $selectable : null; 1972 }, 1973 update: function update(query) { 1974 var isValidUpdate = query !== this.query; 1975 if (isValidUpdate) { 1976 this.query = query; 1977 _.each(this.datasets, updateDataset); 1978 } 1979 return isValidUpdate; 1980 function updateDataset(dataset) { 1981 dataset.update(query); 1982 } 1983 }, 1984 empty: function empty() { 1985 _.each(this.datasets, clearDataset); 1986 this.query = null; 1987 this.$node.addClass(this.classes.empty); 1988 function clearDataset(dataset) { 1989 dataset.clear(); 1990 } 1991 }, 1992 destroy: function destroy() { 1993 this.$node.off(".tt"); 1994 this.$node = $("<div>"); 1995 _.each(this.datasets, destroyDataset); 1996 function destroyDataset(dataset) { 1997 dataset.destroy(); 1998 } 1999 } 2000 }); 2001 return Menu; 2002 }(); 2003 var Status = function() { 2004 "use strict"; 2005 function Status(options) { 2006 this.$el = $("<span></span>", { 2007 role: "status", 2008 "aria-live": "polite" 2009 }).css({ 2010 position: "absolute", 2011 padding: "0", 2012 border: "0", 2013 height: "1px", 2014 width: "1px", 2015 "margin-bottom": "-1px", 2016 "margin-right": "-1px", 2017 overflow: "hidden", 2018 clip: "rect(0 0 0 0)", 2019 "white-space": "nowrap" 2020 }); 2021 options.$input.after(this.$el); 2022 _.each(options.menu.datasets, _.bind(function(dataset) { 2023 if (dataset.onSync) { 2024 dataset.onSync("rendered", _.bind(this.update, this)); 2025 dataset.onSync("cleared", _.bind(this.cleared, this)); 2026 } 2027 }, this)); 2028 } 2029 _.mixin(Status.prototype, { 2030 update: function update(event, suggestions) { 2031 var length = suggestions.length; 2032 var words; 2033 if (length === 1) { 2034 words = { 2035 result: "result", 2036 is: "is" 2037 }; 2038 } else { 2039 words = { 2040 result: "results", 2041 is: "are" 2042 }; 2043 } 2044 this.$el.text(length + " " + words.result + " " + words.is + " available, use up and down arrow keys to navigate."); 2045 }, 2046 cleared: function() { 2047 this.$el.text(""); 2048 } 2049 }); 2050 return Status; 2051 }(); 2052 var DefaultMenu = function() { 2053 "use strict"; 2054 var s = Menu.prototype; 2055 function DefaultMenu() { 2056 Menu.apply(this, [].slice.call(arguments, 0)); 2057 } 2058 _.mixin(DefaultMenu.prototype, Menu.prototype, { 2059 open: function open() { 2060 !this._allDatasetsEmpty() && this._show(); 2061 return s.open.apply(this, [].slice.call(arguments, 0)); 2062 }, 2063 close: function close() { 2064 this._hide(); 2065 return s.close.apply(this, [].slice.call(arguments, 0)); 2066 }, 2067 _onRendered: function onRendered() { 2068 if (this._allDatasetsEmpty()) { 2069 this._hide(); 2070 } else { 2071 this.isOpen() && this._show(); 2072 } 2073 return s._onRendered.apply(this, [].slice.call(arguments, 0)); 2074 }, 2075 _onCleared: function onCleared() { 2076 if (this._allDatasetsEmpty()) { 2077 this._hide(); 2078 } else { 2079 this.isOpen() && this._show(); 2080 } 2081 return s._onCleared.apply(this, [].slice.call(arguments, 0)); 2082 }, 2083 setLanguageDirection: function setLanguageDirection(dir) { 2084 this.$node.css(dir === "ltr" ? this.css.ltr : this.css.rtl); 2085 return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0)); 2086 }, 2087 _hide: function hide() { 2088 this.$node.hide(); 2089 }, 2090 _show: function show() { 2091 this.$node.css("display", "block"); 2092 } 2093 }); 2094 return DefaultMenu; 2095 }(); 2096 var Typeahead = function() { 2097 "use strict"; 2098 function Typeahead(o, www) { 2099 var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged, onWhitespaceChanged; 2100 o = o || {}; 2101 if (!o.input) { 2102 $.error("missing input"); 2103 } 2104 if (!o.menu) { 2105 $.error("missing menu"); 2106 } 2107 if (!o.eventBus) { 2108 $.error("missing event bus"); 2109 } 2110 www.mixin(this); 2111 this.eventBus = o.eventBus; 2112 this.minLength = _.isNumber(o.minLength) ? o.minLength : 1; 2113 this.input = o.input; 2114 this.menu = o.menu; 2115 this.enabled = true; 2116 this.autoselect = !!o.autoselect; 2117 this.active = false; 2118 this.input.hasFocus() && this.activate(); 2119 this.dir = this.input.getLangDir(); 2120 this._hacks(); 2121 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); 2122 onFocused = c(this, "activate", "open", "_onFocused"); 2123 onBlurred = c(this, "deactivate", "_onBlurred"); 2124 onEnterKeyed = c(this, "isActive", "isOpen", "_onEnterKeyed"); 2125 onTabKeyed = c(this, "isActive", "isOpen", "_onTabKeyed"); 2126 onEscKeyed = c(this, "isActive", "_onEscKeyed"); 2127 onUpKeyed = c(this, "isActive", "open", "_onUpKeyed"); 2128 onDownKeyed = c(this, "isActive", "open", "_onDownKeyed"); 2129 onLeftKeyed = c(this, "isActive", "isOpen", "_onLeftKeyed"); 2130 onRightKeyed = c(this, "isActive", "isOpen", "_onRightKeyed"); 2131 onQueryChanged = c(this, "_openIfActive", "_onQueryChanged"); 2132 onWhitespaceChanged = c(this, "_openIfActive", "_onWhitespaceChanged"); 2133 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); 2134 } 2135 _.mixin(Typeahead.prototype, { 2136 _hacks: function hacks() { 2137 var $input, $menu; 2138 $input = this.input.$input || $("<div>"); 2139 $menu = this.menu.$node || $("<div>"); 2140 $input.on("blur.tt", function($e) { 2141 var active, isActive, hasActive; 2142 active = document.activeElement; 2143 isActive = $menu.is(active); 2144 hasActive = $menu.has(active).length > 0; 2145 if (_.isMsie() && (isActive || hasActive)) { 2146 $e.preventDefault(); 2147 $e.stopImmediatePropagation(); 2148 _.defer(function() { 2149 $input.focus(); 2150 }); 2151 } 2152 }); 2153 $menu.on("mousedown.tt", function($e) { 2154 $e.preventDefault(); 2155 }); 2156 }, 2157 _onSelectableClicked: function onSelectableClicked(type, $el) { 2158 this.select($el); 2159 }, 2160 _onDatasetCleared: function onDatasetCleared() { 2161 this._updateHint(); 2162 }, 2163 _onDatasetRendered: function onDatasetRendered(type, suggestions, async, dataset) { 2164 this._updateHint(); 2165 if (this.autoselect) { 2166 var cursorClass = this.selectors.cursor.substr(1); 2167 this.menu.$node.find(this.selectors.suggestion).first().addClass(cursorClass); 2168 } 2169 this.eventBus.trigger("render", suggestions, async, dataset); 2170 }, 2171 _onAsyncRequested: function onAsyncRequested(type, dataset, query) { 2172 this.eventBus.trigger("asyncrequest", query, dataset); 2173 }, 2174 _onAsyncCanceled: function onAsyncCanceled(type, dataset, query) { 2175 this.eventBus.trigger("asynccancel", query, dataset); 2176 }, 2177 _onAsyncReceived: function onAsyncReceived(type, dataset, query) { 2178 this.eventBus.trigger("asyncreceive", query, dataset); 2179 }, 2180 _onFocused: function onFocused() { 2181 this._minLengthMet() && this.menu.update(this.input.getQuery()); 2182 }, 2183 _onBlurred: function onBlurred() { 2184 if (this.input.hasQueryChangedSinceLastFocus()) { 2185 this.eventBus.trigger("change", this.input.getQuery()); 2186 } 2187 }, 2188 _onEnterKeyed: function onEnterKeyed(type, $e) { 2189 var $selectable; 2190 if ($selectable = this.menu.getActiveSelectable()) { 2191 if (this.select($selectable)) { 2192 $e.preventDefault(); 2193 $e.stopPropagation(); 2194 } 2195 } else if (this.autoselect) { 2196 if (this.select(this.menu.getTopSelectable())) { 2197 $e.preventDefault(); 2198 $e.stopPropagation(); 2199 } 2200 } 2201 }, 2202 _onTabKeyed: function onTabKeyed(type, $e) { 2203 var $selectable; 2204 if ($selectable = this.menu.getActiveSelectable()) { 2205 this.select($selectable) && $e.preventDefault(); 2206 } else if (
vendor: 7,114 bytes, lines 2206-2367
2206$selectable = this.menu.getTopSelectable()) { 2207 this.autocomplete($selectable) && $e.preventDefault(); 2208 } 2209 }, 2210 _onEscKeyed: function onEscKeyed() { 2211 this.close(); 2212 }, 2213 _onUpKeyed: function onUpKeyed() { 2214 this.moveCursor(-1); 2215 }, 2216 _onDownKeyed: function onDownKeyed() { 2217 this.moveCursor(+1); 2218 }, 2219 _onLeftKeyed: function onLeftKeyed() { 2220 if (this.dir === "rtl" && this.input.isCursorAtEnd()) { 2221 this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable()); 2222 } 2223 }, 2224 _onRightKeyed: function onRightKeyed() { 2225 if (this.dir === "ltr" && this.input.isCursorAtEnd()) { 2226 this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable()); 2227 } 2228 }, 2229 _onQueryChanged: function onQueryChanged(e, query) { 2230 this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty(); 2231 }, 2232 _onWhitespaceChanged: function onWhitespaceChanged() { 2233 this._updateHint(); 2234 }, 2235 _onLangDirChanged: function onLangDirChanged(e, dir) { 2236 if (this.dir !== dir) { 2237 this.dir = dir; 2238 this.menu.setLanguageDirection(dir); 2239 } 2240 }, 2241 _openIfActive: function openIfActive() { 2242 this.isActive() && this.open(); 2243 }, 2244 _minLengthMet: function minLengthMet(query) { 2245 query = _.isString(query) ? query : this.input.getQuery() || ""; 2246 return query.length >= this.minLength; 2247 }, 2248 _updateHint: function updateHint() { 2249 var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match; 2250 $selectable = this.menu.getTopSelectable(); 2251 data = this.menu.getSelectableData($selectable); 2252 val = this.input.getInputValue(); 2253 if (data && !_.isBlankString(val) && !this.input.hasOverflow()) { 2254 query = Input.normalizeQuery(val); 2255 escapedQuery = _.escapeRegExChars(query); 2256 frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i"); 2257 match = frontMatchRegEx.exec(data.val); 2258 match && this.input.setHint(val + match[1]); 2259 } else { 2260 this.input.clearHint(); 2261 } 2262 }, 2263 isEnabled: function isEnabled() { 2264 return this.enabled; 2265 }, 2266 enable: function enable() { 2267 this.enabled = true; 2268 }, 2269 disable: function disable() { 2270 this.enabled = false; 2271 }, 2272 isActive: function isActive() { 2273 return this.active; 2274 }, 2275 activate: function activate() { 2276 if (this.isActive()) { 2277 return true; 2278 } else if (!this.isEnabled() || this.eventBus.before("active")) { 2279 return false; 2280 } else { 2281 this.active = true; 2282 this.eventBus.trigger("active"); 2283 return true; 2284 } 2285 }, 2286 deactivate: function deactivate() { 2287 if (!this.isActive()) { 2288 return true; 2289 } else if (this.eventBus.before("idle")) { 2290 return false; 2291 } else { 2292 this.active = false; 2293 this.close(); 2294 this.eventBus.trigger("idle"); 2295 return true; 2296 } 2297 }, 2298 isOpen: function isOpen() { 2299 return this.menu.isOpen(); 2300 }, 2301 open: function open() { 2302 if (!this.isOpen() && !this.eventBus.before("open")) { 2303 this.menu.open(); 2304 this._updateHint(); 2305 this.eventBus.trigger("open"); 2306 } 2307 return this.isOpen(); 2308 }, 2309 close: function close() { 2310 if (this.isOpen() && !this.eventBus.before("close")) { 2311 this.menu.close(); 2312 this.input.clearHint(); 2313 this.input.resetInputValue(); 2314 this.eventBus.trigger("close"); 2315 } 2316 return !this.isOpen(); 2317 }, 2318 setVal: function setVal(val) { 2319 this.input.setQuery(_.toStr(val)); 2320 }, 2321 getVal: function getVal() { 2322 return this.input.getQuery(); 2323 }, 2324 select: function select($selectable) { 2325 var data = this.menu.getSelectableData($selectable); 2326 if (data && !this.eventBus.before("select", data.obj, data.dataset)) { 2327 this.input.setQuery(data.val, true); 2328 this.eventBus.trigger("select", data.obj, data.dataset); 2329 this.close(); 2330 return true; 2331 } 2332 return false; 2333 }, 2334 autocomplete: function autocomplete($selectable) { 2335 var query, data, isValid; 2336 query = this.input.getQuery(); 2337 data = this.menu.getSelectableData($selectable); 2338 isValid = data && query !== data.val; 2339 if (isValid && !this.eventBus.before("autocomplete", data.obj, data.dataset)) { 2340 this.input.setQuery(data.val); 2341 this.eventBus.trigger("autocomplete", data.obj, data.dataset); 2342 return true; 2343 } 2344 return false; 2345 }, 2346 moveCursor: function moveCursor(delta) { 2347 var query, $candidate, data, suggestion, datasetName, cancelMove, id; 2348 query = this.input.getQuery(); 2349 $candidate = this.menu.selectableRelativeToCursor(delta); 2350 data = this.menu.getSelectableData($candidate); 2351 suggestion = data ? data.obj : null; 2352 datasetName = data ? data.dataset : null; 2353 id = $candidate ? $candidate.attr("id") : null; 2354 this.input.trigger("cursorchange", id); 2355 cancelMove = this._minLengthMet() && this.menu.update(query); 2356 if (!cancelMove && !this.eventBus.before("cursorchange", suggestion, datasetName)) { 2357 this.menu.setCursor($candidate); 2358 if (data) { 2359 this.input.setInputValue(data.val); 2360 } else { 2361 this.input.resetInputValue(); 2362 this._updateHint(); 2363 } 2364 this.eventBus.trigger("cursorchange", suggestion, datasetName); 2365 return true; 2366 } 2367 return false;
vendor: 2,552 bytes, lines 2368-2427
2368 }, 2369 destroy: function destroy() { 2370 this.input.destroy(); 2371 this.menu.destroy(); 2372 } 2373 }); 2374 return Typeahead; 2375 function c(ctx) { 2376 var methods = [].slice.call(arguments, 1); 2377 return function() { 2378 var args = [].slice.call(arguments); 2379 _.each(methods, function(method) { 2380 return ctx[method].apply(ctx, args); 2381 }); 2382 }; 2383 } 2384 }(); 2385 (function() { 2386 "use strict"; 2387 var old, keys, methods; 2388 old = $.fn.typeahead; 2389 keys = { 2390 www: "tt-www", 2391 attrs: "tt-attrs", 2392 typeahead: "tt-typeahead" 2393 }; 2394 methods = { 2395 initialize: function initialize(o, datasets) { 2396 var www; 2397 datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1); 2398 o = o || {}; 2399 www = WWW(o.classNames); 2400 return this.each(attach); 2401 function attach() { 2402 var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, status, typeahead, MenuConstructor; 2403 _.each(datasets, function(d) { 2404 d.highlight = !!o.highlight; 2405 }); 2406 $input = $(this); 2407 $wrapper = $(www.html.wrapper); 2408 $hint = $elOrNull(o.hint); 2409 $menu = $elOrNull(o.menu); 2410 defaultHint = o.hint !== false && !$hint; 2411 defaultMenu = o.menu !== false && !$menu; 2412 defaultHint && ($hint = buildHintFromInput($input, www)); 2413 defaultMenu && ($menu = $(www.html.menu).css(www.css.menu)); 2414 $hint && $hint.val(""); 2415 $input = prepInput($input, www); 2416 if (defaultHint || defaultMenu) { 2417 $wrapper.css(www.css.wrapper); 2418 $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint); 2419 $input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null); 2420 } 2421 MenuConstructor = defaultMenu ? DefaultMenu : Menu; 2422 eventBus = new EventBus({ 2423 el: $input 2424 }); 2425 input = new Input({ 2426 hint: $hint, 2427 input: $input
vendor: 7,106 bytes, lines 2427-2621
2427 2428 }, www); 2429 menu = new MenuConstructor({ 2430 node: $menu, 2431 datasets: datasets 2432 }, www); 2433 status = new Status({ 2434 $input: $input, 2435 menu: menu 2436 }); 2437 typeahead = new Typeahead({ 2438 input: input, 2439 menu: menu, 2440 eventBus: eventBus, 2441 minLength: o.minLength, 2442 autoselect: o.autoselect 2443 }, www); 2444 $input.data(keys.www, www); 2445 $input.data(keys.typeahead, typeahead); 2446 } 2447 }, 2448 isEnabled: function isEnabled() { 2449 var enabled; 2450 ttEach(this.first(), function(t) { 2451 enabled = t.isEnabled(); 2452 }); 2453 return enabled; 2454 }, 2455 enable: function enable() { 2456 ttEach(this, function(t) { 2457 t.enable(); 2458 }); 2459 return this; 2460 }, 2461 disable: function disable() { 2462 ttEach(this, function(t) { 2463 t.disable(); 2464 }); 2465 return this; 2466 }, 2467 isActive: function isActive() { 2468 var active; 2469 ttEach(this.first(), function(t) { 2470 active = t.isActive(); 2471 }); 2472 return active; 2473 }, 2474 activate: function activate() { 2475 ttEach(this, function(t) { 2476 t.activate(); 2477 }); 2478 return this; 2479 }, 2480 deactivate: function deactivate() { 2481 ttEach(this, function(t) { 2482 t.deactivate(); 2483 }); 2484 return this; 2485 }, 2486 isOpen: function isOpen() { 2487 var open; 2488 ttEach(this.first(), function(t) { 2489 open = t.isOpen(); 2490 }); 2491 return open; 2492 }, 2493 open: function open() { 2494 ttEach(this, function(t) { 2495 t.open(); 2496 }); 2497 return this; 2498 }, 2499 close: function close() { 2500 ttEach(this, function(t) { 2501 t.close(); 2502 }); 2503 return this; 2504 }, 2505 select: function select(el) { 2506 var success = false, $el = $(el); 2507 ttEach(this.first(), function(t) { 2508 success = t.select($el); 2509 }); 2510 return success; 2511 }, 2512 autocomplete: function autocomplete(el) { 2513 var success = false, $el = $(el); 2514 ttEach(this.first(), function(t) { 2515 success = t.autocomplete($el); 2516 }); 2517 return success; 2518 }, 2519 moveCursor: function moveCursoe(delta) { 2520 var success = false; 2521 ttEach(this.first(), function(t) { 2522 success = t.moveCursor(delta); 2523 }); 2524 return success; 2525 }, 2526 val: function val(newVal) { 2527 var query; 2528 if (!arguments.length) { 2529 ttEach(this.first(), function(t) { 2530 query = t.getVal(); 2531 }); 2532 return query; 2533 } else { 2534 ttEach(this, function(t) { 2535 t.setVal(_.toStr(newVal)); 2536 }); 2537 return this; 2538 } 2539 }, 2540 destroy: function destroy() { 2541 ttEach(this, function(typeahead, $input) { 2542 revert($input); 2543 typeahead.destroy(); 2544 }); 2545 return this; 2546 } 2547 }; 2548 $.fn.typeahead = function(method) { 2549 if (methods[method]) { 2550 return methods[method].apply(this, [].slice.call(arguments, 1)); 2551 } else { 2552 return methods.initialize.apply(this, arguments); 2553 } 2554 }; 2555 $.fn.typeahead.noConflict = function noConflict() { 2556 $.fn.typeahead = old; 2557 return this; 2558 }; 2559 function ttEach($els, fn) { 2560 $els.each(function() { 2561 var $input = $(this), typeahead; 2562 (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input); 2563 }); 2564 } 2565 function buildHintFromInput($input, www) { 2566 return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop({ 2567 readonly: true, 2568 required: false 2569 }).removeAttr("id name placeholder").removeClass("required").attr({ 2570 spellcheck: "false", 2571 tabindex: -1 2572 }); 2573 } 2574 function prepInput($input, www) { 2575 $input.data(keys.attrs, { 2576 dir: $input.attr("dir"), 2577 autocomplete: $input.attr("autocomplete"), 2578 spellcheck: $input.attr("spellcheck"), 2579 style: $input.attr("style") 2580 }); 2581 $input.addClass(www.classes.input).attr({ 2582 spellcheck: false 2583 }); 2584 try { 2585 !$input.attr("dir") && $input.attr("dir", "auto"); 2586 } catch (e) {} 2587 return $input; 2588 } 2589 function getBackgroundStyles($el) { 2590 return { 2591 backgroundAttachment: $el.css("background-attachment"), 2592 backgroundClip: $el.css("background-clip"), 2593 backgroundColor: $el.css("background-color"), 2594 backgroundImage: $el.css("background-image"), 2595 backgroundOrigin: $el.css("background-origin"), 2596 backgroundPosition: $el.css("background-position"), 2597 backgroundRepeat: $el.css("background-repeat"), 2598 backgroundSize: $el.css("background-size") 2599 }; 2600 } 2601 function revert($input) { 2602 var www, $wrapper; 2603 www = $input.data(keys.www); 2604 $wrapper = $input.parent().filter(www.selectors.wrapper); 2605 _.each($input.data(keys.attrs), function(val, key) { 2606 _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val); 2607 }); 2608 $input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input); 2609 if ($wrapper.length) { 2610 $input.detach().insertAfter($wrapper); 2611 $wrapper.remove(); 2612 } 2613 } 2614 function $elOrNull(obj) { 2615 var isValid, $el; 2616 isValid = _.isJQuery(obj) || _.isElement(obj); 2617 $el = isValid ? $(obj).first() : []; 2618 return $el.length ? $el : null; 2619 } 2620 })(); 2621});
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.