: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* jQuery UI Autocomplete 1.13.3
* Copyright OpenJS Foundation and other contributors
* Released under the MIT license.
* https://jquery.org/license
//>>description: Lists suggested words as the user is typing.
//>>docs: https://api.jqueryui.com/autocomplete/
//>>demos: https://jqueryui.com/autocomplete/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/autocomplete.css
//>>css.theme: ../../themes/base/theme.css
if ( typeof define === "function" && define.amd ) {
// AMD. Register as an anonymous module.
"../safe-active-element",
$.widget( "ui.autocomplete", {
defaultElement: "<input>",
// 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
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._addClass( "ui-autocomplete-input" );
this.element.attr( "autocomplete", "off" );
this._on( this.element, {
keydown: function( event ) {
if ( this.element.prop( "readOnly" ) ) {
suppressKeyPressRepeat = true;
suppressKeyPress = false;
suppressKeyPressRepeat = false;
var keyCode = $.ui.keyCode;
switch ( event.keyCode ) {
this._move( "previousPage", event );
this._move( "nextPage", event );
this._keyEvent( "previous", event );
this._keyEvent( "next", event );
// when menu is open and has focus
if ( this.menu.active ) {
// #6055 - Opera still allows the keypress to occur
// which causes forms to submit
this.menu.select( event );
if ( this.menu.active ) {
this.menu.select( event );
if ( this.menu.element.is( ":visible" ) ) {
if ( !this.isMultiLine ) {
this._value( this.term );
// Different browsers have different default behavior for escape
// Single press can mean undo or clear
// Double press in IE means clear the whole form
suppressKeyPressRepeat = true;
// search timeout should be triggered before the input value is changed
this._searchTimeout( event );
keypress: function( event ) {
if ( suppressKeyPress ) {
suppressKeyPress = false;
if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
if ( suppressKeyPressRepeat ) {
// Replicate some key handlers to allow them to repeat in Firefox and Opera
var keyCode = $.ui.keyCode;
switch ( event.keyCode ) {
this._move( "previousPage", event );
this._move( "nextPage", event );
this._keyEvent( "previous", event );
this._keyEvent( "next", event );
input: function( event ) {
this._searchTimeout( event );
this.selectedItem = null;
this.previous = this._value();
blur: function( event ) {
clearTimeout( this.searching );
.appendTo( this._appendTo() )
// disable ARIA support, the live region takes care of that
// 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.
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
menufocus: function( event, ui ) {
// Prevent accidental activation of menu items in Firefox (#7024 #9118)
if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
this.document.one( "mousemove", function() {
$( event.target ).trigger( event.originalEvent );
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 ) );
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.selectedItem = item;
this.liveRegion = $( "<div>", {
"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
beforeunload: function() {
this.element.removeAttr( "autocomplete" );
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" ) {
if ( key === "appendTo" ) {
this.menu.element.appendTo( this._appendTo() );
if ( key === "disabled" && value && this.xhr ) {
_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 ) ) {
var element = this.options.appendTo;
element = element.jquery || element.nodeType ?
this.document.find( element ).eq( 0 );
if ( !element || !element[ 0 ] ) {
element = this.element.closest( ".ui-front, dialog" );
element = this.document[ 0 ].body;
_initSource: function() {
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 ) {
success: function( data ) {
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 );
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 this._search( value );
_search: function( value ) {
this._addClass( "ui-autocomplete-loading" );
this.cancelSearch = false;
this.source( { term: value }, this._response() );
var index = ++this.requestIndex;
return function( content ) {
if ( index === this.requestIndex ) {
this.__response( content );
this._removeClass( "ui-autocomplete-loading" );
__response: function( content ) {
content = this._normalize( content );
this._trigger( "response", null, { content: content } );
if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
this._suggest( content );
// use ._close() instead of .close() so we don't cancel future searches
close: function( event ) {
this.cancelSearch = true;
_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._trigger( "close", event );