Blame | Last modification | View Log | RSS feed
/*!* typeahead.js 0.10.5* https://github.com/twitter/typeahead.js* Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT*/(function($) {var _ = function() {"use strict";return {isMsie: function() {return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;},isBlankString: function(str) {return !str || /^\s*$/.test(str);},escapeRegExChars: function(str) {return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");},isString: function(obj) {return typeof obj === "string";},isNumber: function(obj) {return typeof obj === "number";},isArray: $.isArray,isFunction: $.isFunction,isObject: $.isPlainObject,isUndefined: function(obj) {return typeof obj === "undefined";},toStr: function toStr(s) {return _.isUndefined(s) || s === null ? "" : s + "";},bind: $.proxy,each: function(collection, cb) {$.each(collection, reverseArgs);function reverseArgs(index, value) {return cb(value, index);}},map: $.map,filter: $.grep,every: function(obj, test) {var result = true;if (!obj) {return result;}$.each(obj, function(key, val) {if (!(result = test.call(null, val, key, obj))) {return false;}});return !!result;},some: function(obj, test) {var result = false;if (!obj) {return result;}$.each(obj, function(key, val) {if (result = test.call(null, val, key, obj)) {return false;}});return !!result;},mixin: $.extend,getUniqueId: function() {var counter = 0;return function() {return counter++;};}(),templatify: function templatify(obj) {return $.isFunction(obj) ? obj : template;function template() {return String(obj);}},defer: function(fn) {setTimeout(fn, 0);},debounce: function(func, wait, immediate) {var timeout, result;return function() {var context = this, args = arguments, later, callNow;later = function() {timeout = null;if (!immediate) {result = func.apply(context, args);}};callNow = immediate && !timeout;clearTimeout(timeout);timeout = setTimeout(later, wait);if (callNow) {result = func.apply(context, args);}return result;};},throttle: function(func, wait) {var context, args, timeout, result, previous, later;previous = 0;later = function() {previous = new Date();timeout = null;result = func.apply(context, args);};return function() {var now = new Date(), remaining = wait - (now - previous);context = this;args = arguments;if (remaining <= 0) {clearTimeout(timeout);timeout = null;previous = now;result = func.apply(context, args);} else if (!timeout) {timeout = setTimeout(later, remaining);}return result;};},noop: function() {}};}();var VERSION = "0.10.5";var tokenizers = function() {"use strict";return {nonword: nonword,whitespace: whitespace,obj: {nonword: getObjTokenizer(nonword),whitespace: getObjTokenizer(whitespace)}};function whitespace(str) {str = _.toStr(str);return str ? str.split(/\s+/) : [];}function nonword(str) {str = _.toStr(str);return str ? str.split(/\W+/) : [];}function getObjTokenizer(tokenizer) {return function setKey() {var args = [].slice.call(arguments, 0);return function tokenize(o) {var tokens = [];_.each(args, function(k) {tokens = tokens.concat(tokenizer(_.toStr(o[k])));});return tokens;};};}}();var LruCache = function() {"use strict";function LruCache(maxSize) {this.maxSize = _.isNumber(maxSize) ? maxSize : 100;this.reset();if (this.maxSize <= 0) {this.set = this.get = $.noop;}}_.mixin(LruCache.prototype, {set: function set(key, val) {var tailItem = this.list.tail, node;if (this.size >= this.maxSize) {this.list.remove(tailItem);delete this.hash[tailItem.key];}if (node = this.hash[key]) {node.val = val;this.list.moveToFront(node);} else {node = new Node(key, val);this.list.add(node);this.hash[key] = node;this.size++;}},get: function get(key) {var node = this.hash[key];if (node) {this.list.moveToFront(node);return node.val;}},reset: function reset() {this.size = 0;this.hash = {};this.list = new List();}});function List() {this.head = this.tail = null;}_.mixin(List.prototype, {add: function add(node) {if (this.head) {node.next = this.head;this.head.prev = node;}this.head = node;this.tail = this.tail || node;},remove: function remove(node) {node.prev ? node.prev.next = node.next : this.head = node.next;node.next ? node.next.prev = node.prev : this.tail = node.prev;},moveToFront: function(node) {this.remove(node);this.add(node);}});function Node(key, val) {this.key = key;this.val = val;this.prev = this.next = null;}return LruCache;}();var PersistentStorage = function() {"use strict";var ls, methods;try {ls = window.localStorage;ls.setItem("~~~", "!");ls.removeItem("~~~");} catch (err) {ls = null;}function PersistentStorage(namespace) {this.prefix = [ "__", namespace, "__" ].join("");this.ttlKey = "__ttl__";this.keyMatcher = new RegExp("^" + _.escapeRegExChars(this.prefix));}if (ls && window.JSON) {methods = {_prefix: function(key) {return this.prefix + key;},_ttlKey: function(key) {return this._prefix(key) + this.ttlKey;},get: function(key) {if (this.isExpired(key)) {this.remove(key);}return decode(ls.getItem(this._prefix(key)));},set: function(key, val, ttl) {if (_.isNumber(ttl)) {ls.setItem(this._ttlKey(key), encode(now() + ttl));} else {ls.removeItem(this._ttlKey(key));}return ls.setItem(this._prefix(key), encode(val));},remove: function(key) {ls.removeItem(this._ttlKey(key));ls.removeItem(this._prefix(key));return this;},clear: function() {var i, key, keys = [], len = ls.length;for (i = 0; i < len; i++) {if ((key = ls.key(i)).match(this.keyMatcher)) {keys.push(key.replace(this.keyMatcher, ""));}}for (i = keys.length; i--; ) {this.remove(keys[i]);}return this;},isExpired: function(key) {var ttl = decode(ls.getItem(this._ttlKey(key)));return _.isNumber(ttl) && now() > ttl ? true : false;}};} else {methods = {get: _.noop,set: _.noop,remove: _.noop,clear: _.noop,isExpired: _.noop};}_.mixin(PersistentStorage.prototype, methods);return PersistentStorage;function now() {return new Date().getTime();}function encode(val) {return JSON.stringify(_.isUndefined(val) ? null : val);}function decode(val) {return JSON.parse(val);}}();var Transport = function() {"use strict";var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, sharedCache = new LruCache(10);function Transport(o) {o = o || {};this.cancelled = false;this.lastUrl = null;this._send = o.transport ? callbackToDeferred(o.transport) : $.ajax;this._get = o.rateLimiter ? o.rateLimiter(this._get) : this._get;this._cache = o.cache === false ? new LruCache(0) : sharedCache;}Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {maxPendingRequests = num;};Transport.resetCache = function resetCache() {sharedCache.reset();};_.mixin(Transport.prototype, {_get: function(url, o, cb) {var that = this, jqXhr;if (this.cancelled || url !== this.lastUrl) {return;}if (jqXhr = pendingRequests[url]) {jqXhr.done(done).fail(fail);} else if (pendingRequestsCount < maxPendingRequests) {pendingRequestsCount++;pendingRequests[url] = this._send(url, o).done(done).fail(fail).always(always);} else {this.onDeckRequestArgs = [].slice.call(arguments, 0);}function done(resp) {cb && cb(null, resp);that._cache.set(url, resp);}function fail() {cb && cb(true);}function always() {pendingRequestsCount--;delete pendingRequests[url];if (that.onDeckRequestArgs) {that._get.apply(that, that.onDeckRequestArgs);that.onDeckRequestArgs = null;}}},get: function(url, o, cb) {var resp;if (_.isFunction(o)) {cb = o;o = {};}this.cancelled = false;this.lastUrl = url;if (resp = this._cache.get(url)) {_.defer(function() {cb && cb(null, resp);});} else {this._get(url, o, cb);}return !!resp;},cancel: function() {this.cancelled = true;}});return Transport;function callbackToDeferred(fn) {return function customSendWrapper(url, o) {var deferred = $.Deferred();fn(url, o, onSuccess, onError);return deferred;function onSuccess(resp) {_.defer(function() {deferred.resolve(resp);});}function onError(err) {_.defer(function() {deferred.reject(err);});}};}}();var SearchIndex = function() {"use strict";function SearchIndex(o) {o = o || {};if (!o.datumTokenizer || !o.queryTokenizer) {$.error("datumTokenizer and queryTokenizer are both required");}this.datumTokenizer = o.datumTokenizer;this.queryTokenizer = o.queryTokenizer;this.reset();}_.mixin(SearchIndex.prototype, {bootstrap: function bootstrap(o) {this.datums = o.datums;this.trie = o.trie;},add: function(data) {var that = this;data = _.isArray(data) ? data : [ data ];_.each(data, function(datum) {var id, tokens;id = that.datums.push(datum) - 1;tokens = normalizeTokens(that.datumTokenizer(datum));_.each(tokens, function(token) {var node, chars, ch;node = that.trie;chars = token.split("");while (ch = chars.shift()) {node = node.children[ch] || (node.children[ch] = newNode());node.ids.push(id);}});});},get: function get(query) {var that = this, tokens, matches;tokens = normalizeTokens(this.queryTokenizer(query));_.each(tokens, function(token) {var node, chars, ch, ids;if (matches && matches.length === 0) {return false;}node = that.trie;chars = token.split("");while (node && (ch = chars.shift())) {node = node.children[ch];}if (node && chars.length === 0) {ids = node.ids.slice(0);matches = matches ? getIntersection(matches, ids) : ids;} else {matches = [];return false;}});return matches ? _.map(unique(matches), function(id) {return that.datums[id];}) : [];},reset: function reset() {this.datums = [];this.trie = newNode();},serialize: function serialize() {return {datums: this.datums,trie: this.trie};}});return SearchIndex;function normalizeTokens(tokens) {tokens = _.filter(tokens, function(token) {return !!token;});tokens = _.map(tokens, function(token) {return token.toLowerCase();});return tokens;}function newNode() {return {ids: [],children: {}};}function unique(array) {var seen = {}, uniques = [];for (var i = 0, len = array.length; i < len; i++) {if (!seen[array[i]]) {seen[array[i]] = true;uniques.push(array[i]);}}return uniques;}function getIntersection(arrayA, arrayB) {var ai = 0, bi = 0, intersection = [];arrayA = arrayA.sort(compare);arrayB = arrayB.sort(compare);var lenArrayA = arrayA.length, lenArrayB = arrayB.length;while (ai < lenArrayA && bi < lenArrayB) {if (arrayA[ai] < arrayB[bi]) {ai++;} else if (arrayA[ai] > arrayB[bi]) {bi++;} else {intersection.push(arrayA[ai]);ai++;bi++;}}return intersection;function compare(a, b) {return a - b;}}}();var oParser = function() {"use strict";return {local: getLocal,prefetch: getPrefetch,remote: getRemote};function getLocal(o) {return o.local || null;}function getPrefetch(o) {var prefetch, defaults;defaults = {url: null,thumbprint: "",ttl: 24 * 60 * 60 * 1e3,filter: null,ajax: {}};if (prefetch = o.prefetch || null) {prefetch = _.isString(prefetch) ? {url: prefetch} : prefetch;prefetch = _.mixin(defaults, prefetch);prefetch.thumbprint = VERSION + prefetch.thumbprint;prefetch.ajax.type = prefetch.ajax.type || "GET";prefetch.ajax.dataType = prefetch.ajax.dataType || "json";!prefetch.url && $.error("prefetch requires url to be set");}return prefetch;}function getRemote(o) {var remote, defaults;defaults = {url: null,cache: true,wildcard: "%QUERY",replace: null,rateLimitBy: "debounce",rateLimitWait: 300,send: null,filter: null,ajax: {}};if (remote = o.remote || null) {remote = _.isString(remote) ? {url: remote} : remote;remote = _.mixin(defaults, remote);remote.rateLimiter = /^throttle$/i.test(remote.rateLimitBy) ? byThrottle(remote.rateLimitWait) : byDebounce(remote.rateLimitWait);remote.ajax.type = remote.ajax.type || "GET";remote.ajax.dataType = remote.ajax.dataType || "json";delete remote.rateLimitBy;delete remote.rateLimitWait;!remote.url && $.error("remote requires url to be set");}return remote;function byDebounce(wait) {return function(fn) {return _.debounce(fn, wait);};}function byThrottle(wait) {return function(fn) {return _.throttle(fn, wait);};}}}();(function(root) {"use strict";var old, keys;old = root.Bloodhound;keys = {data: "data",protocol: "protocol",thumbprint: "thumbprint"};root.Bloodhound = Bloodhound;function Bloodhound(o) {if (!o || !o.local && !o.prefetch && !o.remote) {$.error("one of local, prefetch, or remote is required");}this.limit = o.limit || 5;this.sorter = getSorter(o.sorter);this.dupDetector = o.dupDetector || ignoreDuplicates;this.local = oParser.local(o);this.prefetch = oParser.prefetch(o);this.remote = oParser.remote(o);this.cacheKey = this.prefetch ? this.prefetch.cacheKey || this.prefetch.url : null;this.index = new SearchIndex({datumTokenizer: o.datumTokenizer,queryTokenizer: o.queryTokenizer});this.storage = this.cacheKey ? new PersistentStorage(this.cacheKey) : null;}Bloodhound.noConflict = function noConflict() {root.Bloodhound = old;return Bloodhound;};Bloodhound.tokenizers = tokenizers;_.mixin(Bloodhound.prototype, {_loadPrefetch: function loadPrefetch(o) {var that = this, serialized, deferred;if (serialized = this._readFromStorage(o.thumbprint)) {this.index.bootstrap(serialized);deferred = $.Deferred().resolve();} else {deferred = $.ajax(o.url, o.ajax).done(handlePrefetchResponse);}return deferred;function handlePrefetchResponse(resp) {that.clear();that.add(o.filter ? o.filter(resp) : resp);that._saveToStorage(that.index.serialize(), o.thumbprint, o.ttl);}},_getFromRemote: function getFromRemote(query, cb) {var that = this, url, uriEncodedQuery;if (!this.transport) {return;}query = query || "";uriEncodedQuery = encodeURIComponent(query);url = this.remote.replace ? this.remote.replace(this.remote.url, query) : this.remote.url.replace(this.remote.wildcard, uriEncodedQuery);return this.transport.get(url, this.remote.ajax, handleRemoteResponse);function handleRemoteResponse(err, resp) {err ? cb([]) : cb(that.remote.filter ? that.remote.filter(resp) : resp);}},_cancelLastRemoteRequest: function cancelLastRemoteRequest() {this.transport && this.transport.cancel();},_saveToStorage: function saveToStorage(data, thumbprint, ttl) {if (this.storage) {this.storage.set(keys.data, data, ttl);this.storage.set(keys.protocol, location.protocol, ttl);this.storage.set(keys.thumbprint, thumbprint, ttl);}},_readFromStorage: function readFromStorage(thumbprint) {var stored = {}, isExpired;if (this.storage) {stored.data = this.storage.get(keys.data);stored.protocol = this.storage.get(keys.protocol);stored.thumbprint = this.storage.get(keys.thumbprint);}isExpired = stored.thumbprint !== thumbprint || stored.protocol !== location.protocol;return stored.data && !isExpired ? stored.data : null;},_initialize: function initialize() {var that = this, local = this.local, deferred;deferred = this.prefetch ? this._loadPrefetch(this.prefetch) : $.Deferred().resolve();local && deferred.done(addLocalToIndex);this.transport = this.remote ? new Transport(this.remote) : null;return this.initPromise = deferred.promise();function addLocalToIndex() {that.add(_.isFunction(local) ? local() : local);}},initialize: function initialize(force) {return !this.initPromise || force ? this._initialize() : this.initPromise;},add: function add(data) {this.index.add(data);},get: function get(query, cb) {var that = this, matches = [], cacheHit = false;matches = this.index.get(query);matches = this.sorter(matches).slice(0, this.limit);matches.length < this.limit ? cacheHit = this._getFromRemote(query, returnRemoteMatches) : this._cancelLastRemoteRequest();if (!cacheHit) {(matches.length > 0 || !this.transport) && cb && cb(matches);}function returnRemoteMatches(remoteMatches) {var matchesWithBackfill = matches.slice(0);_.each(remoteMatches, function(remoteMatch) {var isDuplicate;isDuplicate = _.some(matchesWithBackfill, function(match) {return that.dupDetector(remoteMatch, match);});!isDuplicate && matchesWithBackfill.push(remoteMatch);return matchesWithBackfill.length < that.limit;});cb && cb(that.sorter(matchesWithBackfill));}},clear: function clear() {this.index.reset();},clearPrefetchCache: function clearPrefetchCache() {this.storage && this.storage.clear();},clearRemoteCache: function clearRemoteCache() {this.transport && Transport.resetCache();},ttAdapter: function ttAdapter() {return _.bind(this.get, this);}});return Bloodhound;function getSorter(sortFn) {return _.isFunction(sortFn) ? sort : noSort;function sort(array) {return array.sort(sortFn);}function noSort(array) {return array;}}function ignoreDuplicates() {return false;}})(this);})(window.jQuery);