Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4145075
jquery.ui.autocomplete.js
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
jquery.ui.autocomplete.js
View Options
/*!
* jQuery UI Autocomplete 1.9.2
* http://jqueryui.com
*
* Copyright 2012 jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/autocomplete/
*
* Depends:
* jquery.ui.core.js
* jquery.ui.widget.js
* jquery.ui.position.js
* jquery.ui.menu.js
*/
(
function
(
$
,
undefined
)
{
// used to prevent race conditions with remote data sources
var
requestIndex
=
0
;
$
.
widget
(
"ui.autocomplete"
,
{
version
:
"1.9.2"
,
defaultElement
:
"<input>"
,
options
:
{
appendTo
:
"body"
,
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
},
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
;
this
.
isMultiLine
=
this
.
_isMultiLine
();
this
.
valueMethod
=
this
.
element
[
this
.
element
.
is
(
"input,textarea"
)
?
"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
:
case
keyCode
.
NUMPAD_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
;
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"
)
.
appendTo
(
this
.
document
.
find
(
this
.
options
.
appendTo
||
"body"
)[
0
]
)
.
menu
({
// custom key handling for now
input
:
$
(),
// disable ARIA support, the live region takes care of that
role
:
null
})
.
zIndex
(
this
.
element
.
zIndex
()
+
1
)
.
hide
()
.
data
(
"menu"
);
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
)
{
// #7024 - Prevent accidental activation of menu items in Firefox
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
;
}
}
// back compat for _renderItem using item.autocomplete, via #7810
// TODO remove the fallback, see #8156
var
item
=
ui
.
item
.
data
(
"ui-autocomplete-item"
)
||
ui
.
item
.
data
(
"item.autocomplete"
);
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
);
}
}
else
{
// Normally the input is populated with the item's value as the
// menu is navigated, causing screen readers to notice a change and
// announce the item. Since the focus event was canceled, this doesn't
// happen, so we update the live region so that screen readers can
// still notice the change and announce it.
this
.
liveRegion
.
text
(
item
.
value
);
}
},
menuselect
:
function
(
event
,
ui
)
{
// back compat for _renderItem using item.autocomplete, via #7810
// TODO remove the fallback, see #8156
var
item
=
ui
.
item
.
data
(
"ui-autocomplete-item"
)
||
ui
.
item
.
data
(
"item.autocomplete"
),
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"
:
"polite"
})
.
addClass
(
"ui-helper-hidden-accessible"
)
.
insertAfter
(
this
.
element
);
if
(
$
.
fn
.
bgiframe
)
{
this
.
menu
.
element
.
bgiframe
();
}
// 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
.
document
.
find
(
value
||
"body"
)[
0
]
);
}
if
(
key
===
"disabled"
&&
value
&&
this
.
xhr
)
{
this
.
xhr
.
abort
();
}
},
_isMultiLine
:
function
()
{
// Textareas are always multi-line
if
(
this
.
element
.
is
(
"textarea"
)
)
{
return
true
;
}
// Inputs are always single-line, even if inside a contentEditable element
// IE also treats inputs as contentEditable
if
(
this
.
element
.
is
(
"input"
)
)
{
return
false
;
}
// All other element types are determined by whether or not they're contentEditable
return
this
.
element
.
prop
(
"isContentEditable"
);
},
_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
()
{
// only search if the value has changed
if
(
this
.
term
!==
this
.
_value
()
)
{
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
that
=
this
,
index
=
++
requestIndex
;
return
function
(
content
)
{
if
(
index
===
requestIndex
)
{
that
.
__response
(
content
);
}
that
.
pending
--
;
if
(
!
that
.
pending
)
{
that
.
element
.
removeClass
(
"ui-autocomplete-loading"
);
}
};
},
__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
({
label
:
item
.
label
||
item
.
value
,
value
:
item
.
value
||
item
.
label
},
item
);
});
},
_suggest
:
function
(
items
)
{
var
ul
=
this
.
menu
.
element
.
empty
()
.
zIndex
(
this
.
element
.
zIndex
()
+
1
);
this
.
_renderMenu
(
ul
,
items
);
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>"
)
.
append
(
$
(
"<a>"
).
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
)
)
{
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
.
text
(
message
);
}
});
}(
jQuery
));
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Aug 19 2026, 17:30 (5 w, 7 h ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
a2/e2/e379550c13d8def0cb65a1640d33
Default Alt Text
jquery.ui.autocomplete.js (15 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment