1694 lines
		
	
	
		
			70 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1694 lines
		
	
	
		
			70 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/*!
 | 
						||
 * typeahead.js 1.3.1
 | 
						||
 * https://github.com/corejavascript/typeahead.js
 | 
						||
 * Copyright 2013-2020 Twitter, Inc. and other contributors; Licensed MIT
 | 
						||
 */
 | 
						||
 | 
						||
 | 
						||
(function(root, factory) {
 | 
						||
    if (typeof define === "function" && define.amd) {
 | 
						||
        define([ "jquery" ], function(a0) {
 | 
						||
            return factory(a0);
 | 
						||
        });
 | 
						||
    } else if (typeof module === "object" && module.exports) {
 | 
						||
        module.exports = factory(require("jquery"));
 | 
						||
    } else {
 | 
						||
        factory(root["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);
 | 
						||
            },
 | 
						||
            guid: function() {
 | 
						||
                function _p8(s) {
 | 
						||
                    var p = (Math.random().toString(16) + "000000000").substr(2, 8);
 | 
						||
                    return s ? "-" + p.substr(0, 4) + "-" + p.substr(4, 4) : p;
 | 
						||
                }
 | 
						||
                return "tt-" + _p8() + _p8(true) + _p8(true) + _p8();
 | 
						||
            },
 | 
						||
            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: '<span class="' + c.wrapper + '"></span>',
 | 
						||
                menu: '<div role="listbox" 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 = $.Event(namespace + type);
 | 
						||
                this.$el.trigger.call(this.$el, $e, 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,
 | 
						||
            diacriticInsensitive: false
 | 
						||
        };
 | 
						||
        var accented = {
 | 
						||
            A: "[AaªÀ-Åà-åĀ-ąǍǎȀ-ȃȦȧᴬᵃḀḁẚẠ-ảₐ℀℁℻⒜Ⓐⓐ㍱-㍴㎀-㎄㎈㎉㎩-㎯㏂㏊㏟㏿Aa]",
 | 
						||
            B: "[BbᴮᵇḂ-ḇℬ⒝Ⓑⓑ㍴㎅-㎇㏃㏈㏔㏝Bb]",
 | 
						||
            C: "[CcÇçĆ-čᶜ℀ℂ℃℅℆ℭⅭⅽ⒞Ⓒⓒ㍶㎈㎉㎝㎠㎤㏄-㏇Cc]",
 | 
						||
            D: "[DdĎďDŽ-džDZ-dzᴰᵈḊ-ḓⅅⅆⅮⅾ⒟Ⓓⓓ㋏㍲㍷-㍹㎗㎭-㎯㏅㏈Dd]",
 | 
						||
            E: "[EeÈ-Ëè-ëĒ-ěȄ-ȇȨȩᴱᵉḘ-ḛẸ-ẽₑ℡ℯℰⅇ⒠Ⓔⓔ㉐㋍㋎Ee]",
 | 
						||
            F: "[FfᶠḞḟ℉ℱ℻⒡Ⓕⓕ㎊-㎌㎙ff-fflFf]",
 | 
						||
            G: "[GgĜ-ģǦǧǴǵᴳᵍḠḡℊ⒢Ⓖⓖ㋌㋍㎇㎍-㎏㎓㎬㏆㏉㏒㏿Gg]",
 | 
						||
            H: "[HhĤĥȞȟʰᴴḢ-ḫẖℋ-ℎ⒣Ⓗⓗ㋌㍱㎐-㎔㏊㏋㏗Hh]",
 | 
						||
            I: "[IiÌ-Ïì-ïĨ-İIJijǏǐȈ-ȋᴵᵢḬḭỈ-ịⁱℐℑℹⅈⅠ-ⅣⅥ-ⅨⅪⅫⅰ-ⅳⅵ-ⅸⅺⅻ⒤Ⓘⓘ㍺㏌㏕fiffiIi]",
 | 
						||
            J: "[JjIJ-ĵLJ-njǰʲᴶⅉ⒥ⒿⓙⱼJj]",
 | 
						||
            K: "[KkĶķǨǩᴷᵏḰ-ḵK⒦Ⓚⓚ㎄㎅㎉㎏㎑㎘㎞㎢㎦㎪㎸㎾㏀㏆㏍-㏏Kk]",
 | 
						||
            L: "[LlĹ-ŀLJ-ljˡᴸḶḷḺ-ḽℒℓ℡Ⅼⅼ⒧Ⓛⓛ㋏㎈㎉㏐-㏓㏕㏖㏿flfflLl]",
 | 
						||
            M: "[MmᴹᵐḾ-ṃ℠™ℳⅯⅿ⒨Ⓜⓜ㍷-㍹㎃㎆㎎㎒㎖㎙-㎨㎫㎳㎷㎹㎽㎿㏁㏂㏎㏐㏔-㏖㏘㏙㏞㏟Mm]",
 | 
						||
            N: "[NnÑñŃ-ʼnNJ-njǸǹᴺṄ-ṋⁿℕ№⒩Ⓝⓝ㎁㎋㎚㎱㎵㎻㏌㏑Nn]",
 | 
						||
            O: "[OoºÒ-Öò-öŌ-őƠơǑǒǪǫȌ-ȏȮȯᴼᵒỌ-ỏₒ℅№ℴ⒪Ⓞⓞ㍵㏇㏒㏖Oo]",
 | 
						||
            P: "[PpᴾᵖṔ-ṗℙ⒫Ⓟⓟ㉐㍱㍶㎀㎊㎩-㎬㎰㎴㎺㏋㏗-㏚Pp]",
 | 
						||
            Q: "[Qqℚ⒬Ⓠⓠ㏃Qq]",
 | 
						||
            R: "[RrŔ-řȐ-ȓʳᴿᵣṘ-ṛṞṟ₨ℛ-ℝ⒭Ⓡⓡ㋍㍴㎭-㎯㏚㏛Rr]",
 | 
						||
            S: "[SsŚ-šſȘșˢṠ-ṣ₨℁℠⒮Ⓢⓢ㎧㎨㎮-㎳㏛㏜stSs]",
 | 
						||
            T: "[TtŢ-ťȚțᵀᵗṪ-ṱẗ℡™⒯Ⓣⓣ㉐㋏㎔㏏ſtstTt]",
 | 
						||
            U: "[UuÙ-Üù-üŨ-ųƯưǓǔȔ-ȗᵁᵘᵤṲ-ṷỤ-ủ℆⒰Ⓤⓤ㍳㍺Uu]",
 | 
						||
            V: "[VvᵛᵥṼ-ṿⅣ-Ⅷⅳ-ⅷ⒱Ⓥⓥⱽ㋎㍵㎴-㎹㏜㏞Vv]",
 | 
						||
            W: "[WwŴŵʷᵂẀ-ẉẘ⒲Ⓦⓦ㎺-㎿㏝Ww]",
 | 
						||
            X: "[XxˣẊ-ẍₓ℻Ⅸ-Ⅻⅸ-ⅻ⒳Ⓧⓧ㏓Xx]",
 | 
						||
            Y: "[YyÝýÿŶ-ŸȲȳʸẎẏẙỲ-ỹ⒴Ⓨⓨ㏉Yy]",
 | 
						||
            Z: "[ZzŹ-žDZ-dzᶻẐ-ẕℤℨ⒵Ⓩⓩ㎐-㎔Zz]"
 | 
						||
        };
 | 
						||
        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, o.diacriticInsensitive);
 | 
						||
            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 accent_replacer(chr) {
 | 
						||
            return accented[chr.toUpperCase()] || chr;
 | 
						||
        }
 | 
						||
        function getRegex(patterns, caseSensitive, wordsOnly, diacriticInsensitive) {
 | 
						||
            var escapedPatterns = [], regexStr;
 | 
						||
            for (var i = 0, len = patterns.length; i < len; i++) {
 | 
						||
                var escapedWord = _.escapeRegExChars(patterns[i]);
 | 
						||
                if (diacriticInsensitive) {
 | 
						||
                    escapedWord = escapedWord.replace(/\S/g, accent_replacer);
 | 
						||
                }
 | 
						||
                escapedPatterns.push(escapedWord);
 | 
						||
            }
 | 
						||
            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) {
 | 
						||
            var id;
 | 
						||
            o = o || {};
 | 
						||
            if (!o.input) {
 | 
						||
                $.error("input is missing");
 | 
						||
            }
 | 
						||
            www.mixin(this);
 | 
						||
            this.$hint = $(o.hint);
 | 
						||
            this.$input = $(o.input);
 | 
						||
            this.$menu = $(o.menu);
 | 
						||
            id = this.$input.attr("id") || _.guid();
 | 
						||
            this.$menu.attr("id", id + "_listbox");
 | 
						||
            this.$hint.attr({
 | 
						||
                "aria-hidden": true
 | 
						||
            });
 | 
						||
            this.$input.attr({
 | 
						||
                "aria-owns": id + "_listbox",
 | 
						||
                role: "combobox",
 | 
						||
                "aria-autocomplete": "list",
 | 
						||
                "aria-expanded": false
 | 
						||
            });
 | 
						||
            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;
 | 
						||
            }
 | 
						||
            this.onSync("cursorchange", this._updateDescendent);
 | 
						||
        }
 | 
						||
        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);
 | 
						||
                }
 | 
						||
            },
 | 
						||
            _updateDescendent: function updateDescendent(event, id) {
 | 
						||
                this.$input.attr("aria-activedescendant", id);
 | 
						||
            },
 | 
						||
            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>");
 | 
						||
            },
 | 
						||
            setAriaExpanded: function setAriaExpanded(value) {
 | 
						||
                this.$input.attr("aria-expanded", value);
 | 
						||
            }
 | 
						||
        });
 | 
						||
        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 = {
 | 
						||
            dataset: "tt-selectable-dataset",
 | 
						||
            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 = _.toStr(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 ? o.source.__ttAdapter() : o.source;
 | 
						||
            this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async;
 | 
						||
            this._resetLastSuggestion();
 | 
						||
            this.$el = $(o.node).attr("role", "presentation").addClass(this.classes.dataset).addClass(this.classes.dataset + "-" + this.name);
 | 
						||
        }
 | 
						||
        Dataset.extractData = function extractData(el) {
 | 
						||
            var $el = $(el);
 | 
						||
            if ($el.data(keys.obj)) {
 | 
						||
                return {
 | 
						||
                    dataset: $el.data(keys.dataset) || "",
 | 
						||
                    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", suggestions, false, this.name);
 | 
						||
            },
 | 
						||
            _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", suggestions, true, this.name);
 | 
						||
            },
 | 
						||
            _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.dataset, that.name).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 ? this.templates.footer({
 | 
						||
                    query: query,
 | 
						||
                    suggestions: suggestions,
 | 
						||
                    dataset: this.name
 | 
						||
                }) : null;
 | 
						||
            },
 | 
						||
            _getHeader: function getHeader(query, suggestions) {
 | 
						||
                return this.templates.header ? this.templates.header({
 | 
						||
                    query: query,
 | 
						||
                    suggestions: suggestions,
 | 
						||
                    dataset: this.name
 | 
						||
                }) : null;
 | 
						||
            },
 | 
						||
            _resetLastSuggestion: function resetLastSuggestion() {
 | 
						||
                this.$lastSuggestion = $();
 | 
						||
            },
 | 
						||
            _injectQuery: function injectQuery(query, obj) {
 | 
						||
                return _.isObject(obj) ? _.mixin({
 | 
						||
                    _query: query
 | 
						||
                }, obj) : obj;
 | 
						||
            },
 | 
						||
            update: function update(query) {
 | 
						||
                var that = this, canceled = false, syncCalled = false, rendered = 0;
 | 
						||
                this.cancel();
 | 
						||
                this.cancel = function cancel() {
 | 
						||
                    canceled = true;
 | 
						||
                    that.cancel = $.noop;
 | 
						||
                    that.async && that.trigger("asyncCanceled", query, that.name);
 | 
						||
                };
 | 
						||
                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, that.name);
 | 
						||
                    }
 | 
						||
                }
 | 
						||
                function async(suggestions) {
 | 
						||
                    suggestions = suggestions || [];
 | 
						||
                    if (!canceled && rendered < that.limit) {
 | 
						||
                        that.cancel = $.noop;
 | 
						||
                        var idx = Math.abs(rendered - that.limit);
 | 
						||
                        rendered += idx;
 | 
						||
                        that._append(query, suggestions.slice(0, idx));
 | 
						||
                        that.async && that.trigger("asyncReceived", query, that.name);
 | 
						||
                    }
 | 
						||
                }
 | 
						||
            },
 | 
						||
            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) ? display : displayFn;
 | 
						||
            function displayFn(obj) {
 | 
						||
                return obj[display];
 | 
						||
            }
 | 
						||
        }
 | 
						||
        function getTemplates(templates, displayFn) {
 | 
						||
            return {
 | 
						||
                notFound: templates.notFound && _.templatify(templates.notFound),
 | 
						||
                pending: templates.pending && _.templatify(templates.pending),
 | 
						||
                header: templates.header && _.templatify(templates.header),
 | 
						||
                footer: templates.footer && _.templatify(templates.footer),
 | 
						||
                suggestion: templates.suggestion ? userSuggestionTemplate : suggestionTemplate
 | 
						||
            };
 | 
						||
            function userSuggestionTemplate(context) {
 | 
						||
                var template = templates.suggestion;
 | 
						||
                return $(template(context)).attr("id", _.guid());
 | 
						||
            }
 | 
						||
            function suggestionTemplate(context) {
 | 
						||
                return $('<div role="option">').attr("id", _.guid()).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 ? node : $("<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, _.bind(function isDatasetEmpty(dataset) {
 | 
						||
                    var isEmpty = dataset.isEmpty();
 | 
						||
                    this.$node.attr("aria-expanded", !isEmpty);
 | 
						||
                    return isEmpty;
 | 
						||
                }, this));
 | 
						||
            },
 | 
						||
            _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);
 | 
						||
                this.$node.on("mouseover", this.selectors.selectable, function() {
 | 
						||
                    that.setCursor($(this));
 | 
						||
                });
 | 
						||
                this.$node.on("mouseleave", function() {
 | 
						||
                    that._removeCursor();
 | 
						||
                });
 | 
						||
                _.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.scrollTop(0);
 | 
						||
                this.$node.addClass(this.classes.open);
 | 
						||
            },
 | 
						||
            close: function close() {
 | 
						||
                this.$node.attr("aria-expanded", false);
 | 
						||
                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 ? $selectables.index($oldCursor) : -1;
 | 
						||
                newIndex = oldIndex + delta;
 | 
						||
                newIndex = (newIndex + 1) % ($selectables.length + 1) - 1;
 | 
						||
                newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex;
 | 
						||
                return newIndex === -1 ? null : $selectables.eq(newIndex);
 | 
						||
            },
 | 
						||
            setCursor: function setCursor($selectable) {
 | 
						||
                this._removeCursor();
 | 
						||
                if ($selectable = $selectable && $selectable.first()) {
 | 
						||
                    $selectable.addClass(this.classes.cursor);
 | 
						||
                    this._ensureVisible($selectable);
 | 
						||
                }
 | 
						||
            },
 | 
						||
            getSelectableData: function getSelectableData($el) {
 | 
						||
                return $el && $el.length ? Dataset.extractData($el) : null;
 | 
						||
            },
 | 
						||
            getActiveSelectable: function getActiveSelectable() {
 | 
						||
                var $selectable = this._getSelectables().filter(this.selectors.cursor).first();
 | 
						||
                return $selectable.length ? $selectable : null;
 | 
						||
            },
 | 
						||
            getTopSelectable: function getTopSelectable() {
 | 
						||
                var $selectable = this._getSelectables().first();
 | 
						||
                return $selectable.length ? $selectable : null;
 | 
						||
            },
 | 
						||
            update: function update(query) {
 | 
						||
                var isValidUpdate = query !== this.query;
 | 
						||
                if (isValidUpdate) {
 | 
						||
                    this.query = query;
 | 
						||
                    _.each(this.datasets, updateDataset);
 | 
						||
                }
 | 
						||
                return isValidUpdate;
 | 
						||
                function updateDataset(dataset) {
 | 
						||
                    dataset.update(query);
 | 
						||
                }
 | 
						||
            },
 | 
						||
            empty: function empty() {
 | 
						||
                _.each(this.datasets, clearDataset);
 | 
						||
                this.query = null;
 | 
						||
                this.$node.addClass(this.classes.empty);
 | 
						||
                function clearDataset(dataset) {
 | 
						||
                    dataset.clear();
 | 
						||
                }
 | 
						||
            },
 | 
						||
            destroy: function destroy() {
 | 
						||
                this.$node.off(".tt");
 | 
						||
                this.$node = $("<div>");
 | 
						||
                _.each(this.datasets, destroyDataset);
 | 
						||
                function destroyDataset(dataset) {
 | 
						||
                    dataset.destroy();
 | 
						||
                }
 | 
						||
            }
 | 
						||
        });
 | 
						||
        return Menu;
 | 
						||
    }();
 | 
						||
    var Status = function() {
 | 
						||
        "use strict";
 | 
						||
        function Status(options) {
 | 
						||
            this.$el = $("<span></span>", {
 | 
						||
                role: "status",
 | 
						||
                "aria-live": "polite"
 | 
						||
            }).css({
 | 
						||
                position: "absolute",
 | 
						||
                padding: "0",
 | 
						||
                border: "0",
 | 
						||
                height: "1px",
 | 
						||
                width: "1px",
 | 
						||
                "margin-bottom": "-1px",
 | 
						||
                "margin-right": "-1px",
 | 
						||
                overflow: "hidden",
 | 
						||
                clip: "rect(0 0 0 0)",
 | 
						||
                "white-space": "nowrap"
 | 
						||
            });
 | 
						||
            options.$input.after(this.$el);
 | 
						||
            _.each(options.menu.datasets, _.bind(function(dataset) {
 | 
						||
                if (dataset.onSync) {
 | 
						||
                    dataset.onSync("rendered", _.bind(this.update, this));
 | 
						||
                    dataset.onSync("cleared", _.bind(this.cleared, this));
 | 
						||
                }
 | 
						||
            }, this));
 | 
						||
        }
 | 
						||
        _.mixin(Status.prototype, {
 | 
						||
            update: function update(event, suggestions) {
 | 
						||
                var length = suggestions.length;
 | 
						||
                var words;
 | 
						||
                if (length === 1) {
 | 
						||
                    words = {
 | 
						||
                        result: "result",
 | 
						||
                        is: "is"
 | 
						||
                    };
 | 
						||
                } else {
 | 
						||
                    words = {
 | 
						||
                        result: "results",
 | 
						||
                        is: "are"
 | 
						||
                    };
 | 
						||
                }
 | 
						||
                this.$el.text(length + " " + words.result + " " + words.is + " available, use up and down arrow keys to navigate.");
 | 
						||
            },
 | 
						||
            cleared: function() {
 | 
						||
                this.$el.text("");
 | 
						||
            }
 | 
						||
        });
 | 
						||
        return Status;
 | 
						||
    }();
 | 
						||
    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" ? this.css.ltr : this.css.rtl);
 | 
						||
                return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0));
 | 
						||
            },
 | 
						||
            _hide: function hide() {
 | 
						||
                this.$node.hide();
 | 
						||
            },
 | 
						||
            _show: function show() {
 | 
						||
                this.$node.css("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) ? o.minLength : 1;
 | 
						||
            this.input = o.input;
 | 
						||
            this.menu = o.menu;
 | 
						||
            this.enabled = true;
 | 
						||
            this.autoselect = !!o.autoselect;
 | 
						||
            this.active = false;
 | 
						||
            this.input.hasFocus() && this.activate();
 | 
						||
            this.dir = this.input.getLangDir();
 | 
						||
            this._hacks();
 | 
						||
            this.menu.bind().onSync("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, suggestions, async, dataset) {
 | 
						||
                this._updateHint();
 | 
						||
                if (this.autoselect) {
 | 
						||
                    var cursorClass = this.selectors.cursor.substr(1);
 | 
						||
                    this.menu.$node.find(this.selectors.suggestion).first().addClass(cursorClass);
 | 
						||
                }
 | 
						||
                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()) {
 | 
						||
                    if (this.select($selectable)) {
 | 
						||
                        $e.preventDefault();
 | 
						||
                        $e.stopPropagation();
 | 
						||
                    }
 | 
						||
                } else if (this.autoselect) {
 | 
						||
                    if (this.select(this.menu.getTopSelectable())) {
 | 
						||
                        $e.preventDefault();
 | 
						||
                        $e.stopPropagation();
 | 
						||
                    }
 | 
						||
                }
 | 
						||
            },
 | 
						||
            _onTabKeyed: function onTabKeyed(type, $e) {
 | 
						||
                var $selectable;
 | 
						||
                if ($selectable = this.menu.getActiveSelectable()) {
 | 
						||
                    this.select($selectable) && $e.preventDefault();
 | 
						||
                } else if (this.autoselect) {
 | 
						||
                    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.getActiveSelectable() || this.menu.getTopSelectable());
 | 
						||
                }
 | 
						||
            },
 | 
						||
            _onRightKeyed: function onRightKeyed() {
 | 
						||
                if (this.dir === "ltr" && this.input.isCursorAtEnd()) {
 | 
						||
                    this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable());
 | 
						||
                }
 | 
						||
            },
 | 
						||
            _onQueryChanged: function onQueryChanged(e, query) {
 | 
						||
                this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty();
 | 
						||
            },
 | 
						||
            _onWhitespaceChanged: function onWhitespaceChanged() {
 | 
						||
                this._updateHint();
 | 
						||
            },
 | 
						||
            _onLangDirChanged: function onLangDirChanged(e, dir) {
 | 
						||
                if (this.dir !== dir) {
 | 
						||
                    this.dir = dir;
 | 
						||
                    this.menu.setLanguageDirection(dir);
 | 
						||
                }
 | 
						||
            },
 | 
						||
            _openIfActive: function openIfActive() {
 | 
						||
                this.isActive() && this.open();
 | 
						||
            },
 | 
						||
            _minLengthMet: function minLengthMet(query) {
 | 
						||
                query = _.isString(query) ? query : this.input.getQuery() || "";
 | 
						||
                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.input.setAriaExpanded(true);
 | 
						||
                    this.menu.open();
 | 
						||
                    this._updateHint();
 | 
						||
                    this.eventBus.trigger("open");
 | 
						||
                }
 | 
						||
                return this.isOpen();
 | 
						||
            },
 | 
						||
            close: function close() {
 | 
						||
                if (this.isOpen() && !this.eventBus.before("close")) {
 | 
						||
                    this.input.setAriaExpanded(false);
 | 
						||
                    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, data.dataset)) {
 | 
						||
                    this.input.setQuery(data.val, true);
 | 
						||
                    this.eventBus.trigger("select", data.obj, data.dataset);
 | 
						||
                    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, data.dataset)) {
 | 
						||
                    this.input.setQuery(data.val);
 | 
						||
                    this.eventBus.trigger("autocomplete", data.obj, data.dataset);
 | 
						||
                    return true;
 | 
						||
                }
 | 
						||
                return false;
 | 
						||
            },
 | 
						||
            moveCursor: function moveCursor(delta) {
 | 
						||
                var query, $candidate, data, suggestion, datasetName, cancelMove, id;
 | 
						||
                query = this.input.getQuery();
 | 
						||
                $candidate = this.menu.selectableRelativeToCursor(delta);
 | 
						||
                data = this.menu.getSelectableData($candidate);
 | 
						||
                suggestion = data ? data.obj : null;
 | 
						||
                datasetName = data ? data.dataset : null;
 | 
						||
                id = $candidate ? $candidate.attr("id") : null;
 | 
						||
                this.input.trigger("cursorchange", id);
 | 
						||
                cancelMove = this._minLengthMet() && this.menu.update(query);
 | 
						||
                if (!cancelMove && !this.eventBus.before("cursorchange", suggestion, datasetName)) {
 | 
						||
                    this.menu.setCursor($candidate);
 | 
						||
                    if (data) {
 | 
						||
                        if (typeof data.val === "string") {
 | 
						||
                            this.input.setInputValue(data.val);
 | 
						||
                        }
 | 
						||
                    } else {
 | 
						||
                        this.input.resetInputValue();
 | 
						||
                        this._updateHint();
 | 
						||
                    }
 | 
						||
                    this.eventBus.trigger("cursorchange", suggestion, datasetName);
 | 
						||
                    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) ? datasets : [].slice.call(arguments, 1);
 | 
						||
                o = o || {};
 | 
						||
                www = WWW(o.classNames);
 | 
						||
                return this.each(attach);
 | 
						||
                function attach() {
 | 
						||
                    var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, status, typeahead, MenuConstructor;
 | 
						||
                    _.each(datasets, function(d) {
 | 
						||
                        d.highlight = !!o.highlight;
 | 
						||
                    });
 | 
						||
                    $input = $(this);
 | 
						||
                    $wrapper = $(www.html.wrapper);
 | 
						||
                    $hint = $elOrNull(o.hint);
 | 
						||
                    $menu = $elOrNull(o.menu);
 | 
						||
                    defaultHint = o.hint !== false && !$hint;
 | 
						||
                    defaultMenu = o.menu !== false && !$menu;
 | 
						||
                    defaultHint && ($hint = buildHintFromInput($input, www));
 | 
						||
                    defaultMenu && ($menu = $(www.html.menu).css(www.css.menu));
 | 
						||
                    $hint && $hint.val("");
 | 
						||
                    $input = prepInput($input, www);
 | 
						||
                    if (defaultHint || defaultMenu) {
 | 
						||
                        $wrapper.css(www.css.wrapper);
 | 
						||
                        $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint);
 | 
						||
                        $input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null);
 | 
						||
                    }
 | 
						||
                    MenuConstructor = defaultMenu ? DefaultMenu : Menu;
 | 
						||
                    eventBus = new EventBus({
 | 
						||
                        el: $input
 | 
						||
                    });
 | 
						||
                    input = new Input({
 | 
						||
                        hint: $hint,
 | 
						||
                        input: $input,
 | 
						||
                        menu: $menu
 | 
						||
                    }, www);
 | 
						||
                    menu = new MenuConstructor({
 | 
						||
                        node: $menu,
 | 
						||
                        datasets: datasets
 | 
						||
                    }, www);
 | 
						||
                    status = new Status({
 | 
						||
                        $input: $input,
 | 
						||
                        menu: menu
 | 
						||
                    });
 | 
						||
                    typeahead = new Typeahead({
 | 
						||
                        input: input,
 | 
						||
                        menu: menu,
 | 
						||
                        eventBus: eventBus,
 | 
						||
                        minLength: o.minLength,
 | 
						||
                        autoselect: o.autoselect
 | 
						||
                    }, www);
 | 
						||
                    $input.data(keys.www, www);
 | 
						||
                    $input.data(keys.typeahead, typeahead);
 | 
						||
                }
 | 
						||
            },
 | 
						||
            isEnabled: function isEnabled() {
 | 
						||
                var enabled;
 | 
						||
                ttEach(this.first(), function(t) {
 | 
						||
                    enabled = t.isEnabled();
 | 
						||
                });
 | 
						||
                return enabled;
 | 
						||
            },
 | 
						||
            enable: function enable() {
 | 
						||
                ttEach(this, function(t) {
 | 
						||
                    t.enable();
 | 
						||
                });
 | 
						||
                return this;
 | 
						||
            },
 | 
						||
            disable: function disable() {
 | 
						||
                ttEach(this, function(t) {
 | 
						||
                    t.disable();
 | 
						||
                });
 | 
						||
                return this;
 | 
						||
            },
 | 
						||
            isActive: function isActive() {
 | 
						||
                var active;
 | 
						||
                ttEach(this.first(), function(t) {
 | 
						||
                    active = t.isActive();
 | 
						||
                });
 | 
						||
                return active;
 | 
						||
            },
 | 
						||
            activate: function activate() {
 | 
						||
                ttEach(this, function(t) {
 | 
						||
                    t.activate();
 | 
						||
                });
 | 
						||
                return this;
 | 
						||
            },
 | 
						||
            deactivate: function deactivate() {
 | 
						||
                ttEach(this, function(t) {
 | 
						||
                    t.deactivate();
 | 
						||
                });
 | 
						||
                return this;
 | 
						||
            },
 | 
						||
            isOpen: function isOpen() {
 | 
						||
                var open;
 | 
						||
                ttEach(this.first(), function(t) {
 | 
						||
                    open = t.isOpen();
 | 
						||
                });
 | 
						||
                return open;
 | 
						||
            },
 | 
						||
            open: function open() {
 | 
						||
                ttEach(this, function(t) {
 | 
						||
                    t.open();
 | 
						||
                });
 | 
						||
                return this;
 | 
						||
            },
 | 
						||
            close: function close() {
 | 
						||
                ttEach(this, function(t) {
 | 
						||
                    t.close();
 | 
						||
                });
 | 
						||
                return this;
 | 
						||
            },
 | 
						||
            select: function select(el) {
 | 
						||
                var success = false, $el = $(el);
 | 
						||
                ttEach(this.first(), function(t) {
 | 
						||
                    success = t.select($el);
 | 
						||
                });
 | 
						||
                return success;
 | 
						||
            },
 | 
						||
            autocomplete: function autocomplete(el) {
 | 
						||
                var success = false, $el = $(el);
 | 
						||
                ttEach(this.first(), function(t) {
 | 
						||
                    success = t.autocomplete($el);
 | 
						||
                });
 | 
						||
                return success;
 | 
						||
            },
 | 
						||
            moveCursor: function moveCursoe(delta) {
 | 
						||
                var success = false;
 | 
						||
                ttEach(this.first(), function(t) {
 | 
						||
                    success = t.moveCursor(delta);
 | 
						||
                });
 | 
						||
                return success;
 | 
						||
            },
 | 
						||
            val: function val(newVal) {
 | 
						||
                var query;
 | 
						||
                if (!arguments.length) {
 | 
						||
                    ttEach(this.first(), function(t) {
 | 
						||
                        query = t.getVal();
 | 
						||
                    });
 | 
						||
                    return query;
 | 
						||
                } else {
 | 
						||
                    ttEach(this, function(t) {
 | 
						||
                        t.setVal(_.toStr(newVal));
 | 
						||
                    });
 | 
						||
                    return this;
 | 
						||
                }
 | 
						||
            },
 | 
						||
            destroy: function destroy() {
 | 
						||
                ttEach(this, function(typeahead, $input) {
 | 
						||
                    revert($input);
 | 
						||
                    typeahead.destroy();
 | 
						||
                });
 | 
						||
                return this;
 | 
						||
            }
 | 
						||
        };
 | 
						||
        $.fn.typeahead = function(method) {
 | 
						||
            if (methods[method]) {
 | 
						||
                return methods[method].apply(this, [].slice.call(arguments, 1));
 | 
						||
            } else {
 | 
						||
                return methods.initialize.apply(this, arguments);
 | 
						||
            }
 | 
						||
        };
 | 
						||
        $.fn.typeahead.noConflict = function noConflict() {
 | 
						||
            $.fn.typeahead = old;
 | 
						||
            return this;
 | 
						||
        };
 | 
						||
        function ttEach($els, fn) {
 | 
						||
            $els.each(function() {
 | 
						||
                var $input = $(this), typeahead;
 | 
						||
                (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input);
 | 
						||
            });
 | 
						||
        }
 | 
						||
        function buildHintFromInput($input, www) {
 | 
						||
            return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop({
 | 
						||
                readonly: true,
 | 
						||
                required: false
 | 
						||
            }).removeAttr("id name placeholder").removeClass("required").attr({
 | 
						||
                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({
 | 
						||
                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) ? $input.removeAttr(key) : $input.attr(key, val);
 | 
						||
            });
 | 
						||
            $input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input);
 | 
						||
            if ($wrapper.length) {
 | 
						||
                $input.detach().insertAfter($wrapper);
 | 
						||
                $wrapper.remove();
 | 
						||
            }
 | 
						||
        }
 | 
						||
        function $elOrNull(obj) {
 | 
						||
            var isValid, $el;
 | 
						||
            isValid = _.isJQuery(obj) || _.isElement(obj);
 | 
						||
            $el = isValid ? $(obj).first() : [];
 | 
						||
            return $el.length ? $el : null;
 | 
						||
        }
 | 
						||
    })();
 | 
						||
}); |