/*!

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

(function( factory ) {

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

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

        // Browser globals
        factory( jQuery );
}

}(function( $ ) {

$.widget( “ui.autocomplete”, {

version: "1.11.4",
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
},

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" ) ) {
                                        if ( !this.isMultiLine ) {
                                                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 && $.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,
                that = this;
        if ( $.isArray( this.options.source ) ) {
                array = this.options.source;
                this.source = function( request, response ) {
                        response( $.ui.autocomplete.filter( array, request.term ) );
                };
        } 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 ) {
        var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
        return $.grep( array, function( value ) {
                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 );
}

});

return $.ui.autocomplete;

}));