Blame | Last modification | View Log | RSS feed
/** typeahead.js* https://github.com/twitter/typeahead.js* Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT*/var SearchIndex = (function() {'use strict';// constructor// -----------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();}// instance methods// ----------------_.mixin(SearchIndex.prototype, {// ### publicbootstrap: 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;// previous tokens didn't share any matchesif (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;}// break early if we find out there are no possible matcheselse {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;// helper functions// ----------------function normalizeTokens(tokens) {// filter out falsy tokenstokens = _.filter(tokens, function(token) { return !!token; });// normalize tokenstokens = _.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; }}})();