2014-10-07 17:28:24 +02:00
/ * !
2015-03-11 16:12:27 +01:00
* jQuery UI Autocomplete 1.11 . 4
2014-10-07 17:28:24 +02:00
* http : //jqueryui.com
*
2015-02-27 11:21:26 +01:00
* Copyright jQuery Foundation and other contributors
2014-10-07 17:28:24 +02:00
* Released under the MIT license .
* http : //jquery.org/license
*
* http : //api.jqueryui.com/autocomplete/
* /
2015-11-05 18:47:30 +01:00
! function ( a ) { "function" == typeof define && define . amd ?
// AMD. Register as an anonymous module.
define ( [ "jquery" , "./core" , "./widget" , "./position" , "./menu" ] , a ) :
// Browser globals
a ( jQuery ) } ( function ( a ) {
// 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.
return a . widget ( "ui.autocomplete" , { version : "1.11.4" , defaultElement : "<input>" , options : { appendTo : null , autoFocus : ! 1 , 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 b , c , d , e = this . element [ 0 ] . nodeName . toLowerCase ( ) , f = "textarea" === e , g = "input" === e ; this . isMultiLine = f ? ! 0 : g ? ! 1 :
// All other element types are determined by whether or not they're contentEditable
this . element . prop ( "isContentEditable" ) , this . valueMethod = this . element [ f || g ? "val" : "text" ] , this . isNewMenu = ! 0 , this . element . addClass ( "ui-autocomplete-input" ) . attr ( "autocomplete" , "off" ) , this . _on ( this . element , { keydown : function ( e ) { if ( this . element . prop ( "readOnly" ) ) return b = ! 0 , d = ! 0 , void ( c = ! 0 ) ; b = ! 1 , d = ! 1 , c = ! 1 ; var f = a . ui . keyCode ; switch ( e . keyCode ) { case f . PAGE _UP : b = ! 0 , this . _move ( "previousPage" , e ) ; break ; case f . PAGE _DOWN : b = ! 0 , this . _move ( "nextPage" , e ) ; break ; case f . UP : b = ! 0 , this . _keyEvent ( "previous" , e ) ; break ; case f . DOWN : b = ! 0 , this . _keyEvent ( "next" , e ) ; break ; case f . ENTER :
// when menu is open and has focus
this . menu . active && ( b = ! 0 , e . preventDefault ( ) , this . menu . select ( e ) ) ; break ; case f . TAB : this . menu . active && this . menu . select ( e ) ; break ; case f . ESCAPE : this . menu . element . is ( ":visible" ) && ( this . isMultiLine || this . _value ( this . term ) , this . close ( e ) ,
// Different browsers have different default behavior for escape
// Single press can mean undo or clear
// Double press in IE means clear the whole form
e . preventDefault ( ) ) ; break ; default : c = ! 0 ,
// search timeout should be triggered before the input value is changed
this . _searchTimeout ( e ) } } , keypress : function ( d ) { if ( b ) return b = ! 1 , void ( ( ! this . isMultiLine || this . menu . element . is ( ":visible" ) ) && d . preventDefault ( ) ) ; if ( ! c ) {
// replicate some key handlers to allow them to repeat in Firefox and Opera
var e = a . ui . keyCode ; switch ( d . keyCode ) { case e . PAGE _UP : this . _move ( "previousPage" , d ) ; break ; case e . PAGE _DOWN : this . _move ( "nextPage" , d ) ; break ; case e . UP : this . _keyEvent ( "previous" , d ) ; break ; case e . DOWN : this . _keyEvent ( "next" , d ) } } } , input : function ( a ) { return d ? ( d = ! 1 , void a . preventDefault ( ) ) : void this . _searchTimeout ( a ) } , focus : function ( ) { this . selectedItem = null , this . previous = this . _value ( ) } , blur : function ( a ) { return this . cancelBlur ? void delete this . cancelBlur : ( clearTimeout ( this . searching ) , this . close ( a ) , void this . _change ( a ) ) } } ) , this . _initSource ( ) , this . menu = a ( "<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 ( b ) {
// prevent moving focus out of the text field
b . 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 = ! 0 , 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 c = this . menu . element [ 0 ] ; a ( b . target ) . closest ( ".ui-menu-item" ) . length || this . _delay ( function ( ) { var b = this ; this . document . one ( "mousedown" , function ( d ) { d . target === b . element [ 0 ] || d . target === c || a . contains ( c , d . target ) || b . close ( ) } ) } ) } , menufocus : function ( b , c ) { var d , e ;
// support: Firefox
// Prevent accidental activation of menu items in Firefox (#7024 #9118)
// support: Firefox
// Prevent accidental activation of menu items in Firefox (#7024 #9118)
// Announce the value in the liveRegion
return this . isNewMenu && ( this . isNewMenu = ! 1 , b . originalEvent && /^mouse/ . test ( b . originalEvent . type ) ) ? ( this . menu . blur ( ) , void this . document . one ( "mousemove" , function ( ) { a ( b . target ) . trigger ( b . originalEvent ) } ) ) : ( e = c . item . data ( "ui-autocomplete-item" ) , ! 1 !== this . _trigger ( "focus" , b , { item : e } ) && b . originalEvent && /^key/ . test ( b . originalEvent . type ) && this . _value ( e . value ) , d = c . item . attr ( "aria-label" ) || e . value , void ( d && a . trim ( d ) . length && ( this . liveRegion . children ( ) . hide ( ) , a ( "<div>" ) . text ( d ) . appendTo ( this . liveRegion ) ) ) ) } , menuselect : function ( a , b ) { var c = b . item . data ( "ui-autocomplete-item" ) , d = this . previous ;
// only trigger when focus was lost (click on menu)
this . element [ 0 ] !== this . document [ 0 ] . activeElement && ( this . element . focus ( ) , this . previous = d ,
// #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 = d , this . selectedItem = c } ) ) , ! 1 !== this . _trigger ( "select" , a , { item : c } ) && this . _value ( c . value ) ,
// reset the term after the select event
// this allows custom select handling to work properly
this . term = this . _value ( ) , this . close ( a ) , this . selectedItem = c } } ) , this . liveRegion = a ( "<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 ( a , b ) { this . _super ( a , b ) , "source" === a && this . _initSource ( ) , "appendTo" === a && this . menu . element . appendTo ( this . _appendTo ( ) ) , "disabled" === a && b && this . xhr && this . xhr . abort ( ) } , _appendTo : function ( ) { var b = this . options . appendTo ; return b && ( b = b . jquery || b . nodeType ? a ( b ) : this . document . find ( b ) . eq ( 0 ) ) , b && b [ 0 ] || ( b = this . element . closest ( ".ui-front" ) ) , b . length || ( b = this . document [ 0 ] . body ) , b } , _initSource : function ( ) { var b , c , d = this ; a . isArray ( this . options . source ) ? ( b = this . options . source , this . source = function ( c , d ) { d ( a . ui . autocomplete . filter ( b , c . term ) ) } ) : "string" == typeof this . options . source ? ( c = this . options . source , this . source = function ( b , e ) { d . xhr && d . xhr . abort ( ) , d . xhr = a . ajax ( { url : c , data : b , dataType : "json" , success : function ( a ) { e ( a ) } , error : function ( ) { e ( [ ] ) } } ) } ) : this . source = this . options . source } , _searchTimeout : function ( a ) { 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 b = this . term === this . _value ( ) , c = this . menu . element . is ( ":visible" ) , d = a . altKey || a . ctrlKey || a . metaKey || a . shiftKey ; ( ! b || b && ! c && ! d ) && ( this . selectedItem = null , this . search ( null , a ) ) } , this . options . delay ) } , search : function ( a , b ) {
// always save the actual value, not the one passed as an argument
return a = null != a ? a : this . _value ( ) , this . term = this . _value ( ) , a . length < this . options . minLength ? this . close ( b ) : this . _trigger ( "search" , b ) !== ! 1 ? this . _search ( a ) : void 0 } , _search : function ( a ) { this . pending ++ , this . element . addClass ( "ui-autocomplete-loading" ) , this . cancelSearch = ! 1 , this . source ( { term : a } , this . _response ( ) ) } , _response : function ( ) { var b = ++ this . requestIndex ; return a . proxy ( function ( a ) { b === this . requestIndex && this . _ _response ( a ) , this . pending -- , this . pending || this . element . removeClass ( "ui-autocomplete-loading" ) } , this ) } , _ _response : function ( a ) { a && ( a = this . _normalize ( a ) ) , this . _trigger ( "response" , null , { content : a } ) , ! this . options . disabled && a && a . length && ! this . cancelSearch ? ( this . _suggest ( a ) , this . _trigger ( "open" ) ) :
// use ._close() instead of .close() so we don't cancel future searches
this . _close ( ) } , close : function ( a ) { this . cancelSearch = ! 0 , this . _close ( a ) } , _close : function ( a ) { this . menu . element . is ( ":visible" ) && ( this . menu . element . hide ( ) , this . menu . blur ( ) , this . isNewMenu = ! 0 , this . _trigger ( "close" , a ) ) } , _change : function ( a ) { this . previous !== this . _value ( ) && this . _trigger ( "change" , a , { item : this . selectedItem } ) } , _normalize : function ( b ) {
// assume all items have the right format when the first item is complete
// assume all items have the right format when the first item is complete
return b . length && b [ 0 ] . label && b [ 0 ] . value ? b : a . map ( b , function ( b ) { return "string" == typeof b ? { label : b , value : b } : a . extend ( { } , b , { label : b . label || b . value , value : b . value || b . label } ) } ) } , _suggest : function ( b ) { var c = this . menu . element . empty ( ) ; this . _renderMenu ( c , b ) , this . isNewMenu = ! 0 , this . menu . refresh ( ) ,
// size and position menu
c . show ( ) , this . _resizeMenu ( ) , c . position ( a . extend ( { of : this . element } , this . options . position ) ) , this . options . autoFocus && this . menu . next ( ) } , _resizeMenu : function ( ) { var a = this . menu . element ; a . outerWidth ( Math . max (
// Firefox wraps long text (possibly a rounding bug)
// so we add 1px to avoid the wrapping (#7513)
a . width ( "" ) . outerWidth ( ) + 1 , this . element . outerWidth ( ) ) ) } , _renderMenu : function ( b , c ) { var d = this ; a . each ( c , function ( a , c ) { d . _renderItemData ( b , c ) } ) } , _renderItemData : function ( a , b ) { return this . _renderItem ( a , b ) . data ( "ui-autocomplete-item" , b ) } , _renderItem : function ( b , c ) { return a ( "<li>" ) . text ( c . label ) . appendTo ( b ) } , _move : function ( a , b ) { return this . menu . element . is ( ":visible" ) ? this . menu . isFirstItem ( ) && /^previous/ . test ( a ) || this . menu . isLastItem ( ) && /^next/ . test ( a ) ? ( this . isMultiLine || this . _value ( this . term ) , void this . menu . blur ( ) ) : void this . menu [ a ] ( b ) : void this . search ( null , b ) } , widget : function ( ) { return this . menu . element } , _value : function ( ) { return this . valueMethod . apply ( this . element , arguments ) } , _keyEvent : function ( a , b ) { ( ! this . isMultiLine || this . menu . element . is ( ":visible" ) ) && ( this . _move ( a , b ) ,
// prevents moving cursor to beginning/end of the text field in some browsers
b . preventDefault ( ) ) } } ) , a . extend ( a . ui . autocomplete , { escapeRegex : function ( a ) { return a . replace ( /[\-\[\]{}()*+?.,\\\^$|#\s]/g , "\\$&" ) } , filter : function ( b , c ) { var d = new RegExp ( a . ui . autocomplete . escapeRegex ( c ) , "i" ) ; return a . grep ( b , function ( a ) { return d . test ( a . label || a . value || a ) } ) } } ) , a . widget ( "ui.autocomplete" , a . ui . autocomplete , { options : { messages : { noResults : "No search results." , results : function ( a ) { return a + ( a > 1 ? " results are" : " result is" ) + " available, use up and down arrow keys to navigate." } } } , _ _response : function ( b ) { var c ; this . _superApply ( arguments ) , this . options . disabled || this . cancelSearch || ( c = b && b . length ? this . options . messages . results ( b . length ) : this . options . messages . noResults , this . liveRegion . children ( ) . hide ( ) , a ( "<div>" ) . text ( c ) . appendTo ( this . liveRegion ) ) } } ) , a . ui . autocomplete } ) ;