679 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			679 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
/*!
 | 
						|
 * jQuery UI Autocomplete 1.13.2
 | 
						|
 * http://jqueryui.com
 | 
						|
 *
 | 
						|
 * Copyright jQuery Foundation and other contributors
 | 
						|
 * Released under the MIT license.
 | 
						|
 * http://jquery.org/license
 | 
						|
 */
 | 
						|
 | 
						|
//>>label: Autocomplete
 | 
						|
//>>group: Widgets
 | 
						|
//>>description: Lists suggested words as the user is typing.
 | 
						|
//>>docs: http://api.jqueryui.com/autocomplete/
 | 
						|
//>>demos: http://jqueryui.com/autocomplete/
 | 
						|
//>>css.structure: ../../themes/base/core.css
 | 
						|
//>>css.structure: ../../themes/base/autocomplete.css
 | 
						|
//>>css.theme: ../../themes/base/theme.css
 | 
						|
 | 
						|
( function( factory ) {
 | 
						|
    "use strict";
 | 
						|
 | 
						|
    if ( typeof define === "function" && define.amd ) {
 | 
						|
 | 
						|
        // AMD. Register as an anonymous module.
 | 
						|
        define( [
 | 
						|
            "jquery",
 | 
						|
            "./menu",
 | 
						|
            "../keycode",
 | 
						|
            "../position",
 | 
						|
            "../safe-active-element",
 | 
						|
            "../version",
 | 
						|
            "../widget"
 | 
						|
        ], factory );
 | 
						|
    } else {
 | 
						|
 | 
						|
        // Browser globals
 | 
						|
        factory( jQuery );
 | 
						|
    }
 | 
						|
} )( function( $ ) {
 | 
						|
    "use strict";
 | 
						|
 | 
						|
    $.widget( "ui.autocomplete", {
 | 
						|
        version: "1.13.2",
 | 
						|
        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,
 | 
						|
        liveRegionTimer: null,
 | 
						|
 | 
						|
        _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";
 | 
						|
 | 
						|
            // Textareas are always multi-line
 | 
						|
            // Inputs are always single-line, even if inside a contentEditable element
 | 
						|
            // IE also treats inputs as contentEditable
 | 
						|
            // All other element types are determined by whether or not they're contentEditable
 | 
						|
            this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element );
 | 
						|
 | 
						|
            this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
 | 
						|
            this.isNewMenu = true;
 | 
						|
 | 
						|
            this._addClass( "ui-autocomplete-input" );
 | 
						|
            this.element.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 ) {
 | 
						|
                    clearTimeout( this.searching );
 | 
						|
                    this.close( event );
 | 
						|
                    this._change( event );
 | 
						|
                }
 | 
						|
            } );
 | 
						|
 | 
						|
            this._initSource();
 | 
						|
            this.menu = $( "<ul>" )
 | 
						|
                .appendTo( this._appendTo() )
 | 
						|
                .menu( {
 | 
						|
 | 
						|
                    // disable ARIA support, the live region takes care of that
 | 
						|
                    role: null
 | 
						|
                } )
 | 
						|
                .hide()
 | 
						|
 | 
						|
                // Support: IE 11 only, Edge <= 14
 | 
						|
                // For other browsers, we preventDefault() on the mousedown event
 | 
						|
                // to keep the dropdown from taking focus from the input. This doesn't
 | 
						|
                // work for IE/Edge, causing problems with selection and scrolling (#9638)
 | 
						|
                // Happily, IE and Edge support an "unselectable" attribute that
 | 
						|
                // prevents an element from receiving focus, exactly what we want here.
 | 
						|
                .attr( {
 | 
						|
                    "unselectable": "on"
 | 
						|
                } )
 | 
						|
                .menu( "instance" );
 | 
						|
 | 
						|
            this._addClass( this.menu.element, "ui-autocomplete", "ui-front" );
 | 
						|
            this._on( this.menu.element, {
 | 
						|
                mousedown: function( event ) {
 | 
						|
 | 
						|
                    // Prevent moving focus out of the text field
 | 
						|
                    event.preventDefault();
 | 
						|
                },
 | 
						|
                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 && String.prototype.trim.call( label ).length ) {
 | 
						|
                        clearTimeout( this.liveRegionTimer );
 | 
						|
                        this.liveRegionTimer = this._delay( function() {
 | 
						|
                            this.liveRegion.html( $( "<div>" ).text( label ) );
 | 
						|
                        }, 100 );
 | 
						|
                    }
 | 
						|
                },
 | 
						|
                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 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
 | 
						|
                        this.element.trigger( "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 = $( "<div>", {
 | 
						|
                role: "status",
 | 
						|
                "aria-live": "assertive",
 | 
						|
                "aria-relevant": "additions"
 | 
						|
            } )
 | 
						|
                .appendTo( this.document[ 0 ].body );
 | 
						|
 | 
						|
            this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
 | 
						|
 | 
						|
            // 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.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();
 | 
						|
            }
 | 
						|
        },
 | 
						|
 | 
						|
        _isEventTargetInWidget: function( event ) {
 | 
						|
            var menuElement = this.menu.element[ 0 ];
 | 
						|
 | 
						|
            return event.target === this.element[ 0 ] ||
 | 
						|
                event.target === menuElement ||
 | 
						|
                $.contains( menuElement, event.target );
 | 
						|
        },
 | 
						|
 | 
						|
        _closeOnClickOutside: function( event ) {
 | 
						|
            if ( !this._isEventTargetInWidget( event ) ) {
 | 
						|
                this.close();
 | 
						|
            }
 | 
						|
        },
 | 
						|
 | 
						|
        _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, dialog" );
 | 
						|
            }
 | 
						|
 | 
						|
            if ( !element.length ) {
 | 
						|
                element = this.document[ 0 ].body;
 | 
						|
            }
 | 
						|
 | 
						|
            return element;
 | 
						|
        },
 | 
						|
 | 
						|
        _initSource: function() {
 | 
						|
            var array, url,
 | 
						|
                that = this;
 | 
						|
            if ( Array.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._addClass( "ui-autocomplete-loading" );
 | 
						|
            this.cancelSearch = false;
 | 
						|
 | 
						|
            this.source( { term: value }, this._response() );
 | 
						|
        },
 | 
						|
 | 
						|
        _response: function() {
 | 
						|
            var index = ++this.requestIndex;
 | 
						|
 | 
						|
            return function( content ) {
 | 
						|
                if ( index === this.requestIndex ) {
 | 
						|
                    this.__response( content );
 | 
						|
                }
 | 
						|
 | 
						|
                this.pending--;
 | 
						|
                if ( !this.pending ) {
 | 
						|
                    this._removeClass( "ui-autocomplete-loading" );
 | 
						|
                }
 | 
						|
            }.bind( 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 ) {
 | 
						|
 | 
						|
            // Remove the handler that closes the menu on outside clicks
 | 
						|
            this._off( this.document, "mousedown" );
 | 
						|
 | 
						|
            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();
 | 
						|
            }
 | 
						|
 | 
						|
            // Listen for interactions outside of the widget (#6642)
 | 
						|
            this._on( this.document, {
 | 
						|
                mousedown: "_closeOnClickOutside"
 | 
						|
            } );
 | 
						|
        },
 | 
						|
 | 
						|
        _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>" )
 | 
						|
                .append( $( "<div>" ).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();
 | 
						|
            }
 | 
						|
        },
 | 
						|
 | 
						|
        // Support: Chrome <=50
 | 
						|
        // We should be able to just use this.element.prop( "isContentEditable" )
 | 
						|
        // but hidden elements always report false in Chrome.
 | 
						|
        // https://code.google.com/p/chromium/issues/detail?id=313082
 | 
						|
        _isContentEditable: function( element ) {
 | 
						|
            if ( !element.length ) {
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
 | 
						|
            var editable = element.prop( "contentEditable" );
 | 
						|
 | 
						|
            if ( editable === "inherit" ) {
 | 
						|
                return this._isContentEditable( element.parent() );
 | 
						|
            }
 | 
						|
 | 
						|
            return editable === "true";
 | 
						|
        }
 | 
						|
    } );
 | 
						|
 | 
						|
    $.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;
 | 
						|
            }
 | 
						|
            clearTimeout( this.liveRegionTimer );
 | 
						|
            this.liveRegionTimer = this._delay( function() {
 | 
						|
                this.liveRegion.html( $( "<div>" ).text( message ) );
 | 
						|
            }, 100 );
 | 
						|
        }
 | 
						|
    } );
 | 
						|
 | 
						|
    return $.ui.autocomplete;
 | 
						|
 | 
						|
} );
 |