text: /*! Copyright (c) 2014 Hidenari Nozaki and contributors | Licensed under the MIT license */
  "use strict";angular.module("angucomplete-alt",[]).directive("angucompleteAlt",["$parse","$http","$sce","$timeout",function($parse,$http,$sce,$timeout){var KEY_DW=40,KEY_UP=38,KEY_ES=27,KEY_EN=13,KEY_BS=8,KEY_DEL=46,KEY_TAB=9,MIN_LENGTH=3,PAUSE=500,BLUR_TIMEOUT=200,REQUIRED_CLASS="autocomplete-required",TEXT_SEARCHING="Searching...",TEXT_NORESULTS="No results found";return{restrict:"EA",require:"^?form",scope:{selectedObject:"=",initialValue:"@",localData:"=",remoteUrlRequestFormatter:"=",remoteUrlResponseFormatter:"=",id:"@",placeholder:"@",remoteUrl:"@",remoteUrlDataField:"@",titleField:"@",descriptionField:"@",imageField:"@",inputClass:"@",pause:"@",searchFields:"@",minlength:"@",matchClass:"@",clearSelected:"@",overrideSuggestions:"@",fieldRequired:"@",fieldRequiredClass:"@"},template:'<div class="angucomplete-holder">  <input id="{{id}}_value" ng-model="searchStr" type="text" placeholder="{{placeholder}}" class="{{inputClass}}" ng-focus="resetHideResults()" ng-blur="hideResults()" autocapitalize="off" autocorrect="off" autocomplete="off"/>  <div id="{{id}}_dropdown" class="angucomplete-dropdown" ng-if="showDropdown">    <div class="angucomplete-searching" ng-show="searching" ng-bind="textSearching"></div>    <div class="angucomplete-searching" ng-show="!searching && (!results || results.length == 0)" ng-bind="textNoResults"></div>    <div class="angucomplete-row" ng-repeat="result in results" ng-click="selectResult(result)" ng-mouseover="hoverRow($index)" ng-class="{\'angucomplete-selected-row\': $index == currentIndex}">      <div ng-if="imageField" class="angucomplete-image-holder">        <img ng-if="result.image && result.image != \'\'" ng-src="{{result.image}}" class="angucomplete-image"/>        <div ng-if="!result.image && result.image != \'\'" class="angucomplete-image-default"></div>      </div>      <div class="angucomplete-title" ng-if="matchClass" ng-bind-html="result.title"></div>      <div class="angucomplete-title" ng-if="!matchClass">{{ result.title }}</div>      <div ng-if="matchClass && result.description && result.description != \'\'" class="angucomplete-description" ng-bind-html="result.description"></div>      <div ng-if="!matchClass && result.description && result.description != \'\'" class="angucomplete-description">{{result.description}}</div>    </div>  </div></div>',link:function(scope,elem,attrs,ctrl){function ie8EventNormalizer(event){return event.which?event.which:event.keyCode}function callOrAssign(value){"function"==typeof scope.selectedObject?scope.selectedObject(value):scope.selectedObject=value,handleRequired(!0)}function returnFunctionOrIdentity(fn){return fn&&"function"==typeof fn?fn:function(data){return data}}function setInputString(str){callOrAssign({originalObject:str}),scope.clearSelected&&(scope.searchStr=null),scope.showDropdown=!1,scope.results=[]}function isNewSearchNeeded(newTerm,oldTerm){return newTerm.length>=minlength&&newTerm!==oldTerm}function extractTitle(data){return scope.titleField.split(",").map(function(field){return extractValue(data,field)}).join(" ")}function extractValue(obj,key){var keys,result;return key?(keys=key.split("."),result=obj,keys.forEach(function(k){result=result[k]})):result=obj,result}function findMatchString(target,str){var result,matches,re=new RegExp(str,"i");if(target)return matches=target.match(re),result=matches?target.replace(re,'<span class="'+scope.matchClass+'">'+matches[0]+"</span>"):target,$sce.trustAsHtml(result)}function handleRequired(valid){validState=scope.searchStr,scope.fieldRequired&&ctrl&&ctrl.$setValidity(requiredClassName,valid)}function keyupHandler(event){var which=ie8EventNormalizer(event);which===KEY_UP||which===KEY_DW||which===KEY_EN?event.preventDefault():(scope.searchStr&&""!==scope.searchStr?isNewSearchNeeded(scope.searchStr,lastSearchTerm)&&(lastSearchTerm=scope.searchStr,scope.showDropdown=!0,scope.currentIndex=-1,scope.results=[],searchTimer&&$timeout.cancel(searchTimer),scope.searching=!0,searchTimer=$timeout(function(){scope.searchTimerComplete(scope.searchStr)},scope.pause)):(scope.showDropdown=!1,lastSearchTerm=null),validState&&validState!==scope.searchStr&&handleRequired(!1))}function specialKeyHandler(event){var which=ie8EventNormalizer(event);which===KEY_ES?(scope.results=[],scope.showDropdown=!1,scope.$apply()):(which===KEY_BS||which===KEY_DEL)&&scope.$apply()}function keydownHandler(event){var which=ie8EventNormalizer(event);which===KEY_EN&&scope.results?(event.preventDefault(),scope.currentIndex>=0&&scope.currentIndex<scope.results.length?(scope.selectResult(scope.results[scope.currentIndex]),scope.$apply()):scope.overrideSuggestions?(setInputString(scope.searchStr),scope.$apply()):(scope.results=[],scope.$apply())):which===KEY_DW&&scope.results?scope.currentIndex+1<scope.results.length&&scope.$apply(function(){scope.currentIndex++}):which===KEY_UP&&scope.results?scope.currentIndex>=1&&scope.$apply(function(){scope.currentIndex--}):which===KEY_TAB&&scope.results&&scope.results.length>0&&-1===scope.currentIndex&&(scope.selectResult(scope.results[0]),scope.$apply())}function httpSuccessCallbackGen(str){return function(responseData){scope.searching=!1,scope.processResults(extractValue(responseFormatter(responseData),scope.remoteUrlDataField),str)}}function httpErrorCallback(){console.error("http error")}function getRemoteResults(str){var params={},url=scope.remoteUrl+str;scope.remoteUrlRequestFormatter&&(params={params:scope.remoteUrlRequestFormatter(str)},url=scope.remoteUrl),$http.get(url,params).success(httpSuccessCallbackGen(str)).error(httpErrorCallback)}function getLocalResults(str){var i,match,s,searchFields=scope.searchFields.split(","),matches=[];for(i=0;i<scope.localData.length;i++){for(match=!1,s=0;s<searchFields.length;s++)match=match||scope.localData[i][searchFields[s]].toLowerCase().indexOf(str.toLowerCase())>=0;match&&(matches[matches.length]=scope.localData[i])}scope.searching=!1,scope.processResults(matches,str)}var hideTimer,responseFormatter,inputField=elem.find("input"),minlength=MIN_LENGTH,searchTimer=null,lastSearchTerm=null,requiredClassName=REQUIRED_CLASS,validState=null;scope.currentIndex=null,scope.searching=!1,scope.searchStr=scope.initialValue,scope.hideResults=function(){hideTimer=$timeout(function(){scope.showDropdown=!1},BLUR_TIMEOUT)},scope.resetHideResults=function(){hideTimer&&$timeout.cancel(hideTimer)},scope.processResults=function(responseData,str){var i,description,image,text;if(responseData&&responseData.length>0)for(scope.results=[],i=0;i<responseData.length;i++)scope.titleField&&""!==scope.titleField&&(text=extractTitle(responseData[i])),description="",scope.descriptionField&&(description=extractValue(responseData[i],scope.descriptionField)),image="",scope.imageField&&(image=extractValue(responseData[i],scope.imageField)),scope.matchClass&&(text=findMatchString(text,str),description=findMatchString(description,str)),scope.results[scope.results.length]={title:text,description:description,image:image,originalObject:responseData[i]};else scope.results=[]},scope.searchTimerComplete=function(str){str.length<minlength||(scope.localData?getLocalResults(str):getRemoteResults(str))},scope.hoverRow=function(index){scope.currentIndex=index},scope.selectResult=function(result){scope.matchClass&&(result.title=extractTitle(result.originalObject),result.description=extractValue(result.originalObject,scope.descriptionField)),scope.searchStr=scope.clearSelected?null:lastSearchTerm=result.title,callOrAssign(result),scope.showDropdown=!1,scope.results=[]},scope.fieldRequiredClass&&""!==scope.fieldRequiredClass&&(requiredClassName=scope.fieldRequiredClass),scope.minlength&&""!==scope.minlength&&(minlength=scope.minlength),scope.pause||(scope.pause=PAUSE),scope.clearSelected||(scope.clearSelected=!1),scope.overrideSuggestions||(scope.overrideSuggestions=!1),scope.fieldRequired&&ctrl&&handleRequired(scope.initialValue?!0:!1),scope.textSearching=attrs.textSearching?attrs.textSearching:TEXT_SEARCHING,scope.textNoResults=attrs.textNoResults?attrs.textNoResults:TEXT_NORESULTS,inputField.on("keydown",keydownHandler),inputField.on("keyup",specialKeyHandler),inputField.on("keyup",keyupHandler),responseFormatter=returnFunctionOrIdentity(scope.remoteUrlResponseFormatter)}}}]);