web: update typeahead.js to 0.10.4

This commit is contained in:
Simon Michael 2014-07-29 10:50:23 -07:00
parent 3ce34b145c
commit 50ef6d52dd
2 changed files with 274 additions and 232 deletions

View File

@ -1,11 +1,13 @@
/*!
* typeahead.js 0.10.2
* typeahead.js 0.10.4
* https://github.com/twitter/typeahead.js
* Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
*/
(function($) {
var _ = {
var _ = function() {
"use strict";
return {
isMsie: function() {
return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
},
@ -27,6 +29,9 @@
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);
@ -120,8 +125,10 @@
},
noop: function() {}
};
var VERSION = "0.10.2";
var tokenizers = function(root) {
}();
var VERSION = "0.10.4";
var tokenizers = function() {
"use strict";
return {
nonword: nonword,
whitespace: whitespace,
@ -130,26 +137,35 @@
whitespace: getObjTokenizer(whitespace)
}
};
function whitespace(s) {
return s.split(/\s+/);
function whitespace(str) {
str = _.toStr(str);
return str ? str.split(/\s+/) : [];
}
function nonword(s) {
return s.split(/\W+/);
function nonword(str) {
str = _.toStr(str);
return str ? str.split(/\W+/) : [];
}
function getObjTokenizer(tokenizer) {
return function setKey(key) {
return function setKey() {
var args = [].slice.call(arguments, 0);
return function tokenize(o) {
return tokenizer(o[key]);
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 = maxSize || 100;
this.size = 0;
this.hash = {};
this.list = new List();
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) {
@ -174,6 +190,11 @@
this.list.moveToFront(node);
return node.val;
}
},
reset: function reset() {
this.size = 0;
this.hash = {};
this.list = new List();
}
});
function List() {
@ -205,6 +226,7 @@
return LruCache;
}();
var PersistentStorage = function() {
"use strict";
var ls, methods;
try {
ls = window.localStorage;
@ -216,7 +238,7 @@
function PersistentStorage(namespace) {
this.prefix = [ "__", namespace, "__" ].join("");
this.ttlKey = "__ttl__";
this.keyMatcher = new RegExp("^" + this.prefix);
this.keyMatcher = new RegExp("^" + _.escapeRegExChars(this.prefix));
}
if (ls && window.JSON) {
methods = {
@ -284,21 +306,28 @@
}
}();
var Transport = function() {
var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, requestCache = new LruCache(10);
"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 clearCache() {
requestCache = new LruCache(10);
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) {
@ -309,7 +338,7 @@
}
function done(resp) {
cb && cb(null, resp);
requestCache.set(url, resp);
that._cache.set(url, resp);
}
function fail() {
cb && cb(true);
@ -329,7 +358,9 @@
cb = o;
o = {};
}
if (resp = requestCache.get(url)) {
this.cancelled = false;
this.lastUrl = url;
if (resp = this._cache.get(url)) {
_.defer(function() {
cb && cb(null, resp);
});
@ -337,6 +368,9 @@
this._get(url, o, cb);
}
return !!resp;
},
cancel: function() {
this.cancelled = true;
}
});
return Transport;
@ -359,6 +393,7 @@
}
}();
var SearchIndex = function() {
"use strict";
function SearchIndex(o) {
o = o || {};
if (!o.datumTokenizer || !o.queryTokenizer) {
@ -370,12 +405,10 @@
}
_.mixin(SearchIndex.prototype, {
bootstrap: function bootstrap(o) {
console.log('bootstrap',o);
this.datums = o.datums;
this.trie = o.trie;
},
add: function(data) {
console.log('add',data);
var that = this;
data = _.isArray(data) ? data : [ data ];
_.each(data, function(datum) {
@ -394,32 +427,18 @@
});
},
get: function get(query) {
console.log('trie',this.trie);
var that = this, tokens, matches;
tokens = normalizeTokens(this.queryTokenizer(query));
// console.log('query',query);
// console.log('tokens',tokens);
_.each(tokens, function(token) {
var node, chars, ch, ids;
if (matches && matches.length === 0) {
return false;
}
node = that.trie;
// console.log('token',token);
// console.log('token split',token.split(""));
//whatever variable is used in the following while loop is losing the first character sometimes
chars = token.split("");
// console.log('pre node',node);
// console.log('pre chars',chars);
// console.log('ch1',ch = chars.shift());
// console.log('node1',node = node.children[ch]);
// console.log('ch2',ch = chars.shift());
// console.log('node2',node = node.children[ch]);
while (node && (ch = chars.shift())) {
node = node.children[ch];
}
// console.log('final node',node);
// console.log('final chars',chars);
if (node && chars.length === 0) {
ids = node.ids.slice(0);
matches = matches ? getIntersection(matches, ids) : ids;
@ -428,7 +447,6 @@
return false;
}
});
// console.log('matches',matches);
return matches ? _.map(unique(matches), function(id) {
return that.datums[id];
}) : [];
@ -462,7 +480,7 @@
}
function unique(array) {
var seen = {}, uniques = [];
for (var i = 0; i < array.length; i++) {
for (var i = 0, len = array.length; i < len; i++) {
if (!seen[array[i]]) {
seen[array[i]] = true;
uniques.push(array[i]);
@ -474,7 +492,8 @@
var ai = 0, bi = 0, intersection = [];
arrayA = arrayA.sort(compare);
arrayB = arrayB.sort(compare);
while (ai < arrayA.length && bi < arrayB.length) {
var lenArrayA = arrayA.length, lenArrayB = arrayB.length;
while (ai < lenArrayA && bi < lenArrayB) {
if (arrayA[ai] < arrayB[bi]) {
ai++;
} else if (arrayA[ai] > arrayB[bi]) {
@ -492,6 +511,7 @@
}
}();
var oParser = function() {
"use strict";
return {
local: getLocal,
prefetch: getPrefetch,
@ -525,6 +545,7 @@
var remote, defaults;
defaults = {
url: null,
cache: true,
wildcard: "%QUERY",
replace: null,
rateLimitBy: "debounce",
@ -559,6 +580,7 @@
}
}();
(function(root) {
"use strict";
var old, keys;
old = root.Bloodhound;
keys = {
@ -607,6 +629,9 @@
},
_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);
@ -615,6 +640,9 @@
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);
@ -652,9 +680,7 @@
var that = this, matches = [], cacheHit = false;
matches = this.index.get(query);
matches = this.sorter(matches).slice(0, this.limit);
if (matches.length < this.limit && this.transport) {
cacheHit = this._getFromRemote(query, returnRemoteMatches);
}
matches.length < this.limit ? cacheHit = this._getFromRemote(query, returnRemoteMatches) : this._cancelLastRemoteRequest();
if (!cacheHit) {
(matches.length > 0 || !this.transport) && cb && cb(matches);
}
@ -698,13 +724,17 @@
return false;
}
})(this);
var html = {
var html = function() {
return {
wrapper: '<span class="twitter-typeahead"></span>',
dropdown: '<span class="tt-dropdown-menu"></span>',
dataset: '<div class="tt-dataset-%CLASS%"></div>',
suggestions: '<span class="tt-suggestions"></span>',
suggestion: '<div class="tt-suggestion"></div>'
};
}();
var css = function() {
"use strict";
var css = {
wrapper: {
position: "relative",
@ -715,7 +745,8 @@
top: "0",
left: "0",
borderColor: "transparent",
boxShadow: "none"
boxShadow: "none",
opacity: "1"
},
input: {
position: "relative",
@ -762,7 +793,10 @@
marginTop: "-1px"
});
}
return css;
}();
var EventBus = function() {
"use strict";
var namespace = "typeahead:";
function EventBus(o) {
if (!o || !o.el) {
@ -779,6 +813,7 @@
return EventBus;
}();
var EventEmitter = function() {
"use strict";
var splitter = /\s+/, nextTick = getNextTick();
return {
onSync: onSync,
@ -838,7 +873,7 @@
return flush;
function flush() {
var cancelled;
for (var i = 0; !cancelled && i < callbacks.length; i += 1) {
for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) {
cancelled = callbacks[i].apply(context, args) === false;
}
return !cancelled;
@ -868,6 +903,7 @@
}
}();
var highlight = function(doc) {
"use strict";
var defaults = {
node: null,
pattern: null,
@ -886,7 +922,7 @@
regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly);
traverse(o.node, hightlightTextNode);
function hightlightTextNode(textNode) {
var match, patternNode;
var match, patternNode, wrapperNode;
if (match = regex.exec(textNode.data)) {
wrapperNode = doc.createElement(o.tagName);
o.className && (wrapperNode.className = o.className);
@ -911,7 +947,7 @@
};
function getRegex(patterns, caseSensitive, wordsOnly) {
var escapedPatterns = [], regexStr;
for (var i = 0; i < patterns.length; i++) {
for (var i = 0, len = patterns.length; i < len; i++) {
escapedPatterns.push(_.escapeRegExChars(patterns[i]));
}
regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")";
@ -919,6 +955,7 @@
}
}(window.document);
var Input = function() {
"use strict";
var specialKeyCodeMap;
specialKeyCodeMap = {
9: "tab",
@ -1014,8 +1051,9 @@
inputValue = this.getInputValue();
areEquivalent = areQueriesEquivalent(inputValue, this.query);
hasDifferentWhitespace = areEquivalent ? this.query.length !== inputValue.length : false;
this.query = inputValue;
if (!areEquivalent) {
this.trigger("queryChanged", this.query = inputValue);
this.trigger("queryChanged", this.query);
} else if (hasDifferentWhitespace) {
this.trigger("whitespaceChanged", this.query);
}
@ -1112,6 +1150,7 @@
}
}();
var Dataset = function() {
"use strict";
var datasetKey = "ttDataset", valueKey = "ttValue", datumKey = "ttDatum";
function Dataset(o) {
o = o || {};
@ -1165,19 +1204,13 @@
nodes = _.map(suggestions, getSuggestionNode);
$suggestions.append.apply($suggestions, nodes);
that.highlight && highlight({
className: "tt-highlight",
node: $suggestions[0],
pattern: query
});
return $suggestions;
function getSuggestionNode(suggestion) {
var $el;
// console.log(that.templates.suggestion(suggestion));
// console.log(datasetKey);
// console.log(that.name);
// console.log(valueKey);
// console.log(that.displayFn(suggestion));
// console.log(datumKey);
// console.log(suggestion);
$el = $(html.suggestion).append(that.templates.suggestion(suggestion)).data(datasetKey, that.name).data(valueKey, that.displayFn(suggestion)).data(datumKey, suggestion);
$el.children().each(function() {
$(this).css(css.suggestionChild);
@ -1251,6 +1284,7 @@
}
}();
var Dropdown = function() {
"use strict";
function Dropdown(o) {
var that = this, onSuggestionClick, onSuggestionMouseEnter, onSuggestionMouseLeave;
o = o || {};
@ -1410,6 +1444,7 @@
}
}();
var Typeahead = function() {
"use strict";
var attrsKey = "ttAttrs";
function Typeahead(o) {
var $menu, $input, $hint;
@ -1420,7 +1455,7 @@
this.isActivated = false;
this.autoselect = !!o.autoselect;
this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;
this.$node = buildDomStructure(o.input, o.withHint);
this.$node = buildDom(o.input, o.withHint);
$menu = this.$node.find(".tt-dropdown-menu");
$input = this.$node.find(".tt-input");
$hint = this.$node.find(".tt-hint");
@ -1588,6 +1623,7 @@
this.dropdown.close();
},
setVal: function setVal(val) {
val = _.toStr(val);
if (this.isActivated) {
this.input.setInputValue(val);
} else {
@ -1607,15 +1643,16 @@
}
});
return Typeahead;
function buildDomStructure(input, withHint) {
function buildDom(input, withHint) {
var $input, $wrapper, $dropdown, $hint;
$input = $(input);
$wrapper = $(html.wrapper).css(css.wrapper);
$dropdown = $(html.dropdown).css(css.dropdown);
$hint = $input.clone().css(css.hint).css(getBackgroundStyles($input));
$hint.val("").removeData().addClass("tt-hint").removeAttr("id name placeholder").prop("disabled", true).attr({
$hint.val("").removeData().addClass("tt-hint").removeAttr("id name placeholder required").prop("readonly", true).attr({
autocomplete: "off",
spellcheck: "false"
spellcheck: "false",
tabindex: -1
});
$input.data(attrsKey, {
dir: $input.attr("dir"),
@ -1654,6 +1691,7 @@
}
}();
(function() {
"use strict";
var old, typeaheadKey, methods;
old = $.fn.typeahead;
typeaheadKey = "ttTypeahead";
@ -1726,8 +1764,12 @@
}
};
$.fn.typeahead = function(method) {
if (methods[method]) {
return methods[method].apply(this, [].slice.call(arguments, 1));
var tts;
if (methods[method] && method !== "initialize") {
tts = this.filter(function() {
return !!$(this).data(typeaheadKey);
});
return methods[method].apply(tts, [].slice.call(arguments, 1));
} else {
return methods.initialize.apply(this, arguments);
}

File diff suppressed because one or more lines are too long