/**
 * @fileOverview Better Autocomplete is a flexible jQuery plugin which offers
 * rich text autocompletion, both from local and remote sources.
 *
 * @author Didrik Nordström, http://betamos.se/
 * @version v1.0-dev
 *
 * @requires jQuery 1.4+  &  IE7+ or any decent webkit/gecko-based web browser
 *
 * @preserve Better Autocomplete v1.0-dev
 * https://github.com/betamos/Better-Autocomplete
 *
 * Copyright 2011, Didrik Nordström, http://betamos.se/
 * Dual licensed under the MIT or GPL Version 2 licenses.
 */
(function($){$.fn.betterAutocomplete=function(method){var methods={init:function(resource,options,callbacks){var $input=$(this),bac=new BetterAutocomplete($input,resource,options,callbacks);$input.data('better-autocomplete',bac);bac.enable()},enable:function(bac){bac.enable()},disable:function(bac){bac.disable()},destroy:function(bac){bac.destroy()}},args=Array.prototype.slice.call(arguments,1);this.each(function(){switch(method){case'init':methods[method].apply(this,args);break;case'enable':case'disable':case'destroy':var bac=$(this).data('better-autocomplete');if(bac instanceof BetterAutocomplete){methods[method].call(this,bac)}break;default:$.error(['Method',method,'does not exist in jQuery.betterAutocomplete.'].join(' '))}});return this};var BetterAutocomplete=function($input,resource,options,callbacks){var lastRenderedQuery='',cache={},cacheOrder=[],cacheSize=0,timer,activeRemoteCalls=[],disableMouseHighlight=false,inputEvents={},isLocal=($.type(resource)!='string'),$results=$('<ul />').addClass('better-autocomplete');options=$.extend({charLimit:isLocal?1:3,delay:350,caseSensitive:false,cacheLimit:isLocal?0:256,remoteTimeout:10000,crossOrigin:false,selectKeys:[9,13]},options);callbacks=$.extend({},defaultCallbacks,callbacks);callbacks.insertSuggestionList($results,$input,options.maxHeight);inputEvents.focus=function(){redraw(true)};inputEvents.blur=function(){redraw()};inputEvents.keydown=function(event){var index=getHighlighted();if($.inArray(event.keyCode,[38,40])>=0&&index>=0){var newIndex,size=$('.result',$results).length;switch(event.keyCode){case 38:newIndex=Math.max(0,index-1);break;case 40:newIndex=Math.min(size-1,index+1);break}disableMouseHighlight=true;setHighlighted(newIndex,true);return false}else if($.inArray(event.keyCode,options.selectKeys)>=0&&!event.shiftKey&&!event.ctrlKey&&!event.altKey&&!event.metaKey){select();return event.keyCode==9}};inputEvents.keyup=inputEvents.click=reprocess;$('.result',$results[0]).live({mouseover:function(){if(disableMouseHighlight){return}setHighlighted($('.result',$results).index($(this)))},mousemove:function(){disableMouseHighlight=false},mousedown:function(){select();return false}});$results.mousedown(function(){return false});this.enable=function(){$input.attr('autocomplete','OFF').attr('aria-autocomplete','list');$input.bind(inputEvents)};this.disable=function(){$input.removeAttr('autocomplete').removeAttr('aria-autocomplete');$results.hide();$input.unbind(inputEvents)};this.destroy=function(){$results.remove();$input.unbind(inputEvents);$input.removeData('better-autocomplete')};var cacheResults=function(query,results){cacheSize+=results.length;while(cacheSize>options.cacheLimit&&cacheOrder.length){var key=cacheOrder.shift();cacheSize-=cache[key].length;delete cache[key]}cacheOrder.push(query);cache[query]=results};var setHighlighted=function(index,autoScroll){var up=index==0||index<getHighlighted(),$scrollTo=$('.result',$results).removeClass('highlight').eq(index).addClass('highlight');if(!autoScroll){return}if($scrollTo.prev().is('.group')&&up){$scrollTo=$scrollTo.prev()}if($scrollTo.position().top<0){$results.scrollTop($scrollTo.position().top+$results.scrollTop())}else if(($scrollTo.position().top+$scrollTo.outerHeight())>$results.height()){$results.scrollTop($scrollTo.position().top+$results.scrollTop()+$scrollTo.outerHeight()-$results.height())}};var getHighlighted=function(){return $('.result',$results).index($('.result.highlight',$results))};var select=function(){var $result=$('.result',$results).eq(getHighlighted());if(!$result.length){return}var result=$result.data('result');callbacks.select(result,$input);reprocess()};var fetchResults=function(query){if(isLocal){cacheResults(query,callbacks.queryLocalResults(query,resource,options.caseSensitive));redraw()}else{activeRemoteCalls.push(query);var url=callbacks.constructURL(resource,query);callbacks.beginFetching($input);callbacks.fetchRemoteData(url,function(data){var searchResults=callbacks.processRemoteData(data);if(!$.isArray(searchResults)){searchResults=[]}cacheResults(query,searchResults);activeRemoteCalls=$.grep(activeRemoteCalls,function(value){return value!=query});if(!activeRemoteCalls.length){callbacks.finishFetching($input)}redraw()},options.remoteTimeout,options.crossOrigin)}};function reprocess(){var query=callbacks.canonicalQuery($input.val(),options.caseSensitive);clearTimeout(timer);timer=null;redraw();if(query.length>=options.charLimit&&!$.isArray(cache[query])&&$.inArray(query,activeRemoteCalls)==-1){$results.empty();if(isLocal){fetchResults(query)}else{timer=setTimeout(function(){fetchResults(query);timer=null},options.delay)}}};var redraw=function(focus){var query=callbacks.canonicalQuery($input.val(),options.caseSensitive);if(!$.isArray(cache[query])){lastRenderedQuery=null;$results.empty()}else if(lastRenderedQuery!==query){lastRenderedQuery=query;renderResults(cache[query]);setHighlighted(0)}if(($input.is(':focus')||focus)&&!$results.is(':empty')){$results.filter(':hidden').show().scrollTop($results.data('scroll-top'))}else if($results.is(':visible')){$results.data('scroll-top',$results.scrollTop()).hide()}};var renderResults=function(results){$results.empty();var groups={};$.each(results,function(index,result){if($.type(result)!='object'){return}var output=callbacks.themeResult(result);if($.type(output)!='string'){return}var group=callbacks.getGroup(result);if($.type(group)=='string'&&!groups[group]){var $groupHeading=$('<li />').addClass('group').append($('<h3 />').html(group)).appendTo($results);groups[group]=$groupHeading}var $result=$('<li />').addClass('result').append(output).data('result',result).addClass(result.addClass);if($.type(group)!='string'&&!$results.children().first().is('.result')){$results.prepend($result);return}var $traverseFrom=($.type(group)=='string')?groups[group]:$results.children().first();var $target=$traverseFrom.nextUntil('.group').last();$result.insertAfter($target.length?$target:$traverseFrom)})}};var defaultCallbacks={select:function(result,$input){$input.val(result.title);$input.blur();},themeResult:function(result){var output=[];if($.type(result.title)=='string'){output.push('<div>',result.title,'</div>')}if($.type(result.description)=='string'){output.push('<p>',result.description,'</p>')}return output.join('')},queryLocalResults:function(query,resource,caseSensitive){if(!$.isArray(resource)){return[]}var results=[];$.each(resource,function(i,value){switch($.type(value)){case'string':if((caseSensitive?value:value.toLowerCase()).indexOf(query)>=0){results.push({title:value})}break;case'object':if($.type(value.title)=='string'&&(caseSensitive?value.title:value.title.toLowerCase()).indexOf(query)>=0){results.push(value)}else if($.type(value.description)=='string'&&(caseSensitive?value.description:value.description.toLowerCase()).indexOf(query)>=0){results.push(value)}break}});return results},fetchRemoteData:function(url,completeCallback,timeout,crossOrigin){$.ajax({url:url,dataType:crossOrigin&&!$.support.cors?'jsonp':'json',timeout:timeout,success:function(data,textStatus){completeCallback(data)},error:function(jqXHR,textStatus,errorThrown){completeCallback()}})},processRemoteData:function(data){if($.isArray(data)){return data}else{return[]}},getGroup:function(result){if($.type(result.group)=='string'){return result.group}},beginFetching:function($input){$input.addClass('fetching')},finishFetching:function($input){$input.removeClass('fetching')},constructURL:function(path,query){return path+'?q='+encodeURIComponent(query)},canonicalQuery:function(rawQuery,caseSensitive){var query=$.trim(rawQuery);if(!caseSensitive){query=query.toLowerCase()}return query},insertSuggestionList:function($results,$input){$results.width($input.outerWidth()-2).css({position:'absolute',left:$input.position().left,top:$input.position().top+$input.outerHeight(),zIndex:10,maxHeight:'330px',boxShadow:'0 0 3px rgba(0, 0, 0, 0.5)'}).insertAfter($input)}};var filters=$.expr[':'];if(!filters.focus){filters.focus=function(elem){return elem===document.activeElement&&(elem.type||elem.href)}}})(jQuery);
