很酷的一个自动补全插件

http://twitter.github.io/typeahead.js

在bootstrap中使用typeahead插件,完成自动补全

相关的文档:https://github.com/twitter/typeahead.js/blob/master/doc/jquery_typeahead.md

数据源:

Local:数组

prefectch:json

remote等方式

--------------------------------------------------------------------------------

Bootstrap3使用typeahead插件实现自动补全功能

html:

<input id="orderNo" class="typeahead" placeholder="Countries" type="text" class="form-control" name="ordersn"> 

js:

var states = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.whitespace,
queryTokenizer: Bloodhound.tokenizers.whitespace,
// `states` is an array of state names defined in "The Basics"
local: states
});
var findOrderByIdVague = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: '${ctx}/admin/order/preOrderByIdVague.json',
remote: {
url: '${ctx}/admin/order/findOrderByIdVague/%QUERY.json',
wildcard: '%QUERY'
},
afterSelect: function (item) {
//选择项之后的事件 ,item是当前选中的。
alert(iterm);
}
});
$(function(){
/**
$('#addCombo .typeahead').typeahead({
hint: true,
highlight: true,
minLength: 1
},
{
name: 'states',
source: states
});
**/
$('#addCombo .typeahead').typeahead(null, {
name: 'best-pictures',
display: 'value',
source: findOrderByIdVague
});
$('#addCombo .typeahead').bind('typeahead:select', function(ev, suggestion) {
console.log('Selection: ' + suggestion.value);
});
}); 
  …findOrderByIdVague/D20150502.json:
[ {
"value" : "D20150502173435141299"
}, {
"value" : "D20150502172928109304"
} ] 

preOrderByIdVague.json:

[{"value":"D201"}] 

docs 相关的事件: 

Custom Events
The following events get triggered on the input element during the life-cycle of a typeahead.
typeahead:active – Fired when the typeahead moves to active state.
typeahead:idle – Fired when the typeahead moves to idle state.
typeahead:open – Fired when the results container is opened.
typeahead:close – Fired when the results container is closed.
typeahead:change – Normalized version of the native change event. Fired when input loses focus and the value has changed since it originally received focus.
typeahead:render – Fired when suggestions are rendered for a dataset. The event handler will be invoked with 4 arguments: the jQuery event object, the suggestions that were rendered, a flag indicating whether the suggestions were fetched asynchronously, and the name of the dataset the rendering occurred in.
typeahead:select – Fired when a suggestion is selected. The event handler will be invoked with 2 arguments: the jQuery event object and the suggestion object that was selected.
typeahead:autocomplete – Fired when a autocompletion occurs. The event handler will be invoked with 2 arguments: the jQuery event object and the suggestion object that was used for autocompletion.
typeahead:cursorchange – Fired when the results container cursor moves. The event handler will be invoked with 2 arguments: the jQuery event object and the suggestion object that was moved to.
typeahead:asyncrequest – Fired when an async request for suggestions is sent. The event handler will be invoked with 3 arguments: the jQuery event object, the current query, and the name of the dataset the async request belongs to.
typeahead:asynccancel – Fired when an async request is cancelled. The event handler will be invoked with 3 arguments: the jQuery event object, the current query, and the name of the dataset the async request belonged to.
typeahead:asyncreceive – Fired when an async request completes. The event handler will be invoked with 3 arguments: the jQuery event object, the current query, and the name of the dataset the async request belongs to.
Example usage:
$('.typeahead').bind('typeahead:select', function(ev, suggestion) {
console.log('Selection: ' + suggestion);
}); 

typeahead.bundle.js:

/*!
* typeahead.js 0.11.1
* https://github.com/twitter/typeahead.js
* Copyright 2013-2015 Twitter, Inc. and other contributors; Licensed MIT
*/
(function(root, factory) {
if (typeof define === "function" && define.amd) {
define("bloodhound", [ "jquery" ], function(a0) {
return root["Bloodhound"] = factory(a0);
});
} else if (typeof exports === "object") {
module.exports = factory(require("jquery"));
} else {
root["Bloodhound"] = factory(jQuery);
}
})(this, function($) {
var _ = function() {
"use strict";
return {
isMsie: function() {
return /(msie|trident)/i.test(navigator.userAgent) "\\$&");
},
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";
},
isElement: function(obj) {
return !!(obj && obj.nodeType === 1);
},
isJQuery: function(obj) {
return obj instanceof $;
},
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,
identity: function(x) {
return x;
},
clone: function(obj) {
return $.extend(true, {}, obj);
},
getIdGenerator: function() {
var counter = 0;
return function() {
return counter++;
};
},
templatify: function templatify(obj) {
return $.isFunction(obj) "0.11.1";
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 "use strict";
function LruCache(maxSize) {
this.maxSize = _.isNumber(maxSize) "use strict";
var LOCAL_STORAGE;
try {
LOCAL_STORAGE = window.localStorage;
LOCAL_STORAGE.setItem("~~~", "!");
LOCAL_STORAGE.removeItem("~~~");
} catch (err) {
LOCAL_STORAGE = null;
}
function PersistentStorage(namespace, override) {
this.prefix = [ "__", namespace, "__" ].join("");
this.ttlKey = "__ttl__";
this.keyMatcher = new RegExp("^" + _.escapeRegExChars(this.prefix));
this.ls = override || LOCAL_STORAGE;
!this.ls && this._noop();
}
_.mixin(PersistentStorage.prototype, {
_prefix: function(key) {
return this.prefix + key;
},
_ttlKey: function(key) {
return this._prefix(key) + this.ttlKey;
},
_noop: function() {
this.get = this.set = this.remove = this.clear = this.isExpired = _.noop;
},
_safeSet: function(key, val) {
try {
this.ls.setItem(key, val);
} catch (err) {
if (err.name === "QuotaExceededError") {
this.clear();
this._noop();
}
}
},
get: function(key) {
if (this.isExpired(key)) {
this.remove(key);
}
return decode(this.ls.getItem(this._prefix(key)));
},
set: function(key, val, ttl) {
if (_.isNumber(ttl)) {
this._safeSet(this._ttlKey(key), encode(now() + ttl));
} else {
this.ls.removeItem(this._ttlKey(key));
}
return this._safeSet(this._prefix(key), encode(val));
},
remove: function(key) {
this.ls.removeItem(this._ttlKey(key));
this.ls.removeItem(this._prefix(key));
return this;
},
clear: function() {
var i, keys = gatherMatchingKeys(this.keyMatcher);
for (i = keys.length; i--; ) {
this.remove(keys[i]);
}
return this;
},
isExpired: function(key) {
var ttl = decode(this.ls.getItem(this._ttlKey(key)));
return _.isNumber(ttl) && now() > ttl ""));
}
}
return keys;
}
}();
var Transport = function() {
"use strict";
var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, sharedCache = new LruCache(10);
function Transport(o) {
o = o || {};
this.cancelled = false;
this.lastReq = null;
this._send = o.transport;
this._get = o.limiter "use strict";
var CHILDREN = "c", IDS = "i";
function SearchIndex(o) {
o = o || {};
if (!o.datumTokenizer || !o.queryTokenizer) {
$.error("datumTokenizer and queryTokenizer are both required");
}
this.identify = o.identify || _.stringify;
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) "");
while (ch = chars.shift()) {
node = node[CHILDREN][ch] || (node[CHILDREN][ch] = newNode());
node[IDS].push(id);
}
});
});
},
get: function get(ids) {
var that = this;
return _.map(ids, function(id) {
return that.datums[id];
});
},
search: function search(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 "use strict";
var keys;
keys = {
data: "data",
protocol: "protocol",
thumbprint: "thumbprint"
};
function Prefetch(o) {
this.url = o.url;
this.ttl = o.ttl;
this.cache = o.cache;
this.prepare = o.prepare;
this.transform = o.transform;
this.transport = o.transport;
this.thumbprint = o.thumbprint;
this.storage = new PersistentStorage(o.cacheKey);
}
_.mixin(Prefetch.prototype, {
_settings: function settings() {
return {
url: this.url,
type: "GET",
dataType: "json"
};
},
store: function store(data) {
if (!this.cache) {
return;
}
this.storage.set(keys.data, data, this.ttl);
this.storage.set(keys.protocol, location.protocol, this.ttl);
this.storage.set(keys.thumbprint, this.thumbprint, this.ttl);
},
fromCache: function fromCache() {
var stored = {}, isExpired;
if (!this.cache) {
return null;
}
stored.data = this.storage.get(keys.data);
stored.protocol = this.storage.get(keys.protocol);
stored.thumbprint = this.storage.get(keys.thumbprint);
isExpired = stored.thumbprint !== this.thumbprint || stored.protocol !== location.protocol;
return stored.data && !isExpired "use strict";
function Remote(o) {
this.url = o.url;
this.prepare = o.prepare;
this.transform = o.transform;
this.transport = new Transport({
cache: o.cache,
limiter: o.limiter,
transport: o.transport
});
}
_.mixin(Remote.prototype, {
_settings: function settings() {
return {
url: this.url,
type: "GET",
dataType: "json"
};
},
get: function get(query, cb) {
var that = this, settings;
if (!cb) {
return;
}
query = query || "";
settings = this.prepare(query, this._settings());
return this.transport.get(settings, onResponse);
function onResponse(err, resp) {
err "use strict";
return function parse(o) {
var defaults, sorter;
defaults = {
initialize: true,
identify: _.stringify,
datumTokenizer: null,
queryTokenizer: null,
sufficient: 5,
sorter: null,
local: [],
prefetch: null,
remote: null
};
o = _.mixin(defaults, o || {});
!o.datumTokenizer && $.error("datumTokenizer is required");
!o.queryTokenizer && $.error("queryTokenizer is required");
sorter = o.sorter;
o.sorter = sorter "",
prepare: _.identity,
transform: _.identity,
transport: null
};
o = _.isString(o) "prefetch requires url to be set");
o.transform = o.filter || o.transform;
o.cacheKey = o.cacheKey || o.url;
o.thumbprint = VERSION + o.thumbprint;
o.transport = o.transport "debounce",
rateLimitWait: 300,
transform: _.identity,
transport: null
};
o = _.isString(o) "remote requires url to be set");
o.transform = o.filter || o.transform;
o.prepare = toRemotePrepare(o);
o.limiter = toLimiter(o);
o.transport = o.transport "use strict";
var old;
old = window && window.Bloodhound;
function Bloodhound(o) {
o = oParser(o);
this.sorter = o.sorter;
this.identify = o.identify;
this.sufficient = o.sufficient;
this.local = o.local;
this.remote = o.remote "function" && define.amd) {
define("typeahead.js", [ "jquery" ], function(a0) {
return factory(a0);
});
} else if (typeof exports === "object") {
module.exports = factory(require("jquery"));
} else {
factory(jQuery);
}
})(this, function($) {
var _ = function() {
"use strict";
return {
isMsie: function() {
return /(msie|trident)/i.test(navigator.userAgent) "\\$&");
},
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";
},
isElement: function(obj) {
return !!(obj && obj.nodeType === 1);
},
isJQuery: function(obj) {
return obj instanceof $;
},
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,
identity: function(x) {
return x;
},
clone: function(obj) {
return $.extend(true, {}, obj);
},
getIdGenerator: function() {
var counter = 0;
return function() {
return counter++;
};
},
templatify: function templatify(obj) {
return $.isFunction(obj) "use strict";
var defaultClassNames = {
wrapper: "twitter-typeahead",
input: "tt-input",
hint: "tt-hint",
menu: "tt-menu",
dataset: "tt-dataset",
suggestion: "tt-suggestion",
selectable: "tt-selectable",
empty: "tt-empty",
open: "tt-open",
cursor: "tt-cursor",
highlight: "tt-highlight"
};
return build;
function build(o) {
var www, classes;
classes = _.mixin({}, defaultClassNames, o);
www = {
css: buildCss(),
classes: classes,
html: buildHtml(classes),
selectors: buildSelectors(classes)
};
return {
css: www.css,
html: www.html,
classes: www.classes,
selectors: www.selectors,
mixin: function(o) {
_.mixin(o, www);
}
};
}
function buildHtml(c) {
return {
wrapper: '<span class="' + c.wrapper + '"></span>',
menu: '<div class="' + c.menu + '"></div>'
};
}
function buildSelectors(classes) {
var selectors = {};
_.each(classes, function(v, k) {
selectors[k] = "." + v;
});
return selectors;
}
function buildCss() {
var css = {
wrapper: {
position: "relative",
display: "inline-block"
},
hint: {
position: "absolute",
top: "0",
left: "0",
borderColor: "transparent",
boxShadow: "none",
opacity: "1"
},
input: {
position: "relative",
verticalAlign: "top",
backgroundColor: "transparent"
},
inputWithNoHint: {
position: "relative",
verticalAlign: "top"
},
menu: {
position: "absolute",
top: "100%",
left: "0",
zIndex: "100",
display: "none"
},
ltr: {
left: "0",
right: "auto"
},
rtl: {
left: "auto",
right: " 0"
}
};
if (_.isMsie()) {
_.mixin(css.input, {
backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"
});
}
return css;
}
}();
var EventBus = function() {
"use strict";
var namespace, deprecationMap;
namespace = "typeahead:";
deprecationMap = {
render: "rendered",
cursorchange: "cursorchanged",
select: "selected",
autocomplete: "autocompleted"
};
function EventBus(o) {
if (!o || !o.el) {
$.error("EventBus initialized without el");
}
this.$el = $(o.el);
}
_.mixin(EventBus.prototype, {
_trigger: function(type, args) {
var $e;
$e = $.Event(namespace + type);
(args = args || []).unshift($e);
this.$el.trigger.apply(this.$el, args);
return $e;
},
before: function(type) {
var args, $e;
args = [].slice.call(arguments, 1);
$e = this._trigger("before" + type, args);
return $e.isDefaultPrevented();
},
trigger: function(type) {
var deprecatedType;
this._trigger(type, [].slice.call(arguments, 1));
if (deprecatedType = deprecationMap[type]) {
this._trigger(deprecatedType, [].slice.call(arguments, 1));
}
}
});
return EventBus;
}();
var EventEmitter = function() {
"use strict";
var splitter = /\s+/, nextTick = getNextTick();
return {
onSync: onSync,
onAsync: onAsync,
off: off,
trigger: trigger
};
function on(method, types, cb, context) {
var type;
if (!cb) {
return this;
}
types = types.split(splitter);
cb = context "async", types, cb, context);
}
function onSync(types, cb, context) {
return on.call(this, "sync", types, cb, context);
}
function off(types) {
var type;
if (!this._callbacks) {
return this;
}
types = types.split(splitter);
while (type = types.shift()) {
delete this._callbacks[type];
}
return this;
}
function trigger(types) {
var type, callbacks, args, syncFlush, asyncFlush;
if (!this._callbacks) {
return this;
}
types = types.split(splitter);
args = [].slice.call(arguments, 1);
while ((type = types.shift()) && (callbacks = this._callbacks[type])) {
syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args));
asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args));
syncFlush() && nextTick(asyncFlush);
}
return this;
}
function getFlush(callbacks, context, args) {
return flush;
function flush() {
var cancelled;
for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) {
cancelled = callbacks[i].apply(context, args) === false;
}
return !cancelled;
}
}
function getNextTick() {
var nextTickFn;
if (window.setImmediate) {
nextTickFn = function nextTickSetImmediate(fn) {
setImmediate(function() {
fn();
});
};
} else {
nextTickFn = function nextTickSetTimeout(fn) {
setTimeout(function() {
fn();
}, 0);
};
}
return nextTickFn;
}
function bindContext(fn, context) {
return fn.bind "use strict";
var defaults = {
node: null,
pattern: null,
tagName: "strong",
className: null,
wordsOnly: false,
caseSensitive: false
};
return function hightlight(o) {
var regex;
o = _.mixin({}, defaults, o);
if (!o.node || !o.pattern) {
return;
}
o.pattern = _.isArray(o.pattern) "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")";
return caseSensitive "i");
}
}(window.document);
var Input = function() {
"use strict";
var specialKeyCodeMap;
specialKeyCodeMap = {
9: "tab",
27: "esc",
37: "left",
39: "right",
13: "enter",
38: "up",
40: "down"
};
function Input(o, www) {
o = o || {};
if (!o.input) {
$.error("input is missing");
}
www.mixin(this);
this.$hint = $(o.hint);
this.$input = $(o.input);
this.query = this.$input.val();
this.queryWhenFocused = this.hasFocus() "").replace(/\s{2,}/g, " ");
};
_.mixin(Input.prototype, EventEmitter, {
_onBlur: function onBlur() {
this.resetInputValue();
this.trigger("blurred");
},
_onFocus: function onFocus() {
this.queryWhenFocused = this.query;
this.trigger("focused");
},
_onKeydown: function onKeydown($e) {
var keyName = specialKeyCodeMap[$e.which || $e.keyCode];
this._managePreventDefault(keyName, $e);
if (keyName && this._shouldTrigger(keyName, $e)) {
this.trigger(keyName + "Keyed", $e);
}
},
_onInput: function onInput() {
this._setQuery(this.getInputValue());
this.clearHintIfInvalid();
this._checkLanguageDirection();
},
_managePreventDefault: function managePreventDefault(keyName, $e) {
var preventDefault;
switch (keyName) {
case "up":
case "down":
preventDefault = !withModifier($e);
break;
default:
preventDefault = false;
}
preventDefault && $e.preventDefault();
},
_shouldTrigger: function shouldTrigger(keyName, $e) {
var trigger;
switch (keyName) {
case "tab":
trigger = !withModifier($e);
break;
default:
trigger = true;
}
return trigger;
},
_checkLanguageDirection: function checkLanguageDirection() {
var dir = (this.$input.css("direction") || "ltr").toLowerCase();
if (this.dir !== dir) {
this.dir = dir;
this.$hint.attr("dir", dir);
this.trigger("langDirChanged", dir);
}
},
_setQuery: function setQuery(val, silent) {
var areEquivalent, hasDifferentWhitespace;
areEquivalent = areQueriesEquivalent(val, this.query);
hasDifferentWhitespace = areEquivalent "queryChanged", this.query);
} else if (!silent && hasDifferentWhitespace) {
this.trigger("whitespaceChanged", this.query);
}
},
bind: function() {
var that = this, onBlur, onFocus, onKeydown, onInput;
onBlur = _.bind(this._onBlur, this);
onFocus = _.bind(this._onFocus, this);
onKeydown = _.bind(this._onKeydown, this);
onInput = _.bind(this._onInput, this);
this.$input.on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown);
if (!_.isMsie() || _.isMsie() > 9) {
this.$input.on("input.tt", onInput);
} else {
this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) {
if (specialKeyCodeMap[$e.which || $e.keyCode]) {
return;
}
_.defer(_.bind(that._onInput, that, $e));
});
}
return this;
},
focus: function focus() {
this.$input.focus();
},
blur: function blur() {
this.$input.blur();
},
getLangDir: function getLangDir() {
return this.dir;
},
getQuery: function getQuery() {
return this.query || "";
},
setQuery: function setQuery(val, silent) {
this.setInputValue(val);
this._setQuery(val, silent);
},
hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() {
return this.query !== this.queryWhenFocused;
},
getInputValue: function getInputValue() {
return this.$input.val();
},
setInputValue: function setInputValue(value) {
this.$input.val(value);
this.clearHintIfInvalid();
this._checkLanguageDirection();
},
resetInputValue: function resetInputValue() {
this.setInputValue(this.query);
},
getHint: function getHint() {
return this.$hint.val();
},
setHint: function setHint(value) {
this.$hint.val(value);
},
clearHint: function clearHint() {
this.setHint("");
},
clearHintIfInvalid: function clearHintIfInvalid() {
var val, hint, valIsPrefixOfHint, isValid;
val = this.getInputValue();
hint = this.getHint();
valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;
isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow();
!isValid && this.clearHint();
},
hasFocus: function hasFocus() {
return this.$input.is(":focus");
},
hasOverflow: function hasOverflow() {
var constraint = this.$input.width() - 2;
this.$overflowHelper.text(this.getInputValue());
return this.$overflowHelper.width() >= constraint;
},
isCursorAtEnd: function() {
var valueLength, selectionStart, range;
valueLength = this.$input.val().length;
selectionStart = this.$input[0].selectionStart;
if (_.isNumber(selectionStart)) {
return selectionStart === valueLength;
} else if (document.selection) {
range = document.selection.createRange();
range.moveStart("character", -valueLength);
return valueLength === range.text.length;
}
return true;
},
destroy: function destroy() {
this.$hint.off(".tt");
this.$input.off(".tt");
this.$overflowHelper.remove();
this.$hint = this.$input = this.$overflowHelper = $("<div>");
}
});
return Input;
function buildOverflowHelper($input) {
return $('<pre aria-hidden="true"></pre>').css({
position: "absolute",
visibility: "hidden",
whiteSpace: "pre",
fontFamily: $input.css("font-family"),
fontSize: $input.css("font-size"),
fontStyle: $input.css("font-style"),
fontVariant: $input.css("font-variant"),
fontWeight: $input.css("font-weight"),
wordSpacing: $input.css("word-spacing"),
letterSpacing: $input.css("letter-spacing"),
textIndent: $input.css("text-indent"),
textRendering: $input.css("text-rendering"),
textTransform: $input.css("text-transform")
}).insertAfter($input);
}
function areQueriesEquivalent(a, b) {
return Input.normalizeQuery(a) === Input.normalizeQuery(b);
}
function withModifier($e) {
return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;
}
}();
var Dataset = function() {
"use strict";
var keys, nameGenerator;
keys = {
val: "tt-selectable-display",
obj: "tt-selectable-object"
};
nameGenerator = _.getIdGenerator();
function Dataset(o, www) {
o = o || {};
o.templates = o.templates || {};
o.templates.notFound = o.templates.notFound || o.templates.empty;
if (!o.source) {
$.error("missing source");
}
if (!o.node) {
$.error("missing node");
}
if (o.name && !isValidName(o.name)) {
$.error("invalid dataset name: " + o.name);
}
www.mixin(this);
this.highlight = !!o.highlight;
this.name = o.name || nameGenerator();
this.limit = o.limit || 5;
this.displayFn = getDisplayFn(o.display || o.displayKey);
this.templates = getTemplates(o.templates, this.displayFn);
this.source = o.source.__ttAdapter "-" + this.name);
}
Dataset.extractData = function extractData(el) {
var $el = $(el);
if ($el.data(keys.obj)) {
return {
val: $el.data(keys.val) || "",
obj: $el.data(keys.obj) || null
};
}
return null;
};
_.mixin(Dataset.prototype, EventEmitter, {
_overwrite: function overwrite(query, suggestions) {
suggestions = suggestions || [];
if (suggestions.length) {
this._renderSuggestions(query, suggestions);
} else if (this.async && this.templates.pending) {
this._renderPending(query);
} else if (!this.async && this.templates.notFound) {
this._renderNotFound(query);
} else {
this._empty();
}
this.trigger("rendered", this.name, suggestions, false);
},
_append: function append(query, suggestions) {
suggestions = suggestions || [];
if (suggestions.length && this.$lastSuggestion.length) {
this._appendSuggestions(query, suggestions);
} else if (suggestions.length) {
this._renderSuggestions(query, suggestions);
} else if (!this.$lastSuggestion.length && this.templates.notFound) {
this._renderNotFound(query);
}
this.trigger("rendered", this.name, suggestions, true);
},
_renderSuggestions: function renderSuggestions(query, suggestions) {
var $fragment;
$fragment = this._getSuggestionsFragment(query, suggestions);
this.$lastSuggestion = $fragment.children().last();
this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions));
},
_appendSuggestions: function appendSuggestions(query, suggestions) {
var $fragment, $lastSuggestion;
$fragment = this._getSuggestionsFragment(query, suggestions);
$lastSuggestion = $fragment.children().last();
this.$lastSuggestion.after($fragment);
this.$lastSuggestion = $lastSuggestion;
},
_renderPending: function renderPending(query) {
var template = this.templates.pending;
this._resetLastSuggestion();
template && this.$el.html(template({
query: query,
dataset: this.name
}));
},
_renderNotFound: function renderNotFound(query) {
var template = this.templates.notFound;
this._resetLastSuggestion();
template && this.$el.html(template({
query: query,
dataset: this.name
}));
},
_empty: function empty() {
this.$el.empty();
this._resetLastSuggestion();
},
_getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) {
var that = this, fragment;
fragment = document.createDocumentFragment();
_.each(suggestions, function getSuggestionNode(suggestion) {
var $el, context;
context = that._injectQuery(query, suggestion);
$el = $(that.templates.suggestion(context)).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + " " + that.classes.selectable);
fragment.appendChild($el[0]);
});
this.highlight && highlight({
className: this.classes.highlight,
node: fragment,
pattern: query
});
return $(fragment);
},
_getFooter: function getFooter(query, suggestions) {
return this.templates.footer "asyncCanceled", query);
};
this.source(query, sync, async);
!syncCalled && sync([]);
function sync(suggestions) {
if (syncCalled) {
return;
}
syncCalled = true;
suggestions = (suggestions || []).slice(0, that.limit);
rendered = suggestions.length;
that._overwrite(query, suggestions);
if (rendered < that.limit && that.async) {
that.trigger("asyncRequested", query);
}
}
function async(suggestions) {
suggestions = suggestions || [];
if (!canceled && rendered < that.limit) {
that.cancel = $.noop;
rendered += suggestions.length;
that._append(query, suggestions.slice(0, that.limit - rendered));
that.async && that.trigger("asyncReceived", query);
}
}
},
cancel: $.noop,
clear: function clear() {
this._empty();
this.cancel();
this.trigger("cleared");
},
isEmpty: function isEmpty() {
return this.$el.is(":empty");
},
destroy: function destroy() {
this.$el = $("<div>");
}
});
return Dataset;
function getDisplayFn(display) {
display = display || _.stringify;
return _.isFunction(display) "<div>").text(displayFn(context));
}
}
function isValidName(str) {
return /^[_a-zA-Z0-9-]+$/.test(str);
}
}();
var Menu = function() {
"use strict";
function Menu(o, www) {
var that = this;
o = o || {};
if (!o.node) {
$.error("node is required");
}
www.mixin(this);
this.$node = $(o.node);
this.query = null;
this.datasets = _.map(o.datasets, initializeDataset);
function initializeDataset(oDataset) {
var node = that.$node.find(oDataset.node).first();
oDataset.node = node.length "<div>").appendTo(that.$node);
return new Dataset(oDataset, www);
}
}
_.mixin(Menu.prototype, EventEmitter, {
_onSelectableClick: function onSelectableClick($e) {
this.trigger("selectableClicked", $($e.currentTarget));
},
_onRendered: function onRendered(type, dataset, suggestions, async) {
this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());
this.trigger("datasetRendered", dataset, suggestions, async);
},
_onCleared: function onCleared() {
this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());
this.trigger("datasetCleared");
},
_propagate: function propagate() {
this.trigger.apply(this, arguments);
},
_allDatasetsEmpty: function allDatasetsEmpty() {
return _.every(this.datasets, isDatasetEmpty);
function isDatasetEmpty(dataset) {
return dataset.isEmpty();
}
},
_getSelectables: function getSelectables() {
return this.$node.find(this.selectors.selectable);
},
_removeCursor: function _removeCursor() {
var $selectable = this.getActiveSelectable();
$selectable && $selectable.removeClass(this.classes.cursor);
},
_ensureVisible: function ensureVisible($el) {
var elTop, elBottom, nodeScrollTop, nodeHeight;
elTop = $el.position().top;
elBottom = elTop + $el.outerHeight(true);
nodeScrollTop = this.$node.scrollTop();
nodeHeight = this.$node.height() + parseInt(this.$node.css("paddingTop"), 10) + parseInt(this.$node.css("paddingBottom"), 10);
if (elTop < 0) {
this.$node.scrollTop(nodeScrollTop + elTop);
} else if (nodeHeight < elBottom) {
this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight));
}
},
bind: function() {
var that = this, onSelectableClick;
onSelectableClick = _.bind(this._onSelectableClick, this);
this.$node.on("click.tt", this.selectors.selectable, onSelectableClick);
_.each(this.datasets, function(dataset) {
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);
});
return this;
},
isOpen: function isOpen() {
return this.$node.hasClass(this.classes.open);
},
open: function open() {
this.$node.addClass(this.classes.open);
},
close: function close() {
this.$node.removeClass(this.classes.open);
this._removeCursor();
},
setLanguageDirection: function setLanguageDirection(dir) {
this.$node.attr("dir", dir);
},
selectableRelativeToCursor: function selectableRelativeToCursor(delta) {
var $selectables, $oldCursor, oldIndex, newIndex;
$oldCursor = this.getActiveSelectable();
$selectables = this._getSelectables();
oldIndex = $oldCursor ".tt");
this.$node = $("<div>");
_.each(this.datasets, destroyDataset);
function destroyDataset(dataset) {
dataset.destroy();
}
}
});
return Menu;
}();
var DefaultMenu = function() {
"use strict";
var s = Menu.prototype;
function DefaultMenu() {
Menu.apply(this, [].slice.call(arguments, 0));
}
_.mixin(DefaultMenu.prototype, Menu.prototype, {
open: function open() {
!this._allDatasetsEmpty() && this._show();
return s.open.apply(this, [].slice.call(arguments, 0));
},
close: function close() {
this._hide();
return s.close.apply(this, [].slice.call(arguments, 0));
},
_onRendered: function onRendered() {
if (this._allDatasetsEmpty()) {
this._hide();
} else {
this.isOpen() && this._show();
}
return s._onRendered.apply(this, [].slice.call(arguments, 0));
},
_onCleared: function onCleared() {
if (this._allDatasetsEmpty()) {
this._hide();
} else {
this.isOpen() && this._show();
}
return s._onCleared.apply(this, [].slice.call(arguments, 0));
},
setLanguageDirection: function setLanguageDirection(dir) {
this.$node.css(dir === "ltr" "display", "block");
}
});
return DefaultMenu;
}();
var Typeahead = function() {
"use strict";
function Typeahead(o, www) {
var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged, onWhitespaceChanged;
o = o || {};
if (!o.input) {
$.error("missing input");
}
if (!o.menu) {
$.error("missing menu");
}
if (!o.eventBus) {
$.error("missing event bus");
}
www.mixin(this);
this.eventBus = o.eventBus;
this.minLength = _.isNumber(o.minLength) "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);
onFocused = c(this, "activate", "open", "_onFocused");
onBlurred = c(this, "deactivate", "_onBlurred");
onEnterKeyed = c(this, "isActive", "isOpen", "_onEnterKeyed");
onTabKeyed = c(this, "isActive", "isOpen", "_onTabKeyed");
onEscKeyed = c(this, "isActive", "_onEscKeyed");
onUpKeyed = c(this, "isActive", "open", "_onUpKeyed");
onDownKeyed = c(this, "isActive", "open", "_onDownKeyed");
onLeftKeyed = c(this, "isActive", "isOpen", "_onLeftKeyed");
onRightKeyed = c(this, "isActive", "isOpen", "_onRightKeyed");
onQueryChanged = c(this, "_openIfActive", "_onQueryChanged");
onWhitespaceChanged = c(this, "_openIfActive", "_onWhitespaceChanged");
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);
}
_.mixin(Typeahead.prototype, {
_hacks: function hacks() {
var $input, $menu;
$input = this.input.$input || $("<div>");
$menu = this.menu.$node || $("<div>");
$input.on("blur.tt", function($e) {
var active, isActive, hasActive;
active = document.activeElement;
isActive = $menu.is(active);
hasActive = $menu.has(active).length > 0;
if (_.isMsie() && (isActive || hasActive)) {
$e.preventDefault();
$e.stopImmediatePropagation();
_.defer(function() {
$input.focus();
});
}
});
$menu.on("mousedown.tt", function($e) {
$e.preventDefault();
});
},
_onSelectableClicked: function onSelectableClicked(type, $el) {
this.select($el);
},
_onDatasetCleared: function onDatasetCleared() {
this._updateHint();
},
_onDatasetRendered: function onDatasetRendered(type, dataset, suggestions, async) {
this._updateHint();
this.eventBus.trigger("render", suggestions, async, dataset);
},
_onAsyncRequested: function onAsyncRequested(type, dataset, query) {
this.eventBus.trigger("asyncrequest", query, dataset);
},
_onAsyncCanceled: function onAsyncCanceled(type, dataset, query) {
this.eventBus.trigger("asynccancel", query, dataset);
},
_onAsyncReceived: function onAsyncReceived(type, dataset, query) {
this.eventBus.trigger("asyncreceive", query, dataset);
},
_onFocused: function onFocused() {
this._minLengthMet() && this.menu.update(this.input.getQuery());
},
_onBlurred: function onBlurred() {
if (this.input.hasQueryChangedSinceLastFocus()) {
this.eventBus.trigger("change", this.input.getQuery());
}
},
_onEnterKeyed: function onEnterKeyed(type, $e) {
var $selectable;
if ($selectable = this.menu.getActiveSelectable()) {
this.select($selectable) && $e.preventDefault();
}
},
_onTabKeyed: function onTabKeyed(type, $e) {
var $selectable;
if ($selectable = this.menu.getActiveSelectable()) {
this.select($selectable) && $e.preventDefault();
} else if ($selectable = this.menu.getTopSelectable()) {
this.autocomplete($selectable) && $e.preventDefault();
}
},
_onEscKeyed: function onEscKeyed() {
this.close();
},
_onUpKeyed: function onUpKeyed() {
this.moveCursor(-1);
},
_onDownKeyed: function onDownKeyed() {
this.moveCursor(+1);
},
_onLeftKeyed: function onLeftKeyed() {
if (this.dir === "rtl" && this.input.isCursorAtEnd()) {
this.autocomplete(this.menu.getTopSelectable());
}
},
_onRightKeyed: function onRightKeyed() {
if (this.dir === "ltr" && this.input.isCursorAtEnd()) {
this.autocomplete(this.menu.getTopSelectable());
}
},
_onQueryChanged: function onQueryChanged(e, query) {
this._minLengthMet(query) "";
return query.length >= this.minLength;
},
_updateHint: function updateHint() {
var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match;
$selectable = this.menu.getTopSelectable();
data = this.menu.getSelectableData($selectable);
val = this.input.getInputValue();
if (data && !_.isBlankString(val) && !this.input.hasOverflow()) {
query = Input.normalizeQuery(val);
escapedQuery = _.escapeRegExChars(query);
frontMatchRegEx = new RegExp("^(" + escapedQuery + ")(.+$)", "i");
match = frontMatchRegEx.exec(data.val);
match && this.input.setHint(val + match[1]);
} else {
this.input.clearHint();
}
},
isEnabled: function isEnabled() {
return this.enabled;
},
enable: function enable() {
this.enabled = true;
},
disable: function disable() {
this.enabled = false;
},
isActive: function isActive() {
return this.active;
},
activate: function activate() {
if (this.isActive()) {
return true;
} else if (!this.isEnabled() || this.eventBus.before("active")) {
return false;
} else {
this.active = true;
this.eventBus.trigger("active");
return true;
}
},
deactivate: function deactivate() {
if (!this.isActive()) {
return true;
} else if (this.eventBus.before("idle")) {
return false;
} else {
this.active = false;
this.close();
this.eventBus.trigger("idle");
return true;
}
},
isOpen: function isOpen() {
return this.menu.isOpen();
},
open: function open() {
if (!this.isOpen() && !this.eventBus.before("open")) {
this.menu.open();
this._updateHint();
this.eventBus.trigger("open");
}
return this.isOpen();
},
close: function close() {
if (this.isOpen() && !this.eventBus.before("close")) {
this.menu.close();
this.input.clearHint();
this.input.resetInputValue();
this.eventBus.trigger("close");
}
return !this.isOpen();
},
setVal: function setVal(val) {
this.input.setQuery(_.toStr(val));
},
getVal: function getVal() {
return this.input.getQuery();
},
select: function select($selectable) {
var data = this.menu.getSelectableData($selectable);
if (data && !this.eventBus.before("select", data.obj)) {
this.input.setQuery(data.val, true);
this.eventBus.trigger("select", data.obj);
this.close();
return true;
}
return false;
},
autocomplete: function autocomplete($selectable) {
var query, data, isValid;
query = this.input.getQuery();
data = this.menu.getSelectableData($selectable);
isValid = data && query !== data.val;
if (isValid && !this.eventBus.before("autocomplete", data.obj)) {
this.input.setQuery(data.val);
this.eventBus.trigger("autocomplete", data.obj);
return true;
}
return false;
},
moveCursor: function moveCursor(delta) {
var query, $candidate, data, payload, cancelMove;
query = this.input.getQuery();
$candidate = this.menu.selectableRelativeToCursor(delta);
data = this.menu.getSelectableData($candidate);
payload = data "cursorchange", payload)) {
this.menu.setCursor($candidate);
if (data) {
this.input.setInputValue(data.val);
} else {
this.input.resetInputValue();
this._updateHint();
}
this.eventBus.trigger("cursorchange", payload);
return true;
}
return false;
},
destroy: function destroy() {
this.input.destroy();
this.menu.destroy();
}
});
return Typeahead;
function c(ctx) {
var methods = [].slice.call(arguments, 1);
return function() {
var args = [].slice.call(arguments);
_.each(methods, function(method) {
return ctx[method].apply(ctx, args);
});
};
}
}();
(function() {
"use strict";
var old, keys, methods;
old = $.fn.typeahead;
keys = {
www: "tt-www",
attrs: "tt-attrs",
typeahead: "tt-typeahead"
};
methods = {
initialize: function initialize(o, datasets) {
var www;
datasets = _.isArray(datasets) "");
$input = prepInput($input, www);
if (defaultHint || defaultMenu) {
$wrapper.css(www.css.wrapper);
$input.css(defaultHint "readonly", true).removeAttr("id name placeholder required").attr({
autocomplete: "off",
spellcheck: "false",
tabindex: -1
});
}
function prepInput($input, www) {
$input.data(keys.attrs, {
dir: $input.attr("dir"),
autocomplete: $input.attr("autocomplete"),
spellcheck: $input.attr("spellcheck"),
style: $input.attr("style")
});
$input.addClass(www.classes.input).attr({
autocomplete: "off",
spellcheck: false
});
try {
!$input.attr("dir") && $input.attr("dir", "auto");
} catch (e) {}
return $input;
}
function getBackgroundStyles($el) {
return {
backgroundAttachment: $el.css("background-attachment"),
backgroundClip: $el.css("background-clip"),
backgroundColor: $el.css("background-color"),
backgroundImage: $el.css("background-image"),
backgroundOrigin: $el.css("background-origin"),
backgroundPosition: $el.css("background-position"),
backgroundRepeat: $el.css("background-repeat"),
backgroundSize: $el.css("background-size")
};
}
function revert($input) {
var www, $wrapper;
www = $input.data(keys.www);
$wrapper = $input.parent().filter(www.selectors.wrapper);
_.each($input.data(keys.attrs), function(val, key) {
_.isUndefined(val) "htmlcode">
.typeahead,.tt-query,.tt-hint {
width: 396px;
height: 30px;
padding: 8px 12px;
font-size: 24px;
line-height: 30px;
border: 2px solid #ccc;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
outline: none;
}
.typeahead {
background-color: #fff;
}
.typeahead:focus {
border: 2px solid #0097cf;
}
.tt-query {
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
.tt-hint {
color: #999
}
.tt-menu {
width: 422px;
margin: 12px 0;
padding: 8px 0;
background-color: #fff;
border: 1px solid #ccc;
border: 1px solid rgba(0, 0, 0, 0.2);
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
-webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2);
-moz-box-shadow: 0 5px 10px rgba(0,0,0,.2);
box-shadow: 0 5px 10px rgba(0,0,0,.2);
}
.tt-suggestion {
padding: 3px 20px;
font-size: 18px;
line-height: 24px;
}
.tt-suggestion:hover {
cursor: pointer;
color: #fff;
background-color: #0097cf;
}
.tt-suggestion.tt-cursor {
color: #fff;
background-color: #0097cf;
}
.tt-suggestion p {
margin: 0;
}
.gist {
font-size: 14px;
}
/* example specific styles */
/* ----------------------- */
#custom-templates .empty-message {
padding: 5px 10px;
text-align: center;
}
#multiple-datasets .league-name {
margin: 0 20px 5px 20px;
padding: 3px 0;
border-bottom: 1px solid #ccc;
}
#scrollable-dropdown-menu .tt-menu {
max-height: 150px;
overflow-y: auto;
}
#rtl-support .tt-menu {
text-align: right;
}

以上所述是小编给大家介绍的Bootstrap3使用typeahead插件实现自动补全功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!

标签:
bootstrap3自动补全,bootstrap3,typeahead

免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
狼山资源网 Copyright www.pvsay.com