/*! * 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("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) ? 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"; }, 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) ? 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; }; }, stringify: function(val) { return _.isString(val) ? val : JSON.stringify(val); }, noop: function() {} }; }(); var WWW = function() { "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: '', menu: '
' }; } 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 ? bindContext(cb, context) : cb; this._callbacks = this._callbacks || {}; while (type = types.shift()) { this._callbacks[type] = this._callbacks[type] || { sync: [], async: [] }; this._callbacks[type][method].push(cb); } return this; } function onAsync(types, cb, context) { return on.call(this, "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 ? fn.bind(context) : function() { fn.apply(context, [].slice.call(arguments, 0)); }; } }(); var highlight = function(doc) { "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) ? o.pattern : [ o.pattern ]; regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly); traverse(o.node, hightlightTextNode); function hightlightTextNode(textNode) { var match, patternNode, wrapperNode; if (match = regex.exec(textNode.data)) { wrapperNode = doc.createElement(o.tagName); o.className && (wrapperNode.className = o.className); patternNode = textNode.splitText(match.index); patternNode.splitText(match[0].length); wrapperNode.appendChild(patternNode.cloneNode(true)); textNode.parentNode.replaceChild(wrapperNode, patternNode); } return !!match; } function traverse(el, hightlightTextNode) { var childNode, TEXT_NODE_TYPE = 3; for (var i = 0; i < el.childNodes.length; i++) { childNode = el.childNodes[i]; if (childNode.nodeType === TEXT_NODE_TYPE) { i += hightlightTextNode(childNode) ? 1 : 0; } else { traverse(childNode, hightlightTextNode); } } } }; function getRegex(patterns, caseSensitive, wordsOnly) { var escapedPatterns = [], regexStr; for (var i = 0, len = patterns.length; i < len; i++) { escapedPatterns.push(_.escapeRegExChars(patterns[i])); } regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")"; return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "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() ? this.query : null; this.$overflowHelper = buildOverflowHelper(this.$input); this._checkLanguageDirection(); if (this.$hint.length === 0) { this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop; } } Input.normalizeQuery = function(str) { return _.toStr(str).replace(/^\s*/g, "").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 ? this.query.length !== val.length : false; this.query = val; if (!silent && !areEquivalent) { this.trigger("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 = $("