修改jquery.automeplete,使其支持value匹配

原生只会去匹配label,可在实际使用中,可能需要匹配的值并不需要显示在label中,经过添加一个matchType属性解决

1、加入matchType选项,并默认为原生匹配

        $.widget("ui.autocomplete", {
            version: "1.11.0",
            defaultElement: "<input>",
            options: {
                appendTo: null,
                autoFocus: false,
                delay: 300,
                minLength: 1,
                position: {
                    my: "left top",
                    at: "left bottom",
                    collision: "none"
                },
                source: null,

                // callbacks
                change: null,
                close: null,
                focus: null,
                open: null,
                response: null,
                search: null,
                select: null,
                //all,label,value
                matchType: 'all'
            },

2、在_initSource中给filter传入type参数

            _initSource: function() {
                var array, url, type
                that = this;
                if ($.isArray(this.options.source)) {
                    array = this.options.source;
                    type = this.options.matchType;
                    this.source = function(request, response) {
                    response($.ui.autocomplete.filter(array, request.term, type));
                    };
                } else if (typeof this.options.source === "string") {
                    url = this.options.source;
                    this.source = function(request, response) {
                        if (that.xhr) {
                            that.xhr.abort();
                        }
                        that.xhr = $.ajax({
                            url: url,
                            data: request,
                            dataType: "json",
                            success: function(data) {
                                response(data);
                            },
                            error: function() {
                                response([]);
                            }
                        });
                    };
                } else {
                    this.source = this.options.source;
                }
            },

3、修改filter

        $.extend($.ui.autocomplete, {
            escapeRegex: function(value) {
                return value.replace(/[-[]{}()*+?.,\^$|#s]/g, "\$&");
            },
            filter: function(array, term,type) {
                var matcher = new RegExp($.ui.autocomplete.escapeRegex(term), "i");

                return $.grep(array, function(value) {
                    if (type == "label") {
                        return matcher.test(value.value);
                    } else if (type == "value") {
                        return matcher.test(value.value);

                    } else {
                        return matcher.test(value.label || value.value || value);
                    }
                });
            }
        });

最终代码:

/*! jQuery UI - v1.11.0 - 2014-07-06
* http://jqueryui.com
* Includes: core.js, widget.js, position.js, autocomplete.js, menu.js
* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */

(function(factory) {
    if (typeof define === "function" && define.amd) {

        // AMD. Register as an anonymous module.
        define(["jquery"], factory);
    } else {

        // Browser globals
        factory(jQuery);
    }
} (function($) {
    /*!
    * jQuery UI Core 1.11.0
    * http://jqueryui.com
    *
    * Copyright 2014 jQuery Foundation and other contributors
    * Released under the MIT license.
    * http://jquery.org/license
    *
    * http://api.jqueryui.com/category/ui-core/
    */


    // $.ui might exist from components with no dependencies, e.g., $.ui.position
    $.ui = $.ui || {};

    $.extend($.ui, {
        version: "1.11.0",

        keyCode: {
            BACKSPACE: 8,
            COMMA: 188,
            DELETE: 46,
            DOWN: 40,
            END: 35,
            ENTER: 13,
            ESCAPE: 27,
            HOME: 36,
            LEFT: 37,
            PAGE_DOWN: 34,
            PAGE_UP: 33,
            PERIOD: 190,
            RIGHT: 39,
            SPACE: 32,
            TAB: 9,
            UP: 38
        }
    });

    // plugins
    $.fn.extend({
        scrollParent: function() {
            var position = this.css("position"),
            excludeStaticParent = position === "absolute",
            scrollParent = this.parents().filter(function() {
                var parent = $(this);
                if (excludeStaticParent && parent.css("position") === "static") {
                    return false;
                }
                return (/(auto|scroll)/).test(parent.css("overflow") + parent.css("overflow-y") + parent.css("overflow-x"));
            }).eq(0);

            return position === "fixed" || !scrollParent.length ? $(this[0].ownerDocument || document) : scrollParent;
        },

        uniqueId: (function() {
            var uuid = 0;

            return function() {
                return this.each(function() {
                    if (!this.id) {
                        this.id = "ui-id-" + (++uuid);
                    }
                });
            };
        })(),

        removeUniqueId: function() {
            return this.each(function() {
                if (/^ui-id-d+$/.test(this.id)) {
                    $(this).removeAttr("id");
                }
            });
        }
    });

    // selectors
    function focusable(element, isTabIndexNotNaN) {
        var map, mapName, img,
        nodeName = element.nodeName.toLowerCase();
        if ("area" === nodeName) {
            map = element.parentNode;
            mapName = map.name;
            if (!element.href || !mapName || map.nodeName.toLowerCase() !== "map") {
                return false;
            }
            img = $("img[usemap=#" + mapName + "]")[0];
            return !!img && visible(img);
        }
        return (/input|select|textarea|button|object/.test(nodeName) ?
        !element.disabled :
        "a" === nodeName ?
            element.href || isTabIndexNotNaN :
            isTabIndexNotNaN) &&
        // the element and all of its ancestors must be visible
        visible(element);
    }

    function visible(element) {
        return $.expr.filters.visible(element) &&
        !$(element).parents().addBack().filter(function() {
            return $.css(this, "visibility") === "hidden";
        }).length;
    }

    $.extend($.expr[":"], {
        data: $.expr.createPseudo ?
        $.expr.createPseudo(function(dataName) {
            return function(elem) {
                return !!$.data(elem, dataName);
            };
        }) :
        // support: jQuery <1.8
        function(elem, i, match) {
            return !!$.data(elem, match[3]);
        },

        focusable: function(element) {
            return focusable(element, !isNaN($.attr(element, "tabindex")));
        },

        tabbable: function(element) {
            var tabIndex = $.attr(element, "tabindex"),
            isTabIndexNaN = isNaN(tabIndex);
            return (isTabIndexNaN || tabIndex >= 0) && focusable(element, !isTabIndexNaN);
        }
    });

    // support: jQuery <1.8
    if (!$("<a>").outerWidth(1).jquery) {
        $.each(["Width", "Height"], function(i, name) {
            var side = name === "Width" ? ["Left", "Right"] : ["Top", "Bottom"],
            type = name.toLowerCase(),
            orig = {
                innerWidth: $.fn.innerWidth,
                innerHeight: $.fn.innerHeight,
                outerWidth: $.fn.outerWidth,
                outerHeight: $.fn.outerHeight
            };

            function reduce(elem, size, border, margin) {
                $.each(side, function() {
                    size -= parseFloat($.css(elem, "padding" + this)) || 0;
                    if (border) {
                        size -= parseFloat($.css(elem, "border" + this + "Width")) || 0;
                    }
                    if (margin) {
                        size -= parseFloat($.css(elem, "margin" + this)) || 0;
                    }
                });
                return size;
            }

            $.fn["inner" + name] = function(size) {
                if (size === undefined) {
                    return orig["inner" + name].call(this);
                }

                return this.each(function() {
                    $(this).css(type, reduce(this, size) + "px");
                });
            };

            $.fn["outer" + name] = function(size, margin) {
                if (typeof size !== "number") {
                    return orig["outer" + name].call(this, size);
                }

                return this.each(function() {
                    $(this).css(type, reduce(this, size, true, margin) + "px");
                });
            };
        });
    }

    // support: jQuery <1.8
    if (!$.fn.addBack) {
        $.fn.addBack = function(selector) {
            return this.add(selector == null ?
            this.prevObject : this.prevObject.filter(selector)
        );
        };
    }

    // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
    if ($("<a>").data("a-b", "a").removeData("a-b").data("a-b")) {
        $.fn.removeData = (function(removeData) {
            return function(key) {
                if (arguments.length) {
                    return removeData.call(this, $.camelCase(key));
                } else {
                    return removeData.call(this);
                }
            };
        })($.fn.removeData);
    }

    // deprecated
    $.ui.ie = !!/msie [w.]+/.exec(navigator.userAgent.toLowerCase());

    $.fn.extend({
        focus: (function(orig) {
            return function(delay, fn) {
                return typeof delay === "number" ?
                this.each(function() {
                    var elem = this;
                    setTimeout(function() {
                        $(elem).focus();
                        if (fn) {
                            fn.call(elem);
                        }
                    }, delay);
                }) :
                orig.apply(this, arguments);
            };
        })($.fn.focus),

        disableSelection: (function() {
            var eventType = "onselectstart" in document.createElement("div") ?
            "selectstart" :
            "mousedown";

            return function() {
                return this.bind(eventType + ".ui-disableSelection", function(event) {
                    event.preventDefault();
                });
            };
        })(),

        enableSelection: function() {
            return this.unbind(".ui-disableSelection");
        },

        zIndex: function(zIndex) {
            if (zIndex !== undefined) {
                return this.css("zIndex", zIndex);
            }

            if (this.length) {
                var elem = $(this[0]), position, value;
                while (elem.length && elem[0] !== document) {
                    // Ignore z-index if position is set to a value where z-index is ignored by the browser
                    // This makes behavior of this function consistent across browsers
                    // WebKit always returns auto if the element is positioned
                    position = elem.css("position");
                    if (position === "absolute" || position === "relative" || position === "fixed") {
                        // IE returns 0 when zIndex is not specified
                        // other browsers return a string
                        // we ignore the case of nested elements with an explicit value of 0
                        // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
                        value = parseInt(elem.css("zIndex"), 10);
                        if (!isNaN(value) && value !== 0) {
                            return value;
                        }
                    }
                    elem = elem.parent();
                }
            }

            return 0;
        }
    });

    // $.ui.plugin is deprecated. Use $.widget() extensions instead.
    $.ui.plugin = {
        add: function(module, option, set) {
            var i,
            proto = $.ui[module].prototype;
            for (i in set) {
                proto.plugins[i] = proto.plugins[i] || [];
                proto.plugins[i].push([option, set[i]]);
            }
        },
        call: function(instance, name, args, allowDisconnected) {
            var i,
            set = instance.plugins[name];

            if (!set) {
                return;
            }

            if (!allowDisconnected && (!instance.element[0].parentNode || instance.element[0].parentNode.nodeType === 11)) {
                return;
            }

            for (i = 0; i < set.length; i++) {
                if (instance.options[set[i][0]]) {
                    set[i][1].apply(instance.element, args);
                }
            }
        }
    };


    /*!
    * jQuery UI Widget 1.11.0
    * http://jqueryui.com
    *
    * Copyright 2014 jQuery Foundation and other contributors
    * Released under the MIT license.
    * http://jquery.org/license
    *
    * http://api.jqueryui.com/jQuery.widget/
    */


    var widget_uuid = 0,
    widget_slice = Array.prototype.slice;

    $.cleanData = (function(orig) {
        return function(elems) {
            for (var i = 0, elem; (elem = elems[i]) != null; i++) {
                try {
                    $(elem).triggerHandler("remove");
                    // http://bugs.jquery.com/ticket/8235
                } catch (e) { }
            }
            orig(elems);
        };
    })($.cleanData);

    $.widget = function(name, base, prototype) {
        var fullName, existingConstructor, constructor, basePrototype,
        // proxiedPrototype allows the provided prototype to remain unmodified
        // so that it can be used as a mixin for multiple widgets (#8876)
        proxiedPrototype = {},
        namespace = name.split(".")[0];

        name = name.split(".")[1];
        fullName = namespace + "-" + name;

        if (!prototype) {
            prototype = base;
            base = $.Widget;
        }

        // create selector for plugin
        $.expr[":"][fullName.toLowerCase()] = function(elem) {
            return !!$.data(elem, fullName);
        };

        $[namespace] = $[namespace] || {};
        existingConstructor = $[namespace][name];
        constructor = $[namespace][name] = function(options, element) {
            // allow instantiation without "new" keyword
            if (!this._createWidget) {
                return new constructor(options, element);
            }

            // allow instantiation without initializing for simple inheritance
            // must use "new" keyword (the code above always passes args)
            if (arguments.length) {
                this._createWidget(options, element);
            }
        };
        // extend with the existing constructor to carry over any static properties
        $.extend(constructor, existingConstructor, {
            version: prototype.version,
            // copy the object used to create the prototype in case we need to
            // redefine the widget later
            _proto: $.extend({}, prototype),
            // track widgets that inherit from this widget in case this widget is
            // redefined after a widget inherits from it
            _childConstructors: []
        });

        basePrototype = new base();
        // we need to make the options hash a property directly on the new instance
        // otherwise we'll modify the options hash on the prototype that we're
        // inheriting from
        basePrototype.options = $.widget.extend({}, basePrototype.options);
        $.each(prototype, function(prop, value) {
            if (!$.isFunction(value)) {
                proxiedPrototype[prop] = value;
                return;
            }
            proxiedPrototype[prop] = (function() {
                var _super = function() {
                    return base.prototype[prop].apply(this, arguments);
                },
                _superApply = function(args) {
                    return base.prototype[prop].apply(this, args);
                };
                return function() {
                    var __super = this._super,
                    __superApply = this._superApply,
                    returnValue;

                    this._super = _super;
                    this._superApply = _superApply;

                    returnValue = value.apply(this, arguments);

                    this._super = __super;
                    this._superApply = __superApply;

                    return returnValue;
                };
            })();
        });
        constructor.prototype = $.widget.extend(basePrototype, {
            // TODO: remove support for widgetEventPrefix
            // always use the name + a colon as the prefix, e.g., draggable:start
            // don't prefix for widgets that aren't DOM-based
            widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
        }, proxiedPrototype, {
            constructor: constructor,
            namespace: namespace,
            widgetName: name,
            widgetFullName: fullName
        });

        // If this widget is being redefined then we need to find all widgets that
        // are inheriting from it and redefine all of them so that they inherit from
        // the new version of this widget. We're essentially trying to replace one
        // level in the prototype chain.
        if (existingConstructor) {
            $.each(existingConstructor._childConstructors, function(i, child) {
                var childPrototype = child.prototype;

                // redefine the child widget using the same prototype that was
                // originally used, but inherit from the new version of the base
                $.widget(childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto);
            });
            // remove the list of existing child constructors from the old constructor
            // so the old child constructors can be garbage collected
            delete existingConstructor._childConstructors;
        } else {
            base._childConstructors.push(constructor);
        }

        $.widget.bridge(name, constructor);

        return constructor;
    };

    $.widget.extend = function(target) {
        var input = widget_slice.call(arguments, 1),
        inputIndex = 0,
        inputLength = input.length,
        key,
        value;
        for (; inputIndex < inputLength; inputIndex++) {
            for (key in input[inputIndex]) {
                value = input[inputIndex][key];
                if (input[inputIndex].hasOwnProperty(key) && value !== undefined) {
                    // Clone objects
                    if ($.isPlainObject(value)) {
                        target[key] = $.isPlainObject(target[key]) ?
                        $.widget.extend({}, target[key], value) :
                        // Don't extend strings, arrays, etc. with objects
                        $.widget.extend({}, value);
                        // Copy everything else by reference
                    } else {
                        target[key] = value;
                    }
                }
            }
        }
        return target;
    };

    $.widget.bridge = function(name, object) {
        var fullName = object.prototype.widgetFullName || name;
        $.fn[name] = function(options) {
            var isMethodCall = typeof options === "string",
            args = widget_slice.call(arguments, 1),
            returnValue = this;

            // allow multiple hashes to be passed on init
            options = !isMethodCall && args.length ?
            $.widget.extend.apply(null, [options].concat(args)) :
            options;

            if (isMethodCall) {
                this.each(function() {
                    var methodValue,
                    instance = $.data(this, fullName);
                    if (options === "instance") {
                        returnValue = instance;
                        return false;
                    }
                    if (!instance) {
                        return $.error("cannot call methods on " + name + " prior to initialization; " +
                        "attempted to call method '" + options + "'");
                    }
                    if (!$.isFunction(instance[options]) || options.charAt(0) === "_") {
                        return $.error("no such method '" + options + "' for " + name + " widget instance");
                    }
                    methodValue = instance[options].apply(instance, args);
                    if (methodValue !== instance && methodValue !== undefined) {
                        returnValue = methodValue && methodValue.jquery ?
                        returnValue.pushStack(methodValue.get()) :
                        methodValue;
                        return false;
                    }
                });
            } else {
                this.each(function() {
                    var instance = $.data(this, fullName);
                    if (instance) {
                        instance.option(options || {});
                        if (instance._init) {
                            instance._init();
                        }
                    } else {
                        $.data(this, fullName, new object(options, this));
                    }
                });
            }

            return returnValue;
        };
    };

    $.Widget = function( /* options, element */) { };
    $.Widget._childConstructors = [];

    $.Widget.prototype = {
        widgetName: "widget",
        widgetEventPrefix: "",
        defaultElement: "<div>",
        options: {
            disabled: false,

            // callbacks
            create: null
        },
        _createWidget: function(options, element) {
            element = $(element || this.defaultElement || this)[0];
            this.element = $(element);
            this.uuid = widget_uuid++;
            this.eventNamespace = "." + this.widgetName + this.uuid;
            this.options = $.widget.extend({},
            this.options,
            this._getCreateOptions(),
            options);

            this.bindings = $();
            this.hoverable = $();
            this.focusable = $();

            if (element !== this) {
                $.data(element, this.widgetFullName, this);
                this._on(true, this.element, {
                    remove: function(event) {
                        if (event.target === element) {
                            this.destroy();
                        }
                    }
                });
                this.document = $(element.style ?
                // element within the document
                element.ownerDocument :
                // element is window or document
                element.document || element);
                this.window = $(this.document[0].defaultView || this.document[0].parentWindow);
            }

            this._create();
            this._trigger("create", null, this._getCreateEventData());
            this._init();
        },
        _getCreateOptions: $.noop,
        _getCreateEventData: $.noop,
        _create: $.noop,
        _init: $.noop,

        destroy: function() {
            this._destroy();
            // we can probably remove the unbind calls in 2.0
            // all event bindings should go through this._on()
            this.element
            .unbind(this.eventNamespace)
            .removeData(this.widgetFullName)
            // support: jquery <1.6.3
            // http://bugs.jquery.com/ticket/9413
            .removeData($.camelCase(this.widgetFullName));
            this.widget()
            .unbind(this.eventNamespace)
            .removeAttr("aria-disabled")
            .removeClass(
                this.widgetFullName + "-disabled " +
                "ui-state-disabled");

            // clean up events and states
            this.bindings.unbind(this.eventNamespace);
            this.hoverable.removeClass("ui-state-hover");
            this.focusable.removeClass("ui-state-focus");
        },
        _destroy: $.noop,

        widget: function() {
            return this.element;
        },

        option: function(key, value) {
            var options = key,
            parts,
            curOption,
            i;

            if (arguments.length === 0) {
                // don't return a reference to the internal hash
                return $.widget.extend({}, this.options);
            }

            if (typeof key === "string") {
                // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
                options = {};
                parts = key.split(".");
                key = parts.shift();
                if (parts.length) {
                    curOption = options[key] = $.widget.extend({}, this.options[key]);
                    for (i = 0; i < parts.length - 1; i++) {
                        curOption[parts[i]] = curOption[parts[i]] || {};
                        curOption = curOption[parts[i]];
                    }
                    key = parts.pop();
                    if (arguments.length === 1) {
                        return curOption[key] === undefined ? null : curOption[key];
                    }
                    curOption[key] = value;
                } else {
                    if (arguments.length === 1) {
                        return this.options[key] === undefined ? null : this.options[key];
                    }
                    options[key] = value;
                }
            }

            this._setOptions(options);

            return this;
        },
        _setOptions: function(options) {
            var key;

            for (key in options) {
                this._setOption(key, options[key]);
            }

            return this;
        },
        _setOption: function(key, value) {
            this.options[key] = value;

            if (key === "disabled") {
                this.widget()
                .toggleClass(this.widgetFullName + "-disabled", !!value);

                // If the widget is becoming disabled, then nothing is interactive
                if (value) {
                    this.hoverable.removeClass("ui-state-hover");
                    this.focusable.removeClass("ui-state-focus");
                }
            }

            return this;
        },

        enable: function() {
            return this._setOptions({ disabled: false });
        },
        disable: function() {
            return this._setOptions({ disabled: true });
        },

        _on: function(suppressDisabledCheck, element, handlers) {
            var delegateElement,
            instance = this;

            // no suppressDisabledCheck flag, shuffle arguments
            if (typeof suppressDisabledCheck !== "boolean") {
                handlers = element;
                element = suppressDisabledCheck;
                suppressDisabledCheck = false;
            }

            // no element argument, shuffle and use this.element
            if (!handlers) {
                handlers = element;
                element = this.element;
                delegateElement = this.widget();
            } else {
                element = delegateElement = $(element);
                this.bindings = this.bindings.add(element);
            }

            $.each(handlers, function(event, handler) {
                function handlerProxy() {
                    // allow widgets to customize the disabled handling
                    // - disabled as an array instead of boolean
                    // - disabled class as method for disabling individual parts
                    if (!suppressDisabledCheck &&
                        (instance.options.disabled === true ||
                            $(this).hasClass("ui-state-disabled"))) {
                        return;
                    }
                    return (typeof handler === "string" ? instance[handler] : handler)
                    .apply(instance, arguments);
                }

                // copy the guid so direct unbinding works
                if (typeof handler !== "string") {
                    handlerProxy.guid = handler.guid =
                    handler.guid || handlerProxy.guid || $.guid++;
                }

                var match = event.match(/^([w:-]*)s*(.*)$/),
                eventName = match[1] + instance.eventNamespace,
                selector = match[2];
                if (selector) {
                    delegateElement.delegate(selector, eventName, handlerProxy);
                } else {
                    element.bind(eventName, handlerProxy);
                }
            });
        },

        _off: function(element, eventName) {
            eventName = (eventName || "").split(" ").join(this.eventNamespace + " ") + this.eventNamespace;
            element.unbind(eventName).undelegate(eventName);
        },

        _delay: function(handler, delay) {
            function handlerProxy() {
                return (typeof handler === "string" ? instance[handler] : handler)
                .apply(instance, arguments);
            }
            var instance = this;
            return setTimeout(handlerProxy, delay || 0);
        },

        _hoverable: function(element) {
            this.hoverable = this.hoverable.add(element);
            this._on(element, {
                mouseenter: function(event) {
                    $(event.currentTarget).addClass("ui-state-hover");
                },
                mouseleave: function(event) {
                    $(event.currentTarget).removeClass("ui-state-hover");
                }
            });
        },

        _focusable: function(element) {
            this.focusable = this.focusable.add(element);
            this._on(element, {
                focusin: function(event) {
                    $(event.currentTarget).addClass("ui-state-focus");
                },
                focusout: function(event) {
                    $(event.currentTarget).removeClass("ui-state-focus");
                }
            });
        },

        _trigger: function(type, event, data) {
            var prop, orig,
            callback = this.options[type];

            data = data || {};
            event = $.Event(event);
            event.type = (type === this.widgetEventPrefix ?
            type :
            this.widgetEventPrefix + type).toLowerCase();
            // the original event may come from any element
            // so we need to reset the target on the new event
            event.target = this.element[0];

            // copy original event properties over to the new event
            orig = event.originalEvent;
            if (orig) {
                for (prop in orig) {
                    if (!(prop in event)) {
                        event[prop] = orig[prop];
                    }
                }
            }

            this.element.trigger(event, data);
            return !($.isFunction(callback) &&
            callback.apply(this.element[0], [event].concat(data)) === false ||
            event.isDefaultPrevented());
        }
    };

    $.each({ show: "fadeIn", hide: "fadeOut" }, function(method, defaultEffect) {
        $.Widget.prototype["_" + method] = function(element, options, callback) {
            if (typeof options === "string") {
                options = { effect: options };
            }
            var hasOptions,
            effectName = !options ?
                method :
                options === true || typeof options === "number" ?
                    defaultEffect :
                    options.effect || defaultEffect;
            options = options || {};
            if (typeof options === "number") {
                options = { duration: options };
            }
            hasOptions = !$.isEmptyObject(options);
            options.complete = callback;
            if (options.delay) {
                element.delay(options.delay);
            }
            if (hasOptions && $.effects && $.effects.effect[effectName]) {
                element[method](options);
            } else if (effectName !== method && element[effectName]) {
                element[effectName](options.duration, options.easing, callback);
            } else {
                element.queue(function(next) {
                    $(this)[method]();
                    if (callback) {
                        callback.call(element[0]);
                    }
                    next();
                });
            }
        };
    });

    var widget = $.widget;


    /*!
    * jQuery UI Position 1.11.0
    * http://jqueryui.com
    *
    * Copyright 2014 jQuery Foundation and other contributors
    * Released under the MIT license.
    * http://jquery.org/license
    *
    * http://api.jqueryui.com/position/
    */

    (function() {

        $.ui = $.ui || {};

        var cachedScrollbarWidth, supportsOffsetFractions,
    max = Math.max,
    abs = Math.abs,
    round = Math.round,
    rhorizontal = /left|center|right/,
    rvertical = /top|center|bottom/,
    roffset = /[+-]d+(.[d]+)?%?/,
    rposition = /^w+/,
    rpercent = /%$/,
    _position = $.fn.position;

        function getOffsets(offsets, width, height) {
            return [
        parseFloat(offsets[0]) * (rpercent.test(offsets[0]) ? width / 100 : 1),
        parseFloat(offsets[1]) * (rpercent.test(offsets[1]) ? height / 100 : 1)
    ];
        }

        function parseCss(element, property) {
            return parseInt($.css(element, property), 10) || 0;
        }

        function getDimensions(elem) {
            var raw = elem[0];
            if (raw.nodeType === 9) {
                return {
                     elem.width(),
                    height: elem.height(),
                    offset: { top: 0, left: 0 }
                };
            }
            if ($.isWindow(raw)) {
                return {
                     elem.width(),
                    height: elem.height(),
                    offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
                };
            }
            if (raw.preventDefault) {
                return {
                     0,
                    height: 0,
                    offset: { top: raw.pageY, left: raw.pageX }
                };
            }
            return {
                 elem.outerWidth(),
                height: elem.outerHeight(),
                offset: elem.offset()
            };
        }

        $.position = {
            scrollbarWidth: function() {
                if (cachedScrollbarWidth !== undefined) {
                    return cachedScrollbarWidth;
                }
                var w1, w2,
            div = $("<div style='display:block;position:absolute;50px;height:50px;overflow:hidden;'><div style='height:100px;auto;'></div></div>"),
            innerDiv = div.children()[0];

                $("body").append(div);
                w1 = innerDiv.offsetWidth;
                div.css("overflow", "scroll");

                w2 = innerDiv.offsetWidth;

                if (w1 === w2) {
                    w2 = div[0].clientWidth;
                }

                div.remove();

                return (cachedScrollbarWidth = w1 - w2);
            },
            getScrollInfo: function(within) {
                var overflowX = within.isWindow || within.isDocument ? "" :
                within.element.css("overflow-x"),
            overflowY = within.isWindow || within.isDocument ? "" :
                within.element.css("overflow-y"),
            hasOverflowX = overflowX === "scroll" ||
                (overflowX === "auto" && within.width < within.element[0].scrollWidth),
            hasOverflowY = overflowY === "scroll" ||
                (overflowY === "auto" && within.height < within.element[0].scrollHeight);
                return {
                     hasOverflowY ? $.position.scrollbarWidth() : 0,
                    height: hasOverflowX ? $.position.scrollbarWidth() : 0
                };
            },
            getWithinInfo: function(element) {
                var withinElement = $(element || window),
            isWindow = $.isWindow(withinElement[0]),
            isDocument = !!withinElement[0] && withinElement[0].nodeType === 9;
                return {
                    element: withinElement,
                    isWindow: isWindow,
                    isDocument: isDocument,
                    offset: withinElement.offset() || { left: 0, top: 0 },
                    scrollLeft: withinElement.scrollLeft(),
                    scrollTop: withinElement.scrollTop(),
                     isWindow ? withinElement.width() : withinElement.outerWidth(),
                    height: isWindow ? withinElement.height() : withinElement.outerHeight()
                };
            }
        };

        $.fn.position = function(options) {
            if (!options || !options.of) {
                return _position.apply(this, arguments);
            }

            // make a copy, we don't want to modify arguments
            options = $.extend({}, options);

            var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
        target = $(options.of),
        within = $.position.getWithinInfo(options.within),
        scrollInfo = $.position.getScrollInfo(within),
        collision = (options.collision || "flip").split(" "),
        offsets = {};

            dimensions = getDimensions(target);
            if (target[0].preventDefault) {
                // force left top to allow flipping
                options.at = "left top";
            }
            targetWidth = dimensions.width;
            targetHeight = dimensions.height;
            targetOffset = dimensions.offset;
            // clone to reuse original targetOffset later
            basePosition = $.extend({}, targetOffset);

            // force my and at to have valid horizontal and vertical positions
            // if a value is missing or invalid, it will be converted to center
            $.each(["my", "at"], function() {
                var pos = (options[this] || "").split(" "),
            horizontalOffset,
            verticalOffset;

                if (pos.length === 1) {
                    pos = rhorizontal.test(pos[0]) ?
                pos.concat(["center"]) :
                rvertical.test(pos[0]) ?
                    ["center"].concat(pos) :
                    ["center", "center"];
                }
                pos[0] = rhorizontal.test(pos[0]) ? pos[0] : "center";
                pos[1] = rvertical.test(pos[1]) ? pos[1] : "center";

                // calculate offsets
                horizontalOffset = roffset.exec(pos[0]);
                verticalOffset = roffset.exec(pos[1]);
                offsets[this] = [
            horizontalOffset ? horizontalOffset[0] : 0,
            verticalOffset ? verticalOffset[0] : 0
        ];

                // reduce to just the positions without the offsets
                options[this] = [
            rposition.exec(pos[0])[0],
            rposition.exec(pos[1])[0]
        ];
            });

            // normalize collision option
            if (collision.length === 1) {
                collision[1] = collision[0];
            }

            if (options.at[0] === "right") {
                basePosition.left += targetWidth;
            } else if (options.at[0] === "center") {
                basePosition.left += targetWidth / 2;
            }

            if (options.at[1] === "bottom") {
                basePosition.top += targetHeight;
            } else if (options.at[1] === "center") {
                basePosition.top += targetHeight / 2;
            }

            atOffset = getOffsets(offsets.at, targetWidth, targetHeight);
            basePosition.left += atOffset[0];
            basePosition.top += atOffset[1];

            return this.each(function() {
                var collisionPosition, using,
            elem = $(this),
            elemWidth = elem.outerWidth(),
            elemHeight = elem.outerHeight(),
            marginLeft = parseCss(this, "marginLeft"),
            marginTop = parseCss(this, "marginTop"),
            collisionWidth = elemWidth + marginLeft + parseCss(this, "marginRight") + scrollInfo.width,
            collisionHeight = elemHeight + marginTop + parseCss(this, "marginBottom") + scrollInfo.height,
            position = $.extend({}, basePosition),
            myOffset = getOffsets(offsets.my, elem.outerWidth(), elem.outerHeight());

                if (options.my[0] === "right") {
                    position.left -= elemWidth;
                } else if (options.my[0] === "center") {
                    position.left -= elemWidth / 2;
                }

                if (options.my[1] === "bottom") {
                    position.top -= elemHeight;
                } else if (options.my[1] === "center") {
                    position.top -= elemHeight / 2;
                }

                position.left += myOffset[0];
                position.top += myOffset[1];

                // if the browser doesn't support fractions, then round for consistent results
                if (!supportsOffsetFractions) {
                    position.left = round(position.left);
                    position.top = round(position.top);
                }

                collisionPosition = {
                    marginLeft: marginLeft,
                    marginTop: marginTop
                };

                $.each(["left", "top"], function(i, dir) {
                    if ($.ui.position[collision[i]]) {
                        $.ui.position[collision[i]][dir](position, {
                            targetWidth: targetWidth,
                            targetHeight: targetHeight,
                            elemWidth: elemWidth,
                            elemHeight: elemHeight,
                            collisionPosition: collisionPosition,
                            collisionWidth: collisionWidth,
                            collisionHeight: collisionHeight,
                            offset: [atOffset[0] + myOffset[0], atOffset[1] + myOffset[1]],
                            my: options.my,
                            at: options.at,
                            within: within,
                            elem: elem
                        });
                    }
                });

                if (options.using) {
                    // adds feedback as second argument to using callback, if present
                    using = function(props) {
                        var left = targetOffset.left - position.left,
                    right = left + targetWidth - elemWidth,
                    top = targetOffset.top - position.top,
                    bottom = top + targetHeight - elemHeight,
                    feedback = {
                        target: {
                            element: target,
                            left: targetOffset.left,
                            top: targetOffset.top,
                             targetWidth,
                            height: targetHeight
                        },
                        element: {
                            element: elem,
                            left: position.left,
                            top: position.top,
                             elemWidth,
                            height: elemHeight
                        },
                        horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
                        vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
                    };
                        if (targetWidth < elemWidth && abs(left + right) < targetWidth) {
                            feedback.horizontal = "center";
                        }
                        if (targetHeight < elemHeight && abs(top + bottom) < targetHeight) {
                            feedback.vertical = "middle";
                        }
                        if (max(abs(left), abs(right)) > max(abs(top), abs(bottom))) {
                            feedback.important = "horizontal";
                        } else {
                            feedback.important = "vertical";
                        }
                        options.using.call(this, props, feedback);
                    };
                }

                elem.offset($.extend(position, { using: using }));
            });
        };

        $.ui.position = {
            fit: {
                left: function(position, data) {
                    var within = data.within,
                withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
                outerWidth = within.width,
                collisionPosLeft = position.left - data.collisionPosition.marginLeft,
                overLeft = withinOffset - collisionPosLeft,
                overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
                newOverRight;

                    // element is wider than within
                    if (data.collisionWidth > outerWidth) {
                        // element is initially over the left side of within
                        if (overLeft > 0 && overRight <= 0) {
                            newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
                            position.left += overLeft - newOverRight;
                            // element is initially over right side of within
                        } else if (overRight > 0 && overLeft <= 0) {
                            position.left = withinOffset;
                            // element is initially over both left and right sides of within
                        } else {
                            if (overLeft > overRight) {
                                position.left = withinOffset + outerWidth - data.collisionWidth;
                            } else {
                                position.left = withinOffset;
                            }
                        }
                        // too far left -> align with left edge
                    } else if (overLeft > 0) {
                        position.left += overLeft;
                        // too far right -> align with right edge
                    } else if (overRight > 0) {
                        position.left -= overRight;
                        // adjust based on position and margin
                    } else {
                        position.left = max(position.left - collisionPosLeft, position.left);
                    }
                },
                top: function(position, data) {
                    var within = data.within,
                withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
                outerHeight = data.within.height,
                collisionPosTop = position.top - data.collisionPosition.marginTop,
                overTop = withinOffset - collisionPosTop,
                overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
                newOverBottom;

                    // element is taller than within
                    if (data.collisionHeight > outerHeight) {
                        // element is initially over the top of within
                        if (overTop > 0 && overBottom <= 0) {
                            newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
                            position.top += overTop - newOverBottom;
                            // element is initially over bottom of within
                        } else if (overBottom > 0 && overTop <= 0) {
                            position.top = withinOffset;
                            // element is initially over both top and bottom of within
                        } else {
                            if (overTop > overBottom) {
                                position.top = withinOffset + outerHeight - data.collisionHeight;
                            } else {
                                position.top = withinOffset;
                            }
                        }
                        // too far up -> align with top
                    } else if (overTop > 0) {
                        position.top += overTop;
                        // too far down -> align with bottom edge
                    } else if (overBottom > 0) {
                        position.top -= overBottom;
                        // adjust based on position and margin
                    } else {
                        position.top = max(position.top - collisionPosTop, position.top);
                    }
                }
            },
            flip: {
                left: function(position, data) {
                    var within = data.within,
                withinOffset = within.offset.left + within.scrollLeft,
                outerWidth = within.width,
                offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
                collisionPosLeft = position.left - data.collisionPosition.marginLeft,
                overLeft = collisionPosLeft - offsetLeft,
                overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
                myOffset = data.my[0] === "left" ?
                    -data.elemWidth :
                    data.my[0] === "right" ?
                        data.elemWidth :
                        0,
                atOffset = data.at[0] === "left" ?
                    data.targetWidth :
                    data.at[0] === "right" ?
                        -data.targetWidth :
                        0,
                offset = -2 * data.offset[0],
                newOverRight,
                newOverLeft;

                    if (overLeft < 0) {
                        newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
                        if (newOverRight < 0 || newOverRight < abs(overLeft)) {
                            position.left += myOffset + atOffset + offset;
                        }
                    } else if (overRight > 0) {
                        newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
                        if (newOverLeft > 0 || abs(newOverLeft) < overRight) {
                            position.left += myOffset + atOffset + offset;
                        }
                    }
                },
                top: function(position, data) {
                    var within = data.within,
                withinOffset = within.offset.top + within.scrollTop,
                outerHeight = within.height,
                offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
                collisionPosTop = position.top - data.collisionPosition.marginTop,
                overTop = collisionPosTop - offsetTop,
                overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
                top = data.my[1] === "top",
                myOffset = top ?
                    -data.elemHeight :
                    data.my[1] === "bottom" ?
                        data.elemHeight :
                        0,
                atOffset = data.at[1] === "top" ?
                    data.targetHeight :
                    data.at[1] === "bottom" ?
                        -data.targetHeight :
                        0,
                offset = -2 * data.offset[1],
                newOverTop,
                newOverBottom;
                    if (overTop < 0) {
                        newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
                        if ((position.top + myOffset + atOffset + offset) > overTop && (newOverBottom < 0 || newOverBottom < abs(overTop))) {
                            position.top += myOffset + atOffset + offset;
                        }
                    } else if (overBottom > 0) {
                        newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
                        if ((position.top + myOffset + atOffset + offset) > overBottom && (newOverTop > 0 || abs(newOverTop) < overBottom)) {
                            position.top += myOffset + atOffset + offset;
                        }
                    }
                }
            },
            flipfit: {
                left: function() {
                    $.ui.position.flip.left.apply(this, arguments);
                    $.ui.position.fit.left.apply(this, arguments);
                },
                top: function() {
                    $.ui.position.flip.top.apply(this, arguments);
                    $.ui.position.fit.top.apply(this, arguments);
                }
            }
        };

        // fraction support test
        (function() {
            var testElement, testElementParent, testElementStyle, offsetLeft, i,
        body = document.getElementsByTagName("body")[0],
        div = document.createElement("div");

            //Create a "fake body" for testing based on method used in jQuery.support
            testElement = document.createElement(body ? "div" : "body");
            testElementStyle = {
                visibility: "hidden",
                 0,
                height: 0,
                border: 0,
                margin: 0,
                background: "none"
            };
            if (body) {
                $.extend(testElementStyle, {
                    position: "absolute",
                    left: "-1000px",
                    top: "-1000px"
                });
            }
            for (i in testElementStyle) {
                testElement.style[i] = testElementStyle[i];
            }
            testElement.appendChild(div);
            testElementParent = body || document.documentElement;
            testElementParent.insertBefore(testElement, testElementParent.firstChild);

            div.style.cssText = "position: absolute; left: 10.7432222px;";

            offsetLeft = $(div).offset().left;
            supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11;

            testElement.innerHTML = "";
            testElementParent.removeChild(testElement);
        })();

    })();

    var position = $.ui.position;


    /*!
    * jQuery UI Menu 1.11.0
    * http://jqueryui.com
    *
    * Copyright 2014 jQuery Foundation and other contributors
    * Released under the MIT license.
    * http://jquery.org/license
    *
    * http://api.jqueryui.com/menu/
    */


    var menu = $.widget("ui.menu", {
        version: "1.11.0",
        defaultElement: "<ul>",
        delay: 300,
        options: {
            icons: {
                submenu: "ui-icon-carat-1-e"
            },
            items: "> *",
            menus: "ul",
            position: {
                my: "left-1 top",
                at: "right top"
            },
            role: "menu",

            // callbacks
            blur: null,
            focus: null,
            select: null
        },

        _create: function() {
            this.activeMenu = this.element;

            // Flag used to prevent firing of the click handler
            // as the event bubbles up through nested menus
            this.mouseHandled = false;
            this.element
            .uniqueId()
            .addClass("ui-menu ui-widget ui-widget-content")
            .toggleClass("ui-menu-icons", !!this.element.find(".ui-icon").length)
            .attr({
                role: this.options.role,
                tabIndex: 0
            });

            if (this.options.disabled) {
                this.element
                .addClass("ui-state-disabled")
                .attr("aria-disabled", "true");
            }

            this._on({
                // Prevent focus from sticking to links inside menu after clicking
                // them (focus should always stay on UL during navigation).
                "mousedown .ui-menu-item": function(event) {
                    event.preventDefault();
                },
                "click .ui-menu-item": function(event) {
                    var target = $(event.target);
                    if (!this.mouseHandled && target.not(".ui-state-disabled").length) {
                        this.select(event);

                        // Only set the mouseHandled flag if the event will bubble, see #9469.
                        if (!event.isPropagationStopped()) {
                            this.mouseHandled = true;
                        }

                        // Open submenu on click
                        if (target.has(".ui-menu").length) {
                            this.expand(event);
                        } else if (!this.element.is(":focus") && $(this.document[0].activeElement).closest(".ui-menu").length) {

                            // Redirect focus to the menu
                            this.element.trigger("focus", [true]);

                            // If the active item is on the top level, let it stay active.
                            // Otherwise, blur the active item since it is no longer visible.
                            if (this.active && this.active.parents(".ui-menu").length === 1) {
                                clearTimeout(this.timer);
                            }
                        }
                    }
                },
                "mouseenter .ui-menu-item": function(event) {
                    var target = $(event.currentTarget);
                    // Remove ui-state-active class from siblings of the newly focused menu item
                    // to avoid a jump caused by adjacent elements both having a class with a border
                    target.siblings(".ui-state-active").removeClass("ui-state-active");
                    this.focus(event, target);
                },
                mouseleave: "collapseAll",
                "mouseleave .ui-menu": "collapseAll",
                focus: function(event, keepActiveItem) {
                    // If there's already an active item, keep it active
                    // If not, activate the first item
                    var item = this.active || this.element.find(this.options.items).eq(0);

                    if (!keepActiveItem) {
                        this.focus(event, item);
                    }
                },
                blur: function(event) {
                    this._delay(function() {
                        if (!$.contains(this.element[0], this.document[0].activeElement)) {
                            this.collapseAll(event);
                        }
                    });
                },
                keydown: "_keydown"
            });

            this.refresh();

            // Clicks outside of a menu collapse any open menus
            this._on(this.document, {
                click: function(event) {
                    if (this._closeOnDocumentClick(event)) {
                        this.collapseAll(event);
                    }

                    // Reset the mouseHandled flag
                    this.mouseHandled = false;
                }
            });
        },

        _destroy: function() {
            // Destroy (sub)menus
            this.element
            .removeAttr("aria-activedescendant")
            .find(".ui-menu").addBack()
                .removeClass("ui-menu ui-widget ui-widget-content ui-menu-icons ui-front")
                .removeAttr("role")
                .removeAttr("tabIndex")
                .removeAttr("aria-labelledby")
                .removeAttr("aria-expanded")
                .removeAttr("aria-hidden")
                .removeAttr("aria-disabled")
                .removeUniqueId()
                .show();

            // Destroy menu items
            this.element.find(".ui-menu-item")
            .removeClass("ui-menu-item")
            .removeAttr("role")
            .removeAttr("aria-disabled")
            .removeUniqueId()
            .removeClass("ui-state-hover")
            .removeAttr("tabIndex")
            .removeAttr("role")
            .removeAttr("aria-haspopup")
            .children().each(function() {
                var elem = $(this);
                if (elem.data("ui-menu-submenu-carat")) {
                    elem.remove();
                }
            });

            // Destroy menu dividers
            this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content");
        },

        _keydown: function(event) {
            var match, prev, character, skip, regex,
            preventDefault = true;

            function escape(value) {
                return value.replace(/[-[]{}()*+?.,\^$|#s]/g, "\$&");
            }

            switch (event.keyCode) {
                case $.ui.keyCode.PAGE_UP:
                    this.previousPage(event);
                    break;
                case $.ui.keyCode.PAGE_DOWN:
                    this.nextPage(event);
                    break;
                case $.ui.keyCode.HOME:
                    this._move("first", "first", event);
                    break;
                case $.ui.keyCode.END:
                    this._move("last", "last", event);
                    break;
                case $.ui.keyCode.UP:
                    this.previous(event);
                    break;
                case $.ui.keyCode.DOWN:
                    this.next(event);
                    break;
                case $.ui.keyCode.LEFT:
                    this.collapse(event);
                    break;
                case $.ui.keyCode.RIGHT:
                    if (this.active && !this.active.is(".ui-state-disabled")) {
                        this.expand(event);
                    }
                    break;
                case $.ui.keyCode.ENTER:
                case $.ui.keyCode.SPACE:
                    this._activate(event);
                    break;
                case $.ui.keyCode.ESCAPE:
                    this.collapse(event);
                    break;
                default:
                    preventDefault = false;
                    prev = this.previousFilter || "";
                    character = String.fromCharCode(event.keyCode);
                    skip = false;

                    clearTimeout(this.filterTimer);

                    if (character === prev) {
                        skip = true;
                    } else {
                        character = prev + character;
                    }

                    regex = new RegExp("^" + escape(character), "i");
                    match = this.activeMenu.find(this.options.items).filter(function() {
                        return regex.test($(this).text());
                    });
                    match = skip && match.index(this.active.next()) !== -1 ?
                this.active.nextAll(".ui-menu-item") :
                match;

                    // If no matches on the current filter, reset to the last character pressed
                    // to move down the menu to the first item that starts with that character
                    if (!match.length) {
                        character = String.fromCharCode(event.keyCode);
                        regex = new RegExp("^" + escape(character), "i");
                        match = this.activeMenu.find(this.options.items).filter(function() {
                            return regex.test($(this).text());
                        });
                    }

                    if (match.length) {
                        this.focus(event, match);
                        if (match.length > 1) {
                            this.previousFilter = character;
                            this.filterTimer = this._delay(function() {
                                delete this.previousFilter;
                            }, 1000);
                        } else {
                            delete this.previousFilter;
                        }
                    } else {
                        delete this.previousFilter;
                    }
            }

            if (preventDefault) {
                event.preventDefault();
            }
        },

        _activate: function(event) {
            if (!this.active.is(".ui-state-disabled")) {
                if (this.active.is("[aria-haspopup='true']")) {
                    this.expand(event);
                } else {
                    this.select(event);
                }
            }
        },

        refresh: function() {
            var menus, items,
            that = this,
            icon = this.options.icons.submenu,
            submenus = this.element.find(this.options.menus);

            this.element.toggleClass("ui-menu-icons", !!this.element.find(".ui-icon").length);

            // Initialize nested menus
            submenus.filter(":not(.ui-menu)")
            .addClass("ui-menu ui-widget ui-widget-content ui-front")
            .hide()
            .attr({
                role: this.options.role,
                "aria-hidden": "true",
                "aria-expanded": "false"
            })
            .each(function() {
                var menu = $(this),
                    item = menu.parent(),
                    submenuCarat = $("<span>")
                        .addClass("ui-menu-icon ui-icon " + icon)
                        .data("ui-menu-submenu-carat", true);

                item
                    .attr("aria-haspopup", "true")
                    .prepend(submenuCarat);
                menu.attr("aria-labelledby", item.attr("id"));
            });

            menus = submenus.add(this.element);
            items = menus.find(this.options.items);

            // Initialize menu-items containing spaces and/or dashes only as dividers
            items.not(".ui-menu-item").each(function() {
                var item = $(this);
                if (that._isDivider(item)) {
                    item.addClass("ui-widget-content ui-menu-divider");
                }
            });

            // Don't refresh list items that are already adapted
            items.not(".ui-menu-item, .ui-menu-divider")
            .addClass("ui-menu-item")
            .uniqueId()
            .attr({
                tabIndex: -1,
                role: this._itemRole()
            });

            // Add aria-disabled attribute to any disabled menu item
            items.filter(".ui-state-disabled").attr("aria-disabled", "true");

            // If the active item has been removed, blur the menu
            if (this.active && !$.contains(this.element[0], this.active[0])) {
                this.blur();
            }
        },

        _itemRole: function() {
            return {
                menu: "menuitem",
                listbox: "option"
}[this.options.role];
            },

            _setOption: function(key, value) {
                if (key === "icons") {
                    this.element.find(".ui-menu-icon")
                .removeClass(this.options.icons.submenu)
                .addClass(value.submenu);
                }
                if (key === "disabled") {
                    this.element
                .toggleClass("ui-state-disabled", !!value)
                .attr("aria-disabled", value);
                }
                this._super(key, value);
            },

            focus: function(event, item) {
                var nested, focused;
                this.blur(event, event && event.type === "focus");

                this._scrollIntoView(item);

                this.active = item.first();
                focused = this.active.addClass("ui-state-focus").removeClass("ui-state-active");
                // Only update aria-activedescendant if there's a role
                // otherwise we assume focus is managed elsewhere
                if (this.options.role) {
                    this.element.attr("aria-activedescendant", focused.attr("id"));
                }

                // Highlight active parent menu item, if any
                this.active
            .parent()
            .closest(".ui-menu-item")
            .addClass("ui-state-active");

                if (event && event.type === "keydown") {
                    this._close();
                } else {
                    this.timer = this._delay(function() {
                        this._close();
                    }, this.delay);
                }

                nested = item.children(".ui-menu");
                if (nested.length && event && (/^mouse/.test(event.type))) {
                    this._startOpening(nested);
                }
                this.activeMenu = item.parent();

                this._trigger("focus", event, { item: item });
            },

            _scrollIntoView: function(item) {
                var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
                if (this._hasScroll()) {
                    borderTop = parseFloat($.css(this.activeMenu[0], "borderTopWidth")) || 0;
                    paddingTop = parseFloat($.css(this.activeMenu[0], "paddingTop")) || 0;
                    offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
                    scroll = this.activeMenu.scrollTop();
                    elementHeight = this.activeMenu.height();
                    itemHeight = item.outerHeight();

                    if (offset < 0) {
                        this.activeMenu.scrollTop(scroll + offset);
                    } else if (offset + itemHeight > elementHeight) {
                        this.activeMenu.scrollTop(scroll + offset - elementHeight + itemHeight);
                    }
                }
            },

            blur: function(event, fromFocus) {
                if (!fromFocus) {
                    clearTimeout(this.timer);
                }

                if (!this.active) {
                    return;
                }

                this.active.removeClass("ui-state-focus");
                this.active = null;

                this._trigger("blur", event, { item: this.active });
            },

            _startOpening: function(submenu) {
                clearTimeout(this.timer);

                // Don't open if already open fixes a Firefox bug that caused a .5 pixel
                // shift in the submenu position when mousing over the carat icon
                if (submenu.attr("aria-hidden") !== "true") {
                    return;
                }

                this.timer = this._delay(function() {
                    this._close();
                    this._open(submenu);
                }, this.delay);
            },

            _open: function(submenu) {
                var position = $.extend({
                    of: this.active
                }, this.options.position);

                clearTimeout(this.timer);
                this.element.find(".ui-menu").not(submenu.parents(".ui-menu"))
            .hide()
            .attr("aria-hidden", "true");

                submenu
            .show()
            .removeAttr("aria-hidden")
            .attr("aria-expanded", "true")
            .position(position);
            },

            collapseAll: function(event, all) {
                clearTimeout(this.timer);
                this.timer = this._delay(function() {
                    // If we were passed an event, look for the submenu that contains the event
                    var currentMenu = all ? this.element :
                $(event && event.target).closest(this.element.find(".ui-menu"));

                    // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
                    if (!currentMenu.length) {
                        currentMenu = this.element;
                    }

                    this._close(currentMenu);

                    this.blur(event);
                    this.activeMenu = currentMenu;
                }, this.delay);
            },

            // With no arguments, closes the currently active menu - if nothing is active
            // it closes all menus.  If passed an argument, it will search for menus BELOW
            _close: function(startMenu) {
                if (!startMenu) {
                    startMenu = this.active ? this.active.parent() : this.element;
                }

                startMenu
            .find(".ui-menu")
                .hide()
                .attr("aria-hidden", "true")
                .attr("aria-expanded", "false")
            .end()
            .find(".ui-state-active").not(".ui-state-focus")
                .removeClass("ui-state-active");
            },

            _closeOnDocumentClick: function(event) {
                return !$(event.target).closest(".ui-menu").length;
            },

            _isDivider: function(item) {

                // Match hyphen, em dash, en dash
                return !/[^-u2014u2013s]/.test(item.text());
            },

            collapse: function(event) {
                var newItem = this.active &&
            this.active.parent().closest(".ui-menu-item", this.element);
                if (newItem && newItem.length) {
                    this._close();
                    this.focus(event, newItem);
                }
            },

            expand: function(event) {
                var newItem = this.active &&
            this.active
                .children(".ui-menu ")
                .find(this.options.items)
                .first();

                if (newItem && newItem.length) {
                    this._open(newItem.parent());

                    // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
                    this._delay(function() {
                        this.focus(event, newItem);
                    });
                }
            },

            next: function(event) {
                this._move("next", "first", event);
            },

            previous: function(event) {
                this._move("prev", "last", event);
            },

            isFirstItem: function() {
                return this.active && !this.active.prevAll(".ui-menu-item").length;
            },

            isLastItem: function() {
                return this.active && !this.active.nextAll(".ui-menu-item").length;
            },

            _move: function(direction, filter, event) {
                var next;
                if (this.active) {
                    if (direction === "first" || direction === "last") {
                        next = this.active
                    [direction === "first" ? "prevAll" : "nextAll"](".ui-menu-item")
                    .eq(-1);
                    } else {
                        next = this.active
                    [direction + "All"](".ui-menu-item")
                    .eq(0);
                    }
                }
                if (!next || !next.length || !this.active) {
                    next = this.activeMenu.find(this.options.items)[filter]();
                }

                this.focus(event, next);
            },

            nextPage: function(event) {
                var item, base, height;

                if (!this.active) {
                    this.next(event);
                    return;
                }
                if (this.isLastItem()) {
                    return;
                }
                if (this._hasScroll()) {
                    base = this.active.offset().top;
                    height = this.element.height();
                    this.active.nextAll(".ui-menu-item").each(function() {
                        item = $(this);
                        return item.offset().top - base - height < 0;
                    });

                    this.focus(event, item);
                } else {
                    this.focus(event, this.activeMenu.find(this.options.items)
                [!this.active ? "first" : "last"]());
                }
            },

            previousPage: function(event) {
                var item, base, height;
                if (!this.active) {
                    this.next(event);
                    return;
                }
                if (this.isFirstItem()) {
                    return;
                }
                if (this._hasScroll()) {
                    base = this.active.offset().top;
                    height = this.element.height();
                    this.active.prevAll(".ui-menu-item").each(function() {
                        item = $(this);
                        return item.offset().top - base + height > 0;
                    });

                    this.focus(event, item);
                } else {
                    this.focus(event, this.activeMenu.find(this.options.items).first());
                }
            },

            _hasScroll: function() {
                return this.element.outerHeight() < this.element.prop("scrollHeight");
            },

            select: function(event) {
                // TODO: It should never be possible to not have an active item at this
                // point, but the tests don't trigger mouseenter before click.
                this.active = this.active || $(event.target).closest(".ui-menu-item");
                var ui = { item: this.active };
                if (!this.active.has(".ui-menu").length) {
                    this.collapseAll(event, true);
                }
                this._trigger("select", event, ui);
            }
        });


        /*!
        * jQuery UI Autocomplete 1.11.0
        * http://jqueryui.com
        *
        * Copyright 2014 jQuery Foundation and other contributors
        * Released under the MIT license.
        * http://jquery.org/license
        *
        * http://api.jqueryui.com/autocomplete/
        */


        $.widget("ui.autocomplete", {
            version: "1.11.0",
            defaultElement: "<input>",
            options: {
                appendTo: null,
                autoFocus: false,
                delay: 300,
                minLength: 1,
                position: {
                    my: "left top",
                    at: "left bottom",
                    collision: "none"
                },
                source: null,

                // callbacks
                change: null,
                close: null,
                focus: null,
                open: null,
                response: null,
                search: null,
                select: null,
                //all,label,value
                matchType: 'all'
            },

            requestIndex: 0,
            pending: 0,

            _create: function() {
                // Some browsers only repeat keydown events, not keypress events,
                // so we use the suppressKeyPress flag to determine if we've already
                // handled the keydown event. #7269
                // Unfortunately the code for & in keypress is the same as the up arrow,
                // so we use the suppressKeyPressRepeat flag to avoid handling keypress
                // events when we know the keydown event was used to modify the
                // search term. #7799
                var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
            nodeName = this.element[0].nodeName.toLowerCase(),
            isTextarea = nodeName === "textarea",
            isInput = nodeName === "input";

                this.isMultiLine =
                // Textareas are always multi-line
            isTextarea ? true :
                // Inputs are always single-line, even if inside a contentEditable element
                // IE also treats inputs as contentEditable
            isInput ? false :
                // All other element types are determined by whether or not they're contentEditable
            this.element.prop("isContentEditable");

                this.valueMethod = this.element[isTextarea || isInput ? "val" : "text"];
                this.isNewMenu = true;

                this.element
            .addClass("ui-autocomplete-input")
            .attr("autocomplete", "off");

                this._on(this.element, {
                    keydown: function(event) {
                        if (this.element.prop("readOnly")) {
                            suppressKeyPress = true;
                            suppressInput = true;
                            suppressKeyPressRepeat = true;
                            return;
                        }

                        suppressKeyPress = false;
                        suppressInput = false;
                        suppressKeyPressRepeat = false;
                        var keyCode = $.ui.keyCode;
                        switch (event.keyCode) {
                            case keyCode.PAGE_UP:
                                suppressKeyPress = true;
                                this._move("previousPage", event);
                                break;
                            case keyCode.PAGE_DOWN:
                                suppressKeyPress = true;
                                this._move("nextPage", event);
                                break;
                            case keyCode.UP:
                                suppressKeyPress = true;
                                this._keyEvent("previous", event);
                                break;
                            case keyCode.DOWN:
                                suppressKeyPress = true;
                                this._keyEvent("next", event);
                                break;
                            case keyCode.ENTER:
                                // when menu is open and has focus
                                if (this.menu.active) {
                                    // #6055 - Opera still allows the keypress to occur
                                    // which causes forms to submit
                                    suppressKeyPress = true;
                                    event.preventDefault();
                                    this.menu.select(event);
                                }
                                break;
                            case keyCode.TAB:
                                if (this.menu.active) {
                                    this.menu.select(event);
                                }
                                break;
                            case keyCode.ESCAPE:
                                if (this.menu.element.is(":visible")) {
                                    this._value(this.term);
                                    this.close(event);
                                    // Different browsers have different default behavior for escape
                                    // Single press can mean undo or clear
                                    // Double press in IE means clear the whole form
                                    event.preventDefault();
                                }
                                break;
                            default:
                                suppressKeyPressRepeat = true;
                                // search timeout should be triggered before the input value is changed
                                this._searchTimeout(event);
                                break;
                        }
                    },
                    keypress: function(event) {
                        if (suppressKeyPress) {
                            suppressKeyPress = false;
                            if (!this.isMultiLine || this.menu.element.is(":visible")) {
                                event.preventDefault();
                            }
                            return;
                        }
                        if (suppressKeyPressRepeat) {
                            return;
                        }

                        // replicate some key handlers to allow them to repeat in Firefox and Opera
                        var keyCode = $.ui.keyCode;
                        switch (event.keyCode) {
                            case keyCode.PAGE_UP:
                                this._move("previousPage", event);
                                break;
                            case keyCode.PAGE_DOWN:
                                this._move("nextPage", event);
                                break;
                            case keyCode.UP:
                                this._keyEvent("previous", event);
                                break;
                            case keyCode.DOWN:
                                this._keyEvent("next", event);
                                break;
                        }
                    },
                    input: function(event) {
                        if (suppressInput) {
                            suppressInput = false;
                            event.preventDefault();
                            return;
                        }
                        this._searchTimeout(event);
                    },
                    focus: function() {
                        this.selectedItem = null;
                        this.previous = this._value();
                    },
                    blur: function(event) {
                        if (this.cancelBlur) {
                            delete this.cancelBlur;
                            return;
                        }

                        clearTimeout(this.searching);
                        this.close(event);
                        this._change(event);
                    }
                });

                this._initSource();
                this.menu = $("<ul>")
            .addClass("ui-autocomplete ui-front")
            .appendTo(this._appendTo())
            .menu({
                // disable ARIA support, the live region takes care of that
                role: null
            })
            .hide()
            .menu("instance");

                this._on(this.menu.element, {
                    mousedown: function(event) {
                        // prevent moving focus out of the text field
                        event.preventDefault();

                        // IE doesn't prevent moving focus even with event.preventDefault()
                        // so we set a flag to know when we should ignore the blur event
                        this.cancelBlur = true;
                        this._delay(function() {
                            delete this.cancelBlur;
                        });

                        // clicking on the scrollbar causes focus to shift to the body
                        // but we can't detect a mouseup or a click immediately afterward
                        // so we have to track the next mousedown and close the menu if
                        // the user clicks somewhere outside of the autocomplete
                        var menuElement = this.menu.element[0];
                        if (!$(event.target).closest(".ui-menu-item").length) {
                            this._delay(function() {
                                var that = this;
                                this.document.one("mousedown", function(event) {
                                    if (event.target !== that.element[0] &&
                                    event.target !== menuElement &&
                                    !$.contains(menuElement, event.target)) {
                                        that.close();
                                    }
                                });
                            });
                        }
                    },
                    menufocus: function(event, ui) {
                        var label, item;
                        // support: Firefox
                        // Prevent accidental activation of menu items in Firefox (#7024 #9118)
                        if (this.isNewMenu) {
                            this.isNewMenu = false;
                            if (event.originalEvent && /^mouse/.test(event.originalEvent.type)) {
                                this.menu.blur();

                                this.document.one("mousemove", function() {
                                    $(event.target).trigger(event.originalEvent);
                                });

                                return;
                            }
                        }

                        item = ui.item.data("ui-autocomplete-item");
                        if (false !== this._trigger("focus", event, { item: item })) {
                            // use value to match what will end up in the input, if it was a key event
                            if (event.originalEvent && /^key/.test(event.originalEvent.type)) {
                                this._value(item.value);
                            }
                        }

                        // Announce the value in the liveRegion
                        label = ui.item.attr("aria-label") || item.value;
                        if (label && jQuery.trim(label).length) {
                            this.liveRegion.children().hide();
                            $("<div>").text(label).appendTo(this.liveRegion);
                        }
                    },
                    menuselect: function(event, ui) {
                        var item = ui.item.data("ui-autocomplete-item"),
                    previous = this.previous;

                        // only trigger when focus was lost (click on menu)
                        if (this.element[0] !== this.document[0].activeElement) {
                            this.element.focus();
                            this.previous = previous;
                            // #6109 - IE triggers two focus events and the second
                            // is asynchronous, so we need to reset the previous
                            // term synchronously and asynchronously :-(
                            this._delay(function() {
                                this.previous = previous;
                                this.selectedItem = item;
                            });
                        }

                        if (false !== this._trigger("select", event, { item: item })) {
                            this._value(item.value);
                        }
                        // reset the term after the select event
                        // this allows custom select handling to work properly
                        this.term = this._value();

                        this.close(event);
                        this.selectedItem = item;
                    }
                });

                this.liveRegion = $("<span>", {
                    role: "status",
                    "aria-live": "assertive",
                    "aria-relevant": "additions"
                })
            .addClass("ui-helper-hidden-accessible")
            .appendTo(this.document[0].body);

                // turning off autocomplete prevents the browser from remembering the
                // value when navigating through history, so we re-enable autocomplete
                // if the page is unloaded before the widget is destroyed. #7790
                this._on(this.window, {
                    beforeunload: function() {
                        this.element.removeAttr("autocomplete");
                    }
                });
            },

            _destroy: function() {
                clearTimeout(this.searching);
                this.element
            .removeClass("ui-autocomplete-input")
            .removeAttr("autocomplete");
                this.menu.element.remove();
                this.liveRegion.remove();
            },

            _setOption: function(key, value) {
                this._super(key, value);
                if (key === "source") {
                    this._initSource();
                }
                if (key === "appendTo") {
                    this.menu.element.appendTo(this._appendTo());
                }
                if (key === "disabled" && value && this.xhr) {
                    this.xhr.abort();
                }
            },

            _appendTo: function() {
                var element = this.options.appendTo;

                if (element) {
                    element = element.jquery || element.nodeType ?
                $(element) :
                this.document.find(element).eq(0);
                }

                if (!element || !element[0]) {
                    element = this.element.closest(".ui-front");
                }

                if (!element.length) {
                    element = this.document[0].body;
                }

                return element;
            },

            _initSource: function() {
                var array, url, type
                that = this;
                if ($.isArray(this.options.source)) {
                    array = this.options.source;
                    type = this.options.matchType;
                    this.source = function(request, response) {
                    response($.ui.autocomplete.filter(array, request.term, type));
                    };
                } else if (typeof this.options.source === "string") {
                    url = this.options.source;
                    this.source = function(request, response) {
                        if (that.xhr) {
                            that.xhr.abort();
                        }
                        that.xhr = $.ajax({
                            url: url,
                            data: request,
                            dataType: "json",
                            success: function(data) {
                                response(data);
                            },
                            error: function() {
                                response([]);
                            }
                        });
                    };
                } else {
                    this.source = this.options.source;
                }
            },

            _searchTimeout: function(event) {
                clearTimeout(this.searching);
                this.searching = this._delay(function() {

                    // Search if the value has changed, or if the user retypes the same value (see #7434)
                    var equalValues = this.term === this._value(),
                menuVisible = this.menu.element.is(":visible"),
                modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;

                    if (!equalValues || (equalValues && !menuVisible && !modifierKey)) {
                        this.selectedItem = null;
                        this.search(null, event);
                    }
                }, this.options.delay);
            },

            search: function(value, event) {
                value = value != null ? value : this._value();

                // always save the actual value, not the one passed as an argument
                this.term = this._value();

                if (value.length < this.options.minLength) {
                    return this.close(event);
                }

                if (this._trigger("search", event) === false) {
                    return;
                }

                return this._search(value);
            },

            _search: function(value) {
                this.pending++;
                this.element.addClass("ui-autocomplete-loading");
                this.cancelSearch = false;

                this.source({ term: value }, this._response());
            },

            _response: function() {
                var index = ++this.requestIndex;

                return $.proxy(function(content) {
                    if (index === this.requestIndex) {
                        this.__response(content);
                    }

                    this.pending--;
                    if (!this.pending) {
                        this.element.removeClass("ui-autocomplete-loading");
                    }
                }, this);
            },

            __response: function(content) {
                if (content) {
                    content = this._normalize(content);
                }
                this._trigger("response", null, { content: content });
                if (!this.options.disabled && content && content.length && !this.cancelSearch) {
                    this._suggest(content);
                    this._trigger("open");
                } else {
                    // use ._close() instead of .close() so we don't cancel future searches
                    this._close();
                }
            },

            close: function(event) {
                this.cancelSearch = true;
                this._close(event);
            },

            _close: function(event) {
                if (this.menu.element.is(":visible")) {
                    this.menu.element.hide();
                    this.menu.blur();
                    this.isNewMenu = true;
                    this._trigger("close", event);
                }
            },

            _change: function(event) {
                if (this.previous !== this._value()) {
                    this._trigger("change", event, { item: this.selectedItem });
                }
            },

            _normalize: function(items) {
                // assume all items have the right format when the first item is complete
                if (items.length && items[0].label && items[0].value) {
                    return items;
                }
                return $.map(items, function(item) {
                    if (typeof item === "string") {
                        return {
                            label: item,
                            value: item
                        };
                    }
                    return $.extend({}, item, {
                        label: item.label || item.value,
                        value: item.value || item.label
                    });
                });
            },

            _suggest: function(items) {
                var ul = this.menu.element.empty();
                this._renderMenu(ul, items);
                this.isNewMenu = true;
                this.menu.refresh();

                // size and position menu
                ul.show();
                this._resizeMenu();
                ul.position($.extend({
                    of: this.element
                }, this.options.position));

                if (this.options.autoFocus) {
                    this.menu.next();
                }
            },

            _resizeMenu: function() {
                var ul = this.menu.element;
                ul.outerWidth(Math.max(
                // Firefox wraps long text (possibly a rounding bug)
                // so we add 1px to avoid the wrapping (#7513)
            ul.width("").outerWidth() + 1,
            this.element.outerWidth()
        ));
            },

            _renderMenu: function(ul, items) {
                var that = this;
                $.each(items, function(index, item) {
                    that._renderItemData(ul, item);
                });
            },

            _renderItemData: function(ul, item) {
                return this._renderItem(ul, item).data("ui-autocomplete-item", item);
            },

            _renderItem: function(ul, item) {
                return $("<li>").text(item.label).appendTo(ul);
            },

            _move: function(direction, event) {
                if (!this.menu.element.is(":visible")) {
                    this.search(null, event);
                    return;
                }
                if (this.menu.isFirstItem() && /^previous/.test(direction) ||
                this.menu.isLastItem() && /^next/.test(direction)) {

                    if (!this.isMultiLine) {
                        this._value(this.term);
                    }

                    this.menu.blur();
                    return;
                }
                this.menu[direction](event);
            },

            widget: function() {
                return this.menu.element;
            },

            _value: function() {
                return this.valueMethod.apply(this.element, arguments);
            },

            _keyEvent: function(keyEvent, event) {
                if (!this.isMultiLine || this.menu.element.is(":visible")) {
                    this._move(keyEvent, event);

                    // prevents moving cursor to beginning/end of the text field in some browsers
                    event.preventDefault();
                }
            }
        });

        $.extend($.ui.autocomplete, {
            escapeRegex: function(value) {
                return value.replace(/[-[]{}()*+?.,\^$|#s]/g, "\$&");
            },
            filter: function(array, term,type) {
                var matcher = new RegExp($.ui.autocomplete.escapeRegex(term), "i");

                return $.grep(array, function(value) {
                    if (type == "label") {
                        return matcher.test(value.value);
                    } else if (type == "value") {
                        return matcher.test(value.value);

                    } else {
                        return matcher.test(value.label || value.value || value);
                    }
                });
            }
        });

        // live region extension, adding a `messages` option
        // NOTE: This is an experimental API. We are still investigating
        // a full solution for string manipulation and internationalization.
        $.widget("ui.autocomplete", $.ui.autocomplete, {
            options: {
                messages: {
                    noResults: "No search results.",
                    results: function(amount) {
                        return amount + (amount > 1 ? " results are" : " result is") +
                    " available, use up and down arrow keys to navigate.";
                    }
                }
            },

            __response: function(content) {
                var message;
                this._superApply(arguments);
                if (this.options.disabled || this.cancelSearch) {
                    return;
                }
                if (content && content.length) {
                    message = this.options.messages.results(content.length);
                } else {
                    message = this.options.messages.noResults;
                }
                this.liveRegion.children().hide();
                $("<div>").text(message).appendTo(this.liveRegion);
            }
        });

        var autocomplete = $.ui.autocomplete;



    }));
原文地址:https://www.cnblogs.com/blackice/p/5129378.html