2 * jQuery Autocomplete plugin 1.1
4 * Copyright (c) 2009 Jörn Zaefferer
6 * Dual licensed under the MIT and GPL licenses:
7 * http://www.opensource.org/licenses/mit-license.php
8 * http://www.gnu.org/licenses/gpl.html
10 * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
11 */;(function($
){$
.fn
.extend({autocomplete
:function(urlOrData
,options
){var isUrl
=typeof urlOrData
=="string";options
=$
.extend({},$
.Autocompleter
.defaults
,{url
:isUrl?urlOrData
:null,data
:isUrl?
null:urlOrData
,delay
:isUrl?$
.Autocompleter
.defaults
.delay
:10,max
:options
&&!options
.scroll?
10:150},options
);options
.highlight
=options
.highlight||
function(value
){return value
;};options
.formatMatch
=options
.formatMatch||options
.formatItem
;return this.each(function(){new $
.Autocompleter(this,options
);});},result
:function(handler
){return this.bind("result",handler
);},search
:function(handler
){return this.trigger("search",[handler]);},flushCache
:function(){return this.trigger("flushCache");},setOptions
:function(options
){return this.trigger("setOptions",[options]);},unautocomplete
:function(){return this.trigger("unautocomplete");}});$
.Autocompleter
=function(input
,options
){var KEY
={UP
:38,DOWN
:40,DEL
:46,TAB
:9,RETURN
:13,ESC
:27,COMMA
:188,PAGEUP
:33,PAGEDOWN
:34,BACKSPACE
:8};var $input
=$
(input
).attr("autocomplete","off").addClass(options
.inputClass
);var timeout
;var previousValue
="";var cache
=$
.Autocompleter
.Cache(options
);var hasFocus
=0;var lastKeyPressCode
;var config
={mouseDownOnSelect
:false};var select
=$
.Autocompleter
.Select(options
,input
,selectCurrent
,config
);var blockSubmit
;$
.browser
.opera
&&$
(input
.form
).bind("submit.autocomplete",function(){if(blockSubmit
){blockSubmit
=false;return false;}});$input
.bind(($
.browser
.opera?
"keypress":"keydown")+".autocomplete",function(event
){hasFocus
=1;lastKeyPressCode
=event
.keyCode
;switch(event
.keyCode
){case KEY
.UP
:event
.preventDefault();if(select
.visible()){select
.prev();}else{onChange(0,true);}break;case KEY
.DOWN
:event
.preventDefault();if(select
.visible()){select
.next();}else{onChange(0,true);}break;case KEY
.PAGEUP
:event
.preventDefault();if(select
.visible()){select
.pageUp();}else{onChange(0,true);}break;case KEY
.PAGEDOWN
:event
.preventDefault();if(select
.visible()){select
.pageDown();}else{onChange(0,true);}break;case options
.multiple
&&$
.trim(options
.multipleSeparator
)==","&&KEY
.COMMA
:case KEY
.TAB
:case KEY
.RETURN
:if(selectCurrent()){event
.preventDefault();blockSubmit
=true;return false;}break;case KEY
.ESC
:select
.hide();break;default:clearTimeout(timeout
);timeout
=setTimeout(onChange
,options
.delay
);break;}}).focus(function(){hasFocus
++;}).blur(function(){hasFocus
=0;if(!config
.mouseDownOnSelect
){hideResults();}}).click(function(){if(hasFocus
++>1&&!select
.visible()){onChange(0,true);}}).bind("search",function(){var fn
=(arguments
.length
>1)?arguments
[1]:null;function findValueCallback(q
,data
){var result
;if(data
&&data
.length
){for(var i
=0;i
<data
.length
;i
++){if(data
[i].result
.toLowerCase()==q
.toLowerCase()){result
=data
[i];break;}}}if(typeof fn
=="function")fn(result
);else $input
.trigger("result",result
&&[result
.data
,result
.value
]);}$
.each(trimWords($input
.val()),function(i
,value
){request(value
,findValueCallback
,findValueCallback
);});}).bind("flushCache",function(){cache
.flush();}).bind("setOptions",function(){$
.extend(options
,arguments
[1]);if("data"in arguments
[1])cache
.populate();}).bind("unautocomplete",function(){select
.unbind();$input
.unbind();$
(input
.form
).unbind(".autocomplete");});function selectCurrent(){var selected
=select
.selected();if(!selected
)return false;var v
=selected
.result
;previousValue
=v
;if(options
.multiple
){var words
=trimWords($input
.val());if(words
.length
>1){var seperator
=options
.multipleSeparator
.length
;var cursorAt
=$
(input
).selection().start
;var wordAt
,progress
=0;$
.each(words
,function(i
,word
){progress
+=word
.length
;if(cursorAt
<=progress
){wordAt
=i
;return false;}progress
+=seperator
;});words
[wordAt]=v
;v
=words
.join(options
.multipleSeparator
);}v
+=options
.multipleSeparator
;}$input
.val(v
);hideResultsNow();$input
.trigger("result",[selected
.data
,selected
.value
]);return true;}function onChange(crap
,skipPrevCheck
){if(lastKeyPressCode
==KEY
.DEL
){select
.hide();return;}var currentValue
=$input
.val();if(!skipPrevCheck
&¤tValue
==previousValue
)return;previousValue
=currentValue
;currentValue
=lastWord(currentValue
);if(currentValue
.length
>=options
.minChars
){$input
.addClass(options
.loadingClass
);if(!options
.matchCase
)currentValue
=currentValue
.toLowerCase();request(currentValue
,receiveData
,hideResultsNow
);}else{stopLoading();select
.hide();}};function trimWords(value
){if(!value
)return[""];if(!options
.multiple
)return[$
.trim(value
)];return $
.map(value
.split(options
.multipleSeparator
),function(word
){return $
.trim(value
).length?$
.trim(word
):null;});}function lastWord(value
){if(!options
.multiple
)return value
;var words
=trimWords(value
);if(words
.length
==1)return words
[0];var cursorAt
=$
(input
).selection().start
;if(cursorAt
==value
.length
){words
=trimWords(value
)}else{words
=trimWords(value
.replace(value
.substring(cursorAt
),""));}return words
[words
.length
-1];}function autoFill(q
,sValue
){if(options
.autoFill
&&(lastWord($input
.val()).toLowerCase()==q
.toLowerCase())&&lastKeyPressCode
!=KEY
.BACKSPACE
){$input
.val($input
.val()+sValue
.substring(lastWord(previousValue
).length
));$
(input
).selection(previousValue
.length
,previousValue
.length
+sValue
.length
);}};function hideResults(){clearTimeout(timeout
);timeout
=setTimeout(hideResultsNow
,200);};function hideResultsNow(){var wasVisible
=select
.visible();select
.hide();clearTimeout(timeout
);stopLoading();if(options
.mustMatch
){$input
.search(function(result
){if(!result
){if(options
.multiple
){var words
=trimWords($input
.val()).slice(0,-1);$input
.val(words
.join(options
.multipleSeparator
)+(words
.length?options
.multipleSeparator
:""));}else{$input
.val("");$input
.trigger("result",null);}}});}};function receiveData(q
,data
){if(data
&&data
.length
&&hasFocus
){stopLoading();select
.display(data
,q
);autoFill(q
,data
[0].value
);select
.show();}else{hideResultsNow();}};function request(term
,success
,failure
){if(!options
.matchCase
)term
=term
.toLowerCase();var data
=cache
.load(term
);if(data
&&data
.length
){success(term
,data
);}else if((typeof options
.url
=="string")&&(options
.url
.length
>0)){var extraParams
={timestamp
:+new Date()};$
.each(options
.extraParams
,function(key
,param
){extraParams
[key]=typeof param
=="function"?
param():param
;});$
.ajax({mode
:"abort",port
:"autocomplete"+input
.name
,dataType
:options
.dataType
,url
:options
.url
,data
:$
.extend({q
:lastWord(term
),limit
:options
.max
},extraParams
),success
:function(data
){var parsed
=options
.parse
&&options
.parse(data
)||
parse(data
);cache
.add(term
,parsed
);success(term
,parsed
);}});}else{select
.emptyList();failure(term
);}};function parse(data
){var parsed
=[];var rows
=data
.split("\n");for(var i
=0;i
<rows
.length
;i
++){var row
=$
.trim(rows
[i]);if(row
){row
=row
.split("|");parsed
[parsed
.length
]={data
:row
,value
:row
[0],result
:options
.formatResult
&&options
.formatResult(row
,row
[0])||row
[0]};}}return parsed
;};function stopLoading(){$input
.removeClass(options
.loadingClass
);};};$
.Autocompleter
.defaults
={inputClass
:"ac_input",resultsClass
:"ac_results",loadingClass
:"ac_loading",minChars
:1,delay
:400,matchCase
:false,matchSubset
:true,matchContains
:false,cacheLength
:10,max
:100,mustMatch
:false,extraParams
:{},selectFirst
:true,formatItem
:function(row
){return row
[0];},formatMatch
:null,autoFill
:false,width
:0,multiple
:false,multipleSeparator
:", ",highlight
:function(value
,term
){return value
.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+term
.replace(/([\^\$\
(\
)\
[\
]\
{\
}\
*\
.\
+\?\|
\\])/gi
,"\\$1")+")(?![^<>]*>)(?![^&;]+;)","gi"),"<strong>$1</strong>");},scroll
:true,scrollHeight
:180};$
.Autocompleter
.Cache
=function(options
){var data
={};var length
=0;function matchSubset(s
,sub
){if(!options
.matchCase
)s
=s
.toLowerCase();var i
=s
.indexOf(sub
);if(options
.matchContains
=="word"){i
=s
.toLowerCase().search("\\b"+sub
.toLowerCase());}if(i
==-1)return false;return i
==0||options
.matchContains
;};function add(q
,value
){if(length
>options
.cacheLength
){flush();}if(!data
[q]){length
++;}data
[q]=value
;}function populate(){if(!options
.data
)return false;var stMatchSets
={},nullData
=0;if(!options
.url
)options
.cacheLength
=1;stMatchSets
[""]=[];for(var i
=0,ol
=options
.data
.length
;i
<ol
;i
++){var rawValue
=options
.data
[i];rawValue
=(typeof rawValue
=="string")?
[rawValue]:rawValue
;var value
=options
.formatMatch(rawValue
,i
+1,options
.data
.length
);if(value
===false)continue;var firstChar
=value
.charAt(0).toLowerCase();if(!stMatchSets
[firstChar])stMatchSets
[firstChar]=[];var row
={value
:value
,data
:rawValue
,result
:options
.formatResult
&&options
.formatResult(rawValue
)||value
};stMatchSets
[firstChar].push(row
);if(nullData
++<options
.max
){stMatchSets
[""].push(row
);}};$
.each(stMatchSets
,function(i
,value
){options
.cacheLength
++;add(i
,value
);});}setTimeout(populate
,25);function flush(){data
={};length
=0;}return{flush
:flush
,add
:add
,populate
:populate
,load
:function(q
){if(!options
.cacheLength||
!length
)return null;if(!options
.url
&&options
.matchContains
){var csub
=[];for(var k
in data
){if(k
.length
>0){var c
=data
[k];$
.each(c
,function(i
,x
){if(matchSubset(x
.value
,q
)){csub
.push(x
);}});}}return csub
;}else
12 if(data
[q]){return data
[q];}else
13 if(options
.matchSubset
){for(var i
=q
.length
-1;i
>=options
.minChars
;i
--){var c
=data
[q
.substr(0,i
)];if(c
){var csub
=[];$
.each(c
,function(i
,x
){if(matchSubset(x
.value
,q
)){csub
[csub
.length
]=x
;}});return csub
;}}}return null;}};};$
.Autocompleter
.Select
=function(options
,input
,select
,config
){var CLASSES
={ACTIVE
:"ac_over"};var listItems
,active
=-1,data
,term
="",needsInit
=true,element
,list
;function init(){if(!needsInit
)return;element
=$
("<div/>").hide().addClass(options
.resultsClass
).css("position","absolute").appendTo(document
.body
);list
=$
("<ul/>").appendTo(element
).mouseover(function(event
){if(target(event
).nodeName
&&target(event
).nodeName
.toUpperCase()=='LI'){active
=$
("li",list
).removeClass(CLASSES
.ACTIVE
).index(target(event
));$
(target(event
)).addClass(CLASSES
.ACTIVE
);}}).click(function(event
){$
(target(event
)).addClass(CLASSES
.ACTIVE
);select();input
.focus();return false;}).mousedown(function(){config
.mouseDownOnSelect
=true;}).mouseup(function(){config
.mouseDownOnSelect
=false;});if(options
.width
>0)element
.css("width",options
.width
);needsInit
=false;}function target(event
){var element
=event
.target
;while(element
&&element
.tagName
!="LI")element
=element
.parentNode
;if(!element
)return[];return element
;}function moveSelect(step
){listItems
.slice(active
,active
+1).removeClass(CLASSES
.ACTIVE
);movePosition(step
);var activeItem
=listItems
.slice(active
,active
+1).addClass(CLASSES
.ACTIVE
);if(options
.scroll
){var offset
=0;listItems
.slice(0,active
).each(function(){offset
+=this.offsetHeight
;});if((offset
+activeItem
[0].offsetHeight
-list
.scrollTop())>list
[0].clientHeight
){list
.scrollTop(offset
+activeItem
[0].offsetHeight
-list
.innerHeight());}else if(offset
<list
.scrollTop()){list
.scrollTop(offset
);}}};function movePosition(step
){active
+=step
;if(active
<0){active
=listItems
.size()-1;}else if(active
>=listItems
.size()){active
=0;}}function limitNumberOfItems(available
){return options
.max
&&options
.max
<available?options
.max
:available
;}function fillList(){list
.empty();var max
=limitNumberOfItems(data
.length
);for(var i
=0;i
<max
;i
++){if(!data
[i])continue;var formatted
=options
.formatItem(data
[i].data
,i
+1,max
,data
[i].value
,term
);if(formatted
===false)continue;var li
=$
("<li/>").html(options
.highlight(formatted
,term
)).addClass(i
%2==0?
"ac_even":"ac_odd").appendTo(list
)[0];$
.data(li
,"ac_data",data
[i]);}listItems
=list
.find("li");if(options
.selectFirst
){listItems
.slice(0,1).addClass(CLASSES
.ACTIVE
);active
=0;}if($
.fn
.bgiframe
)list
.bgiframe();}return{display
:function(d
,q
){init();data
=d
;term
=q
;fillList();},next
:function(){moveSelect(1);},prev
:function(){moveSelect(-1);},pageUp
:function(){if(active
!=0&&active
-8<0){moveSelect(-active
);}else{moveSelect(-8);}},pageDown
:function(){if(active
!=listItems
.size()-1&&active
+8>listItems
.size()){moveSelect(listItems
.size()-1-active
);}else{moveSelect(8);}},hide
:function(){element
&&element
.hide();listItems
&&listItems
.removeClass(CLASSES
.ACTIVE
);active
=-1;},visible
:function(){return element
&&element
.is(":visible");},current
:function(){return this.visible()&&(listItems
.filter("."+CLASSES
.ACTIVE
)[0]||options
.selectFirst
&&listItems
[0]);},show
:function(){var offset
=$
(input
).offset();element
.css({width
:typeof options
.width
=="string"||options
.width
>0?options
.width
:$
(input
).width(),top
:offset
.top
+input
.offsetHeight
,left
:offset
.left
}).show();if(options
.scroll
){list
.scrollTop(0);list
.css({maxHeight
:options
.scrollHeight
,overflow
:'auto'});if($
.browser
.msie
&&typeof document
.body
.style
.maxHeight
==="undefined"){var listHeight
=0;listItems
.each(function(){listHeight
+=this.offsetHeight
;});var scrollbarsVisible
=listHeight
>options
.scrollHeight
;list
.css('height',scrollbarsVisible?options
.scrollHeight
:listHeight
);if(!scrollbarsVisible
){listItems
.width(list
.width()-parseInt(listItems
.css("padding-left"))-parseInt(listItems
.css("padding-right")));}}}},selected
:function(){var selected
=listItems
&&listItems
.filter("."+CLASSES
.ACTIVE
).removeClass(CLASSES
.ACTIVE
);return selected
&&selected
.length
&&$
.data(selected
[0],"ac_data");},emptyList
:function(){list
&&list
.empty();},unbind
:function(){element
&&element
.remove();}};};$
.fn
.selection
=function(start
,end
){if(start
!==undefined
){return this.each(function(){if(this.createTextRange
){var selRange
=this.createTextRange();if(end
===undefined||start
==end
){selRange
.move("character",start
);selRange
.select();}else{selRange
.collapse(true);selRange
.moveStart("character",start
);selRange
.moveEnd("character",end
);selRange
.select();}}else if(this.setSelectionRange
){this.setSelectionRange(start
,end
);}else if(this.selectionStart
){this.selectionStart
=start
;this.selectionEnd
=end
;}});}var field
=this[0];if(field
.createTextRange
){var range
=document
.selection
.createRange(),orig
=field
.value
,teststring
="<->",textLength
=range
.text
.length
;range
.text
=teststring
;var caretAt
=field
.value
.indexOf(teststring
);field
.value
=orig
;this.selection(caretAt
,caretAt
+textLength
);return{start
:caretAt
,end
:caretAt
+textLength
}}else if(field
.selectionStart
!==undefined
){return{start
:field
.selectionStart
,end
:field
.selectionEnd
}}};})(jQuery
);