diff --git a/devbridge-autocomplete.jquery.json b/devbridge-autocomplete.jquery.json
index b6344a9..62140ea 100644
--- a/devbridge-autocomplete.jquery.json
+++ b/devbridge-autocomplete.jquery.json
@@ -6,7 +6,7 @@
"ajax",
"autocomplete"
],
- "version": "2.0.1",
+ "version": "2.0.2",
"author": {
"name": "Tomas Kirda",
"url": "https://github.com/tkirda"
diff --git a/dist/jquery.autocomplete.esm.js b/dist/jquery.autocomplete.esm.js
index 0e40de0..6e9735c 100644
--- a/dist/jquery.autocomplete.esm.js
+++ b/dist/jquery.autocomplete.esm.js
@@ -1,5 +1,5 @@
/**
-* Ajax Autocomplete for jQuery, version 2.0.1
+* Ajax Autocomplete for jQuery, version 2.0.2
* (c) 2025 Tomas Kirda
*
* Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.
@@ -583,7 +583,7 @@ var _Autocomplete = class _Autocomplete {
result.suggestions = this.verifySuggestionsFormat(result.suggestions);
if (!options.noCache) {
this.cachedResponse[cacheKey] = result;
- if (options.preventBadQueries && !result.suggestions.length) {
+ if (options.preventBadQueries && !result.suggestions.length && originalQuery) {
this.badQueries.push(originalQuery);
}
}
diff --git a/dist/jquery.autocomplete.js b/dist/jquery.autocomplete.js
index 7b8f7f9..6026865 100644
--- a/dist/jquery.autocomplete.js
+++ b/dist/jquery.autocomplete.js
@@ -1,5 +1,5 @@
/**
-* Ajax Autocomplete for jQuery, version 2.0.1
+* Ajax Autocomplete for jQuery, version 2.0.2
* (c) 2025 Tomas Kirda
*
* Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.
@@ -591,7 +591,7 @@
result.suggestions = this.verifySuggestionsFormat(result.suggestions);
if (!options.noCache) {
this.cachedResponse[cacheKey] = result;
- if (options.preventBadQueries && !result.suggestions.length) {
+ if (options.preventBadQueries && !result.suggestions.length && originalQuery) {
this.badQueries.push(originalQuery);
}
}
diff --git a/dist/jquery.autocomplete.min.js b/dist/jquery.autocomplete.min.js
index c500c8c..07ac2ed 100644
--- a/dist/jquery.autocomplete.min.js
+++ b/dist/jquery.autocomplete.min.js
@@ -1,5 +1,5 @@
/**
-* Ajax Autocomplete for jQuery, version 2.0.1
+* Ajax Autocomplete for jQuery, version 2.0.2
* (c) 2025 Tomas Kirda
*
* Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.
@@ -15,6 +15,6 @@
factory(jQuery);
}
})(function ($) {
-"use strict";(()=>{var c=null;function C(r){c=r}var v={escapeRegExChars(r){return r.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&")},createNode(r){let t=document.createElement("div");return t.className=r,t.style.position="absolute",t.style.display="none",t}},h={ESC:27,TAB:9,RETURN:13,LEFT:37,UP:38,RIGHT:39,DOWN:40};function x(r,t,e){return r.value.toLowerCase().indexOf(e)!==-1}function T(r){return typeof r=="string"?JSON.parse(r):r}function w(r,t){if(!t){let s=document.createElement("span");return s.textContent=r.value,s.innerHTML}let e="("+v.escapeRegExChars(t)+")";return r.value.replace(new RegExp(e,"gi"),"$1").replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/<(\/?strong)>/g,"<$1>")}function R(r,t){let e=document.createElement("div");return e.className="autocomplete-group",e.textContent=t,e.outerHTML}var S=()=>{},A={ajaxSettings:{},autoSelectFirst:!1,appendTo:"body",width:"auto",minChars:1,maxHeight:300,deferRequestBy:0,params:{},formatResult:w,formatGroup:R,zIndex:9999,type:"GET",noCache:!1,onSearchStart:S,onSearchComplete:S,onSearchError:S,preserveInput:!1,containerClass:"autocomplete-suggestions",tabDisabled:!1,dataType:"text",triggerSelectOnValidInput:!0,preventBadQueries:!0,lookupFilter:x,paramName:"query",transformResult:T,showNoSuggestionNotice:!1,noSuggestionNotice:"No results",orientation:"bottom",forceFixPosition:!1};var p=class p{constructor(t,e){this.suggestions=[];this.badQueries=[];this.selectedIndex=-1;this.cachedResponse={};this.onChangeTimeout=null;this.isLocal=!1;this.classes={selected:"autocomplete-selected",suggestion:"autocomplete-suggestion"};this.hint=null;this.hintValue="";this.selection=null;this.currentRequest=null;this.element=t,this.el=c(t),this.currentValue=t.value,this.options=c.extend(!0,{},p.defaults,e),this.initialize(),this.setOptions(e)}initialize(){let t=this,e=`.${this.classes.suggestion}`,s=this.classes.selected,i=this.options;this.element.setAttribute("autocomplete","off"),this.$noSuggestionsContainer=c('
').html(i.noSuggestionNotice),this.noSuggestionsContainer=this.$noSuggestionsContainer.get(0),this.suggestionsContainer=p.utils.createNode(i.containerClass),this.$container=c(this.suggestionsContainer),this.$container.appendTo(i.appendTo||"body"),i.width!=="auto"&&this.$container.css("width",i.width);let o=this.$container;o.on("mouseover.autocomplete",e,function(){t.activate(c(this).data("index"))}),o.on("click.autocomplete",e,function(){t.select(c(this).data("index"))}),o.on("mouseout.autocomplete",()=>{this.selectedIndex=-1,o.children(`.${s}`).removeClass(s)}),o.on("click.autocomplete",()=>{this.blurTimeoutId!==void 0&&clearTimeout(this.blurTimeoutId)}),this.fixPositionCapture=()=>{this.visible&&this.fixPosition()},c(window).on("resize.autocomplete",this.fixPositionCapture),this.el.on("keydown.autocomplete",n=>this.onKeyPress(n)),this.el.on("keyup.autocomplete",n=>this.onKeyUp(n)),this.el.on("blur.autocomplete",()=>this.onBlur()),this.el.on("focus.autocomplete",()=>this.onFocus()),this.el.on("change.autocomplete",n=>this.onKeyUp(n)),this.el.on("input.autocomplete",n=>this.onKeyUp(n))}onFocus(){this.disabled||(this.fixPosition(),this.el.val().length>=this.options.minChars&&this.onValueChange())}onBlur(){let t=this.options,e=this.getQuery(this.el.val());this.blurTimeoutId=setTimeout(()=>{this.hide(),this.selection&&this.currentValue!==e&&t.onInvalidateSelection?.call(this.element)},200)}abortAjax(){this.currentRequest&&(this.currentRequest.abort(),this.currentRequest=null)}setOptions(t){let e={...this.options,...t};this.isLocal=Array.isArray(e.lookup),this.isLocal&&(e.lookup=this.verifySuggestionsFormat(e.lookup)),e.orientation=this.validateOrientation(e.orientation,"bottom"),this.$container.css({"max-height":`${e.maxHeight}px`,width:`${e.width}px`,"z-index":e.zIndex}),this.options=e}clearCache(){this.cachedResponse={},this.badQueries=[]}clear(){this.clearCache(),this.currentValue="",this.suggestions=[]}disable(){this.disabled=!0,this.onChangeTimeout&&clearTimeout(this.onChangeTimeout),this.abortAjax()}enable(){this.disabled=!1}fixPosition(){let t=this.$container,e=t.parent().get(0);if(e!==document.body&&!this.options.forceFixPosition)return;let s=this.options.orientation,i=t.outerHeight()??0,o=this.el.outerHeight()??0,n=this.el.offset()??{top:0,left:0},a={top:n.top,left:n.left};if(s==="auto"){let l=c(window).height()??0,u=c(window).scrollTop()??0,g=-u+n.top-i,y=u+l-(n.top+o+i);s=Math.max(g,y)===g?"top":"bottom"}if(a.top+=s==="top"?-i:o,e!==document.body&&e!==void 0){let l=t.css("opacity");this.visible||t.css("opacity",0).show();let u=t.offsetParent().offset()??{top:0,left:0};a.top-=u.top,a.top+=e.scrollTop,a.left-=u.left,this.visible||t.css("opacity",l).hide()}this.options.width==="auto"&&(a.width=`${this.el.outerWidth()??0}px`),t.css(a)}isCursorAtEnd(){let t=this.el.val().length,{selectionStart:e}=this.element;return typeof e=="number"?e===t:!0}onKeyPress(t){if(!this.disabled&&!this.visible&&t.which===h.DOWN&&this.currentValue){this.suggest();return}if(!(this.disabled||!this.visible)){switch(t.which){case h.ESC:this.el.val(this.currentValue),this.hide();break;case h.RIGHT:if(this.hint&&this.options.onHint&&this.isCursorAtEnd()){this.selectHint();break}return;case h.TAB:if(this.hint&&this.options.onHint){this.selectHint();return}if(this.selectedIndex===-1){this.hide();return}if(this.select(this.selectedIndex),this.options.tabDisabled===!1)return;break;case h.RETURN:if(this.selectedIndex===-1){this.hide();return}this.select(this.selectedIndex);break;case h.UP:this.moveUp();break;case h.DOWN:this.moveDown();break;default:return}t.stopImmediatePropagation(),t.preventDefault()}}onKeyUp(t){this.disabled||t.which===h.UP||t.which===h.DOWN||(this.onChangeTimeout&&clearTimeout(this.onChangeTimeout),this.currentValue!==this.el.val()&&(this.findBestHint(),this.options.deferRequestBy>0?this.onChangeTimeout=setTimeout(()=>this.onValueChange(),this.options.deferRequestBy):this.onValueChange()))}onValueChange(){if(this.ignoreValueChange){this.ignoreValueChange=!1;return}let t=this.options,e=this.el.val(),s=this.getQuery(e);if(this.selection&&this.currentValue!==s&&(this.selection=null,t.onInvalidateSelection?.call(this.element)),this.onChangeTimeout&&clearTimeout(this.onChangeTimeout),this.currentValue=e,this.selectedIndex=-1,t.triggerSelectOnValidInput&&this.isExactMatch(s)){this.select(0);return}s.lengthi(l,t,s));return{suggestions:o&&a.length>o?a.slice(0,o):a}}getSuggestions(t){let e=this.options,s=e.serviceUrl,i,o;if(e.params[e.paramName]=t,e.onSearchStart.call(this.element,e.params)===!1)return;let n=e.ignoreParams?null:e.params;if(typeof e.lookup=="function"){e.lookup(t,a=>{let l=this.verifySuggestionsFormat(a.suggestions);this.suggestions=l,e.onSearchComplete.call(this.element,t,l),this.suggest()});return}if(this.isLocal?i=this.getSuggestionsLocal(t):(typeof s=="function"&&(s=s.call(this.element,t)),o=`${s}?${c.param(n??{})}`,i=this.cachedResponse[o]),i&&Array.isArray(i.suggestions))this.suggestions=i.suggestions,e.onSearchComplete.call(this.element,t,i.suggestions),this.suggest();else if(this.isBadQuery(t))e.onSearchComplete.call(this.element,t,[]);else{this.abortAjax();let a={url:s,data:n??void 0,type:e.type,dataType:e.dataType,...e.ajaxSettings};this.currentRequest=c.ajax(a).done(l=>{this.currentRequest=null;let u=e.transformResult(l,t);u.suggestions=this.verifySuggestionsFormat(u.suggestions),e.onSearchComplete.call(this.element,t,u.suggestions),this.processResponse(u,t,o)}).fail((l,u,g)=>{e.onSearchError.call(this.element,t,l,u,g)})}}isBadQuery(t){return this.options.preventBadQueries?this.badQueries.some(e=>t.indexOf(e)===0):!1}hide(){this.options.onHide&&this.visible&&this.options.onHide.call(this.element,this.$container),this.visible=!1,this.selectedIndex=-1,this.onChangeTimeout&&clearTimeout(this.onChangeTimeout),this.$container.hide(),this.onHint(null)}groupSuggestionsByCategory(t,e){let s=new Map;for(let i of t){let o=i.data[e],n=s.get(o);n?n.push(i):s.set(o,[i])}return Array.from(s.values()).flat()}suggest(){if(!this.suggestions.length){this.options.showNoSuggestionNotice?this.noSuggestions():this.hide();return}let t=this.options,{groupBy:e,formatResult:s,beforeRender:i}=t,o=this.getQuery(this.currentValue),n=this.classes.suggestion,a=this.classes.selected,l=this.$container;if(t.triggerSelectOnValidInput&&this.isExactMatch(o)){this.select(0);return}e&&(this.suggestions=this.groupSuggestionsByCategory(this.suggestions,e));let u,g=d=>{let f=d.data[e];return u===f?"":(u=f,t.formatGroup(d,u))},y=this.suggestions.map((d,f)=>`${e?g(d):""}${s(d,o,f)}
`).join("");this.adjustContainerWidth(),this.$noSuggestionsContainer.detach(),l.html(y),i?.call(this.element,l,this.suggestions),this.fixPosition(),l.show(),t.autoSelectFirst&&(this.selectedIndex=0,l.scrollTop(0),l.children(`.${n}`).first().addClass(a)),this.visible=!0,this.findBestHint()}noSuggestions(){let{beforeRender:t}=this.options,e=this.$container;this.adjustContainerWidth(),this.$noSuggestionsContainer.detach(),e.empty().append(this.$noSuggestionsContainer),t?.call(this.element,e,this.suggestions),this.fixPosition(),e.show(),this.visible=!0}adjustContainerWidth(){let{width:t}=this.options;if(t==="auto"){let e=this.el.outerWidth()??0;this.$container.css("width",e>0?e:300)}else t==="flex"&&this.$container.css("width","")}findBestHint(){let t=this.el.val().toLowerCase();if(!t)return;let e=this.suggestions.find(s=>s.value.toLowerCase().indexOf(t)===0)??null;this.onHint(e)}onHint(t){let{onHint:e}=this.options,s=t?this.currentValue+t.value.substr(this.currentValue.length):"";this.hintValue!==s&&(this.hintValue=s,this.hint=t,e?.call(this.element,s))}verifySuggestionsFormat(t){return t.length&&typeof t[0]=="string"?t.map(e=>({value:e,data:null})):t.map(e=>typeof e.value=="string"?e:{...e,value:String(e.value)})}validateOrientation(t,e){let s=(t||"").trim().toLowerCase();return s==="auto"||s==="top"||s==="bottom"?s:e}processResponse(t,e,s){let i=this.options;t.suggestions=this.verifySuggestionsFormat(t.suggestions),i.noCache||(this.cachedResponse[s]=t,i.preventBadQueries&&!t.suggestions.length&&this.badQueries.push(e)),e===this.getQuery(this.currentValue)&&(this.suggestions=t.suggestions,this.suggest())}activate(t){let e=this.classes.selected,s=this.$container,i=s.find(`.${this.classes.suggestion}`);if(s.find(`.${e}`).removeClass(e),this.selectedIndex=t,this.selectedIndex!==-1&&i.length>this.selectedIndex){let o=i.get(this.selectedIndex);return c(o).addClass(e),o}return null}selectHint(){this.select(this.suggestions.indexOf(this.hint))}select(t){this.hide(),this.onSelect(t)}moveUp(){if(this.selectedIndex!==-1){if(this.selectedIndex===0){this.$container.children(`.${this.classes.suggestion}`).first().removeClass(this.classes.selected),this.selectedIndex=-1,this.ignoreValueChange=!1,this.el.val(this.currentValue),this.findBestHint();return}this.adjustScroll(this.selectedIndex-1)}}moveDown(){this.selectedIndex!==this.suggestions.length-1&&this.adjustScroll(this.selectedIndex+1)}adjustScroll(t){let e=this.activate(t);if(!e)return;let s=c(e).outerHeight()??0,i=e.offsetTop,o=this.$container,n=o.scrollTop()??0,a=n+this.options.maxHeight-s;ia&&o.scrollTop(i-this.options.maxHeight+s),this.options.preserveInput||(this.ignoreValueChange=!0,this.el.val(this.getValue(this.suggestions[t].value))),this.onHint(null)}onSelect(t){let e=this.options.onSelect,s=this.suggestions[t];this.currentValue=this.getValue(s.value),this.currentValue!==this.el.val()&&!this.options.preserveInput&&this.el.val(this.currentValue),this.onHint(null),this.suggestions=[],this.selection=s,e?.call(this.element,s)}getValue(t){let{delimiter:e}=this.options;if(!e)return t;let s=this.currentValue,i=s.split(e);return i.length===1?t:s.substr(0,s.length-i[i.length-1].length)+t}dispose(){this.el.off(".autocomplete").removeData("autocomplete"),this.fixPositionCapture&&c(window).off("resize.autocomplete",this.fixPositionCapture),this.$container.remove()}};p.defaults=A,p.utils=v;var m=p;var b="autocomplete";function H(r){C(r),r.Autocomplete=m,r.fn.devbridgeAutocomplete=function(t,e){return arguments.length?this.each(function(){let s=r(this),i=s.data(b);typeof t=="string"?i&&typeof i[t]=="function"&&i[t](e):(i&&i.dispose&&i.dispose(),i=new m(this,t),s.data(b,i))}):this.first().data(b)},r.fn.autocomplete||(r.fn.autocomplete=r.fn.devbridgeAutocomplete)}H($);})();
+"use strict";(()=>{var c=null;function C(r){c=r}var v={escapeRegExChars(r){return r.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&")},createNode(r){let t=document.createElement("div");return t.className=r,t.style.position="absolute",t.style.display="none",t}},h={ESC:27,TAB:9,RETURN:13,LEFT:37,UP:38,RIGHT:39,DOWN:40};function x(r,t,e){return r.value.toLowerCase().indexOf(e)!==-1}function T(r){return typeof r=="string"?JSON.parse(r):r}function w(r,t){if(!t){let s=document.createElement("span");return s.textContent=r.value,s.innerHTML}let e="("+v.escapeRegExChars(t)+")";return r.value.replace(new RegExp(e,"gi"),"$1").replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/<(\/?strong)>/g,"<$1>")}function R(r,t){let e=document.createElement("div");return e.className="autocomplete-group",e.textContent=t,e.outerHTML}var S=()=>{},A={ajaxSettings:{},autoSelectFirst:!1,appendTo:"body",width:"auto",minChars:1,maxHeight:300,deferRequestBy:0,params:{},formatResult:w,formatGroup:R,zIndex:9999,type:"GET",noCache:!1,onSearchStart:S,onSearchComplete:S,onSearchError:S,preserveInput:!1,containerClass:"autocomplete-suggestions",tabDisabled:!1,dataType:"text",triggerSelectOnValidInput:!0,preventBadQueries:!0,lookupFilter:x,paramName:"query",transformResult:T,showNoSuggestionNotice:!1,noSuggestionNotice:"No results",orientation:"bottom",forceFixPosition:!1};var p=class p{constructor(t,e){this.suggestions=[];this.badQueries=[];this.selectedIndex=-1;this.cachedResponse={};this.onChangeTimeout=null;this.isLocal=!1;this.classes={selected:"autocomplete-selected",suggestion:"autocomplete-suggestion"};this.hint=null;this.hintValue="";this.selection=null;this.currentRequest=null;this.element=t,this.el=c(t),this.currentValue=t.value,this.options=c.extend(!0,{},p.defaults,e),this.initialize(),this.setOptions(e)}initialize(){let t=this,e=`.${this.classes.suggestion}`,s=this.classes.selected,i=this.options;this.element.setAttribute("autocomplete","off"),this.$noSuggestionsContainer=c('').html(i.noSuggestionNotice),this.noSuggestionsContainer=this.$noSuggestionsContainer.get(0),this.suggestionsContainer=p.utils.createNode(i.containerClass),this.$container=c(this.suggestionsContainer),this.$container.appendTo(i.appendTo||"body"),i.width!=="auto"&&this.$container.css("width",i.width);let o=this.$container;o.on("mouseover.autocomplete",e,function(){t.activate(c(this).data("index"))}),o.on("click.autocomplete",e,function(){t.select(c(this).data("index"))}),o.on("mouseout.autocomplete",()=>{this.selectedIndex=-1,o.children(`.${s}`).removeClass(s)}),o.on("click.autocomplete",()=>{this.blurTimeoutId!==void 0&&clearTimeout(this.blurTimeoutId)}),this.fixPositionCapture=()=>{this.visible&&this.fixPosition()},c(window).on("resize.autocomplete",this.fixPositionCapture),this.el.on("keydown.autocomplete",n=>this.onKeyPress(n)),this.el.on("keyup.autocomplete",n=>this.onKeyUp(n)),this.el.on("blur.autocomplete",()=>this.onBlur()),this.el.on("focus.autocomplete",()=>this.onFocus()),this.el.on("change.autocomplete",n=>this.onKeyUp(n)),this.el.on("input.autocomplete",n=>this.onKeyUp(n))}onFocus(){this.disabled||(this.fixPosition(),this.el.val().length>=this.options.minChars&&this.onValueChange())}onBlur(){let t=this.options,e=this.getQuery(this.el.val());this.blurTimeoutId=setTimeout(()=>{this.hide(),this.selection&&this.currentValue!==e&&t.onInvalidateSelection?.call(this.element)},200)}abortAjax(){this.currentRequest&&(this.currentRequest.abort(),this.currentRequest=null)}setOptions(t){let e={...this.options,...t};this.isLocal=Array.isArray(e.lookup),this.isLocal&&(e.lookup=this.verifySuggestionsFormat(e.lookup)),e.orientation=this.validateOrientation(e.orientation,"bottom"),this.$container.css({"max-height":`${e.maxHeight}px`,width:`${e.width}px`,"z-index":e.zIndex}),this.options=e}clearCache(){this.cachedResponse={},this.badQueries=[]}clear(){this.clearCache(),this.currentValue="",this.suggestions=[]}disable(){this.disabled=!0,this.onChangeTimeout&&clearTimeout(this.onChangeTimeout),this.abortAjax()}enable(){this.disabled=!1}fixPosition(){let t=this.$container,e=t.parent().get(0);if(e!==document.body&&!this.options.forceFixPosition)return;let s=this.options.orientation,i=t.outerHeight()??0,o=this.el.outerHeight()??0,n=this.el.offset()??{top:0,left:0},a={top:n.top,left:n.left};if(s==="auto"){let l=c(window).height()??0,u=c(window).scrollTop()??0,g=-u+n.top-i,y=u+l-(n.top+o+i);s=Math.max(g,y)===g?"top":"bottom"}if(a.top+=s==="top"?-i:o,e!==document.body&&e!==void 0){let l=t.css("opacity");this.visible||t.css("opacity",0).show();let u=t.offsetParent().offset()??{top:0,left:0};a.top-=u.top,a.top+=e.scrollTop,a.left-=u.left,this.visible||t.css("opacity",l).hide()}this.options.width==="auto"&&(a.width=`${this.el.outerWidth()??0}px`),t.css(a)}isCursorAtEnd(){let t=this.el.val().length,{selectionStart:e}=this.element;return typeof e=="number"?e===t:!0}onKeyPress(t){if(!this.disabled&&!this.visible&&t.which===h.DOWN&&this.currentValue){this.suggest();return}if(!(this.disabled||!this.visible)){switch(t.which){case h.ESC:this.el.val(this.currentValue),this.hide();break;case h.RIGHT:if(this.hint&&this.options.onHint&&this.isCursorAtEnd()){this.selectHint();break}return;case h.TAB:if(this.hint&&this.options.onHint){this.selectHint();return}if(this.selectedIndex===-1){this.hide();return}if(this.select(this.selectedIndex),this.options.tabDisabled===!1)return;break;case h.RETURN:if(this.selectedIndex===-1){this.hide();return}this.select(this.selectedIndex);break;case h.UP:this.moveUp();break;case h.DOWN:this.moveDown();break;default:return}t.stopImmediatePropagation(),t.preventDefault()}}onKeyUp(t){this.disabled||t.which===h.UP||t.which===h.DOWN||(this.onChangeTimeout&&clearTimeout(this.onChangeTimeout),this.currentValue!==this.el.val()&&(this.findBestHint(),this.options.deferRequestBy>0?this.onChangeTimeout=setTimeout(()=>this.onValueChange(),this.options.deferRequestBy):this.onValueChange()))}onValueChange(){if(this.ignoreValueChange){this.ignoreValueChange=!1;return}let t=this.options,e=this.el.val(),s=this.getQuery(e);if(this.selection&&this.currentValue!==s&&(this.selection=null,t.onInvalidateSelection?.call(this.element)),this.onChangeTimeout&&clearTimeout(this.onChangeTimeout),this.currentValue=e,this.selectedIndex=-1,t.triggerSelectOnValidInput&&this.isExactMatch(s)){this.select(0);return}s.lengthi(l,t,s));return{suggestions:o&&a.length>o?a.slice(0,o):a}}getSuggestions(t){let e=this.options,s=e.serviceUrl,i,o;if(e.params[e.paramName]=t,e.onSearchStart.call(this.element,e.params)===!1)return;let n=e.ignoreParams?null:e.params;if(typeof e.lookup=="function"){e.lookup(t,a=>{let l=this.verifySuggestionsFormat(a.suggestions);this.suggestions=l,e.onSearchComplete.call(this.element,t,l),this.suggest()});return}if(this.isLocal?i=this.getSuggestionsLocal(t):(typeof s=="function"&&(s=s.call(this.element,t)),o=`${s}?${c.param(n??{})}`,i=this.cachedResponse[o]),i&&Array.isArray(i.suggestions))this.suggestions=i.suggestions,e.onSearchComplete.call(this.element,t,i.suggestions),this.suggest();else if(this.isBadQuery(t))e.onSearchComplete.call(this.element,t,[]);else{this.abortAjax();let a={url:s,data:n??void 0,type:e.type,dataType:e.dataType,...e.ajaxSettings};this.currentRequest=c.ajax(a).done(l=>{this.currentRequest=null;let u=e.transformResult(l,t);u.suggestions=this.verifySuggestionsFormat(u.suggestions),e.onSearchComplete.call(this.element,t,u.suggestions),this.processResponse(u,t,o)}).fail((l,u,g)=>{e.onSearchError.call(this.element,t,l,u,g)})}}isBadQuery(t){return this.options.preventBadQueries?this.badQueries.some(e=>t.indexOf(e)===0):!1}hide(){this.options.onHide&&this.visible&&this.options.onHide.call(this.element,this.$container),this.visible=!1,this.selectedIndex=-1,this.onChangeTimeout&&clearTimeout(this.onChangeTimeout),this.$container.hide(),this.onHint(null)}groupSuggestionsByCategory(t,e){let s=new Map;for(let i of t){let o=i.data[e],n=s.get(o);n?n.push(i):s.set(o,[i])}return Array.from(s.values()).flat()}suggest(){if(!this.suggestions.length){this.options.showNoSuggestionNotice?this.noSuggestions():this.hide();return}let t=this.options,{groupBy:e,formatResult:s,beforeRender:i}=t,o=this.getQuery(this.currentValue),n=this.classes.suggestion,a=this.classes.selected,l=this.$container;if(t.triggerSelectOnValidInput&&this.isExactMatch(o)){this.select(0);return}e&&(this.suggestions=this.groupSuggestionsByCategory(this.suggestions,e));let u,g=d=>{let f=d.data[e];return u===f?"":(u=f,t.formatGroup(d,u))},y=this.suggestions.map((d,f)=>`${e?g(d):""}${s(d,o,f)}
`).join("");this.adjustContainerWidth(),this.$noSuggestionsContainer.detach(),l.html(y),i?.call(this.element,l,this.suggestions),this.fixPosition(),l.show(),t.autoSelectFirst&&(this.selectedIndex=0,l.scrollTop(0),l.children(`.${n}`).first().addClass(a)),this.visible=!0,this.findBestHint()}noSuggestions(){let{beforeRender:t}=this.options,e=this.$container;this.adjustContainerWidth(),this.$noSuggestionsContainer.detach(),e.empty().append(this.$noSuggestionsContainer),t?.call(this.element,e,this.suggestions),this.fixPosition(),e.show(),this.visible=!0}adjustContainerWidth(){let{width:t}=this.options;if(t==="auto"){let e=this.el.outerWidth()??0;this.$container.css("width",e>0?e:300)}else t==="flex"&&this.$container.css("width","")}findBestHint(){let t=this.el.val().toLowerCase();if(!t)return;let e=this.suggestions.find(s=>s.value.toLowerCase().indexOf(t)===0)??null;this.onHint(e)}onHint(t){let{onHint:e}=this.options,s=t?this.currentValue+t.value.substr(this.currentValue.length):"";this.hintValue!==s&&(this.hintValue=s,this.hint=t,e?.call(this.element,s))}verifySuggestionsFormat(t){return t.length&&typeof t[0]=="string"?t.map(e=>({value:e,data:null})):t.map(e=>typeof e.value=="string"?e:{...e,value:String(e.value)})}validateOrientation(t,e){let s=(t||"").trim().toLowerCase();return s==="auto"||s==="top"||s==="bottom"?s:e}processResponse(t,e,s){let i=this.options;t.suggestions=this.verifySuggestionsFormat(t.suggestions),i.noCache||(this.cachedResponse[s]=t,i.preventBadQueries&&!t.suggestions.length&&e&&this.badQueries.push(e)),e===this.getQuery(this.currentValue)&&(this.suggestions=t.suggestions,this.suggest())}activate(t){let e=this.classes.selected,s=this.$container,i=s.find(`.${this.classes.suggestion}`);if(s.find(`.${e}`).removeClass(e),this.selectedIndex=t,this.selectedIndex!==-1&&i.length>this.selectedIndex){let o=i.get(this.selectedIndex);return c(o).addClass(e),o}return null}selectHint(){this.select(this.suggestions.indexOf(this.hint))}select(t){this.hide(),this.onSelect(t)}moveUp(){if(this.selectedIndex!==-1){if(this.selectedIndex===0){this.$container.children(`.${this.classes.suggestion}`).first().removeClass(this.classes.selected),this.selectedIndex=-1,this.ignoreValueChange=!1,this.el.val(this.currentValue),this.findBestHint();return}this.adjustScroll(this.selectedIndex-1)}}moveDown(){this.selectedIndex!==this.suggestions.length-1&&this.adjustScroll(this.selectedIndex+1)}adjustScroll(t){let e=this.activate(t);if(!e)return;let s=c(e).outerHeight()??0,i=e.offsetTop,o=this.$container,n=o.scrollTop()??0,a=n+this.options.maxHeight-s;ia&&o.scrollTop(i-this.options.maxHeight+s),this.options.preserveInput||(this.ignoreValueChange=!0,this.el.val(this.getValue(this.suggestions[t].value))),this.onHint(null)}onSelect(t){let e=this.options.onSelect,s=this.suggestions[t];this.currentValue=this.getValue(s.value),this.currentValue!==this.el.val()&&!this.options.preserveInput&&this.el.val(this.currentValue),this.onHint(null),this.suggestions=[],this.selection=s,e?.call(this.element,s)}getValue(t){let{delimiter:e}=this.options;if(!e)return t;let s=this.currentValue,i=s.split(e);return i.length===1?t:s.substr(0,s.length-i[i.length-1].length)+t}dispose(){this.el.off(".autocomplete").removeData("autocomplete"),this.fixPositionCapture&&c(window).off("resize.autocomplete",this.fixPositionCapture),this.$container.remove()}};p.defaults=A,p.utils=v;var m=p;var b="autocomplete";function H(r){C(r),r.Autocomplete=m,r.fn.devbridgeAutocomplete=function(t,e){return arguments.length?this.each(function(){let s=r(this),i=s.data(b);typeof t=="string"?i&&typeof i[t]=="function"&&i[t](e):(i&&i.dispose&&i.dispose(),i=new m(this,t),s.data(b,i))}):this.first().data(b)},r.fn.autocomplete||(r.fn.autocomplete=r.fn.devbridgeAutocomplete)}H($);})();
});
diff --git a/package.json b/package.json
index 70a22b8..4a7cb0a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "devbridge-autocomplete",
- "version": "2.0.1",
+ "version": "2.0.2",
"description": "Autocomplete provides suggestions while you type into the text field.",
"homepage": "https://github.com/devbridge/jQuery-Autocomplete",
"author": "Tomas Kirda (https://twitter.com/tkirda)",
diff --git a/src/Autocomplete.ts b/src/Autocomplete.ts
index 0054222..eef7f81 100644
--- a/src/Autocomplete.ts
+++ b/src/Autocomplete.ts
@@ -645,7 +645,11 @@ export class Autocomplete {
if (!options.noCache) {
this.cachedResponse[cacheKey] = result;
- if (options.preventBadQueries && !result.suggestions.length) {
+ // Guard against pushing an empty `originalQuery`. `isBadQuery`
+ // matches by prefix (`q.indexOf(bad) === 0`); an empty entry
+ // would match every subsequent query and silently block all
+ // ajax requests after the first empty-query response.
+ if (options.preventBadQueries && !result.suggestions.length && originalQuery) {
this.badQueries.push(originalQuery);
}
}
diff --git a/test/autocomplete.test.js b/test/autocomplete.test.js
index 3bae7ce..acdc4c1 100644
--- a/test/autocomplete.test.js
+++ b/test/autocomplete.test.js
@@ -362,6 +362,44 @@ describe("Autocomplete Async — preventBadQueries", () => {
});
});
+describe("Autocomplete Async — empty originalQuery", () => {
+ it("does not push an empty originalQuery onto badQueries", async () => {
+ const input = $("");
+ const serviceUrl = "/autocomplete/empty-bad-query";
+ let ajaxCount = 0;
+
+ input.autocomplete({
+ serviceUrl,
+ minChars: 0,
+ preventBadQueries: true,
+ });
+ const instance = input.autocomplete();
+
+ $.mockjax({
+ url: serviceUrl,
+ responseTime: 1,
+ response: function () {
+ ajaxCount += 1;
+ this.responseText = JSON.stringify({ suggestions: [] });
+ },
+ });
+
+ // First lookup: empty query with no results.
+ input.val("");
+ instance.onValueChange();
+ await new Promise((r) => setTimeout(r, 30));
+
+ // Second lookup: real query — must not be short-circuited by an empty
+ // prefix sitting in badQueries.
+ input.val("Jam");
+ instance.onValueChange();
+ await new Promise((r) => setTimeout(r, 30));
+
+ expect(instance.badQueries).not.toContain("");
+ expect(ajaxCount).toBe(2);
+ });
+});
+
describe("Autocomplete", () => {
afterEach(() => {
$(".autocomplete-suggestions").hide();