diff --git a/bower.json b/bower.json index cf24cef..29c8934 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "autocompeter", - "version": "1.1.13", + "version": "1.2.0", "homepage": "https://autocompeter.com", "authors": [ "Peter Bengtsson " diff --git a/public/dist/autocompeter.js b/public/dist/autocompeter.js index 12bb8e9..1e47701 100644 --- a/public/dist/autocompeter.js +++ b/public/dist/autocompeter.js @@ -90,6 +90,7 @@ var results_ps = []; var selected_pointer = 0; + var actually_selected_pointer = false; q.spellcheck = false; q.autocomplete = 'off'; @@ -215,7 +216,7 @@ } p = createDomElement('p'); - if (i === selected_pointer) { + if (i === selected_pointer && actually_selected_pointer) { p.classList.add('selected'); } p.dataset.i = i; // needed by the onmouseover event handler @@ -244,12 +245,13 @@ function findParentForm(element) { var parent = element.parentNode; + if (parent === null) { + console.warn("Form can not be found. Nothing to submit"); + return; + } if (parent.nodeName === 'FORM') { return parent; } - if (parent === null) { - throw "too deep. no parent form node to be found"; - } return findParentForm(parent); } @@ -262,6 +264,7 @@ if (q.value !== hint.value) { handler(); // this starts a new ajax request } + actually_selected_pointer = true; } else if (name === 'down' || name === 'up') { if (name === 'down') { selected_pointer = Math.min(results_ps.length - 1, ++selected_pointer); @@ -269,15 +272,16 @@ selected_pointer = Math.max(0, --selected_pointer); } for (i=0, len=results_ps.length; i < len; i++) { - if (i === selected_pointer) { + if (i === selected_pointer && actually_selected_pointer) { results_ps[i].classList.add('selected'); } else { results_ps[i].classList.remove('selected'); } } + actually_selected_pointer = true; displayResults(); } else if (name === 'enter') { - if (results_ps.length) { + if (results_ps.length && actually_selected_pointer) { var p = results_ps[selected_pointer]; var a = p.getElementsByTagName('a')[0]; q.value = hint.value = a.textContent; @@ -286,7 +290,10 @@ } else { // We need to submit the form but we can't simply `return true` // because the event we're returning to isn't a form submission. - findParentForm(q).submit(); + var form = findParentForm(q); + if (form) { + form.submit(); + } return true; } } else if (name === 'esc') { @@ -338,8 +345,11 @@ } } - // new character, let's reset the selected_pointer + // New character, let's reset the selected_pointer selected_pointer = 0; + // Also, reset that none of the results have been explicitly + // selected yet. + actually_selected_pointer = false; if (cache[q.value.trim()]) { var response = cache[q.value.trim()]; terms = response.terms; diff --git a/public/dist/autocompeter.min.js b/public/dist/autocompeter.min.js index a912fbc..edbbc98 100644 --- a/public/dist/autocompeter.min.js +++ b/public/dist/autocompeter.min.js @@ -1,2 +1,2 @@ /* Autocompeter.com 1.1.13 */ -!function(e,t){"use strict";function n(e,n){var a=t.createElement(e);for(var l in n)a[l]=n[l];return a}function a(e,t,n){e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent(t,n)}function l(){var e,t,n,a,l,r,u,o=[].slice;for(a=arguments[0],n=2<=arguments.length?o.call(arguments,1):[],r=0,u=n.length;u>r;r++){t=n[r];for(e in t)l=t[e],a[e]=l}return a}function r(r,u){function o(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function i(e){var t=N.map(o),n=new RegExp("\\b(("+t.join("|")+")[\\S']*)","gi");return e.replace(n,"$1")}function s(e){"P"===e.target.tagName&&w!==+e.target.dataset.i&&(w=+e.target.dataset.i,c())}function p(e,t){for(var n=[],a=t.map(o),l=new RegExp("\\b("+a.join("|")+")","gi"),r=0,u=e.length;u>r;r++)e[r][1].search(l)>-1&&n.push(e[r]);return n}function c(a){a=a||!1,!a&&k&&e.clearTimeout(k);var l,u;if(null!==M){if(a&&(M=p(M,N)),!M.length)return void(L.style.display="none");L.style.display="block";var s=L.getElementsByTagName("p");for(l=s.length-1;l>=0;l--)s[l].remove();b=[];var c,v,d=null,f=[];M.length||(E.value="");var m=N.map(o),g=new RegExp("\\b("+m.join("|")+")(\\w+)\\b","gi"),h=t.createDocumentFragment();for(l=0,u=M.length;u>l;l++){for(var y,x;null!==(y=g.exec(M[l][1]));)x=new RegExp("\\b"+o(y[0])+"\\b","gi"),d=y[y.length-1],void 0===d||x.test(r.value)||w===l&&f.push(d);c=n("p"),l===w&&c.classList.add("selected"),c.dataset.i=l,v=n("a",{innerHTML:i(M[l][1]),href:M[l][0]}),c.appendChild(v),h.appendChild(c),b.push(c)}L.appendChild(h),f.length&&" "!==r.value.charAt(r.value.length-1)?(d=f[w%f.length],E.value=r.value+d):E.value=""}}function v(e){var t=e.parentNode;if("FORM"===t.nodeName)return t;if(null===t)throw"too deep. no parent form node to be found";return v(t)}function d(t){var n,a;if("tab"===t)E.value!==r.value&&(r.value=E.value+" "),r.value!==E.value&&g();else if("down"===t||"up"===t){for("down"===t?w=Math.min(b.length-1,++w):"up"===t&&(w=Math.max(0,--w)),n=0,a=b.length;a>n;n++)n===w?b[n].classList.add("selected"):b[n].classList.remove("selected");c()}else if("enter"===t){if(!b.length)return v(r).submit(),!0;var l=b[w],u=l.getElementsByTagName("a")[0];r.value=E.value=u.textContent,L.style.display="none",e.location=u.href}else"esc"===t&&(L.style.display="none");return!1}function f(e){var t={13:"enter",9:"tab",38:"up",40:"down",27:"esc"};return t[e.keyCode]?(e.preventDefault(),d(t[e.keyCode])):!1}function m(){L.style.display="none"}function g(){if(!r.value.trim())return E.value="",void(L.style.display="none");if(E.value.length&&(-1===E.value.indexOf(r.value.trim())&&(E.value=r.value),"block"===L.style.display&&(N=r.value.trim().split(/\s+/),k=e.setTimeout(function(){c(!0)},150))),w=0,X[r.value.trim()]){var t=X[r.value.trim()];N=t.terms,M=t.results,c()}else{if(T&&T.abort(),e.XMLHttpRequest)T=new e.XMLHttpRequest;else{if(!e.ActiveXObject)return;T=new e.ActiveXObject("Microsoft.XMLHTTP")}if(r.value.trim().length){var n=r.value.trim().substring(0,r.value.trim().length-1);if(X[n]&&!X[n].results.length)return void(X[r.value.trim()]={results:[]})}T.onreadystatechange=function(){if(4===T.readyState)if(200===T.status){if(R===r.value){var e=JSON.parse(T.responseText);X[r.value.trim()]=e,N=e.terms,M=e.results,c()}}else 0!==T.status&&(console.warn(T.status,T.responseText),m())},T.open("GET",u.url+encodeURIComponent(r.value.trim()),!0),R=r.value,T.send()}}function h(e){E.value=r.value,setTimeout(function(){L.style.display="none"},200),e.preventDefault()}function y(){if(j&&u.ping&&e.XMLHttpRequest){var t=new e.XMLHttpRequest;t.open("GET",u.url.split("?")[0]+"/ping"),t.send(),j=!1}r.value.length&&b.length&&(L.style.display="block")}u=l({url:"https://autocompeter.com/v1",domain:location.host,groups:null,ping:!0},u||{}),u.url+=u.url.indexOf("?")>-1?"&":"?",u.number&&(u.url+="n="+u.number+"&"),u.groups&&(Array.isArray(u.groups)&&(u.groups=u.groups.join(",")),u.url+="g="+encodeURIComponent(u.groups)+"&"),u.url+="d="+u.domain+"&q=";var b=[],w=0;r.spellcheck=!1,r.autocomplete="off";var x=n("span",{className:"_ac-wrap"}),E=n("input",{tabindex:-1,spellcheck:!1,autocomplete:"off",readonly:"readonly",type:r.type||"text",className:r.className+" _ac-hint"});r.classList.add("_ac-foreground"),x.appendChild(E);var C=r.cloneNode(!0);x.appendChild(C);var L=n("div",{className:"_ac-results"});a(L,"mouseover",s),x.appendChild(L),r.parentElement.insertBefore(x,r),r.parentNode.removeChild(r),r=C;var N,T,R,M=null,k=null,X={},j=!0;a(r,"input",g),a(r,"keydown",f),a(r,"blur",h),a(r,"focus",y)}e.Autocompeter=r}(window,document); \ No newline at end of file +!function(e,t){"use strict";function n(e,n){var a=t.createElement(e);for(var l in n)a[l]=n[l];return a}function a(e,t,n){e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent(t,n)}function l(){var e,t,n,a,l,r,u,o=[].slice;for(a=arguments[0],n=2<=arguments.length?o.call(arguments,1):[],r=0,u=n.length;u>r;r++){t=n[r];for(e in t)l=t[e],a[e]=l}return a}function r(r,u){function o(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function s(e){var t=T.map(o),n=new RegExp("\\b(("+t.join("|")+")[\\S']*)","gi");return e.replace(n,"$1")}function i(e){"P"===e.target.tagName&&w!==+e.target.dataset.i&&(w=+e.target.dataset.i,p())}function c(e,t){for(var n=[],a=t.map(o),l=new RegExp("\\b("+a.join("|")+")","gi"),r=0,u=e.length;u>r;r++)e[r][1].search(l)>-1&&n.push(e[r]);return n}function p(a){a=a||!1,!a&&X&&e.clearTimeout(X);var l,u;if(null!==k){if(a&&(k=c(k,T)),!k.length)return void(L.style.display="none");L.style.display="block";var i=L.getElementsByTagName("p");for(l=i.length-1;l>=0;l--)i[l].remove();b=[];var p,v,d=null,f=[];k.length||(N.value="");var m=T.map(o),g=new RegExp("\\b("+m.join("|")+")(\\w+)\\b","gi"),h=t.createDocumentFragment();for(l=0,u=k.length;u>l;l++){for(var y,E;null!==(y=g.exec(k[l][1]));)E=new RegExp("\\b"+o(y[0])+"\\b","gi"),d=y[y.length-1],void 0===d||E.test(r.value)||w===l&&f.push(d);p=n("p"),l===w&&x&&p.classList.add("selected"),p.dataset.i=l,v=n("a",{innerHTML:s(k[l][1]),href:k[l][0]}),p.appendChild(v),h.appendChild(p),b.push(p)}L.appendChild(h),f.length&&" "!==r.value.charAt(r.value.length-1)?(d=f[w%f.length],N.value=r.value+d):N.value=""}}function v(e){var t=e.parentNode;return null===t?void console.warn("Form can not be found. Nothing to submit"):"FORM"===t.nodeName?t:v(t)}function d(t){var n,a;if("tab"===t)N.value!==r.value&&(r.value=N.value+" "),r.value!==N.value&&g(),x=!0;else if("down"===t||"up"===t){for("down"===t?w=Math.min(b.length-1,++w):"up"===t&&(w=Math.max(0,--w)),n=0,a=b.length;a>n;n++)n===w&&x?b[n].classList.add("selected"):b[n].classList.remove("selected");x=!0,p()}else if("enter"===t){if(!b.length||!x){var l=v(r);return l&&l.submit(),!0}var u=b[w],o=u.getElementsByTagName("a")[0];r.value=N.value=o.textContent,L.style.display="none",e.location=o.href}else"esc"===t&&(L.style.display="none");return!1}function f(e){var t={13:"enter",9:"tab",38:"up",40:"down",27:"esc"};return t[e.keyCode]?(e.preventDefault(),d(t[e.keyCode])):!1}function m(){L.style.display="none"}function g(){if(!r.value.trim())return N.value="",void(L.style.display="none");if(N.value.length&&(-1===N.value.indexOf(r.value.trim())&&(N.value=r.value),"block"===L.style.display&&(T=r.value.trim().split(/\s+/),X=e.setTimeout(function(){p(!0)},150))),w=0,x=!1,j[r.value.trim()]){var t=j[r.value.trim()];T=t.terms,k=t.results,p()}else{if(R&&R.abort(),e.XMLHttpRequest)R=new e.XMLHttpRequest;else{if(!e.ActiveXObject)return;R=new e.ActiveXObject("Microsoft.XMLHTTP")}if(r.value.trim().length){var n=r.value.trim().substring(0,r.value.trim().length-1);if(j[n]&&!j[n].results.length)return void(j[r.value.trim()]={results:[]})}R.onreadystatechange=function(){if(4===R.readyState)if(200===R.status){if(M===r.value){var e=JSON.parse(R.responseText);j[r.value.trim()]=e,T=e.terms,k=e.results,p()}}else 0!==R.status&&(console.warn(R.status,R.responseText),m())},R.open("GET",u.url+encodeURIComponent(r.value.trim()),!0),M=r.value,R.send()}}function h(e){N.value=r.value,setTimeout(function(){L.style.display="none"},200),e.preventDefault()}function y(){if(A&&u.ping&&e.XMLHttpRequest){var t=new e.XMLHttpRequest;t.open("GET",u.url.split("?")[0]+"/ping"),t.send(),A=!1}r.value.length&&b.length&&(L.style.display="block")}u=l({url:"https://autocompeter.com/v1",domain:location.host,groups:null,ping:!0},u||{}),u.url+=u.url.indexOf("?")>-1?"&":"?",u.number&&(u.url+="n="+u.number+"&"),u.groups&&(Array.isArray(u.groups)&&(u.groups=u.groups.join(",")),u.url+="g="+encodeURIComponent(u.groups)+"&"),u.url+="d="+u.domain+"&q=";var b=[],w=0,x=!1;r.spellcheck=!1,r.autocomplete="off";var E=n("span",{className:"_ac-wrap"}),N=n("input",{tabindex:-1,spellcheck:!1,autocomplete:"off",readonly:"readonly",type:r.type||"text",className:r.className+" _ac-hint"});r.classList.add("_ac-foreground"),E.appendChild(N);var C=r.cloneNode(!0);E.appendChild(C);var L=n("div",{className:"_ac-results"});a(L,"mouseover",i),E.appendChild(L),r.parentElement.insertBefore(E,r),r.parentNode.removeChild(r),r=C;var T,R,M,k=null,X=null,j={},A=!0;a(r,"input",g),a(r,"keydown",f),a(r,"blur",h),a(r,"focus",y)}e.Autocompeter=r}(window,document); \ No newline at end of file diff --git a/src/autocompeter.js b/src/autocompeter.js index 12bb8e9..1e47701 100644 --- a/src/autocompeter.js +++ b/src/autocompeter.js @@ -90,6 +90,7 @@ var results_ps = []; var selected_pointer = 0; + var actually_selected_pointer = false; q.spellcheck = false; q.autocomplete = 'off'; @@ -215,7 +216,7 @@ } p = createDomElement('p'); - if (i === selected_pointer) { + if (i === selected_pointer && actually_selected_pointer) { p.classList.add('selected'); } p.dataset.i = i; // needed by the onmouseover event handler @@ -244,12 +245,13 @@ function findParentForm(element) { var parent = element.parentNode; + if (parent === null) { + console.warn("Form can not be found. Nothing to submit"); + return; + } if (parent.nodeName === 'FORM') { return parent; } - if (parent === null) { - throw "too deep. no parent form node to be found"; - } return findParentForm(parent); } @@ -262,6 +264,7 @@ if (q.value !== hint.value) { handler(); // this starts a new ajax request } + actually_selected_pointer = true; } else if (name === 'down' || name === 'up') { if (name === 'down') { selected_pointer = Math.min(results_ps.length - 1, ++selected_pointer); @@ -269,15 +272,16 @@ selected_pointer = Math.max(0, --selected_pointer); } for (i=0, len=results_ps.length; i < len; i++) { - if (i === selected_pointer) { + if (i === selected_pointer && actually_selected_pointer) { results_ps[i].classList.add('selected'); } else { results_ps[i].classList.remove('selected'); } } + actually_selected_pointer = true; displayResults(); } else if (name === 'enter') { - if (results_ps.length) { + if (results_ps.length && actually_selected_pointer) { var p = results_ps[selected_pointer]; var a = p.getElementsByTagName('a')[0]; q.value = hint.value = a.textContent; @@ -286,7 +290,10 @@ } else { // We need to submit the form but we can't simply `return true` // because the event we're returning to isn't a form submission. - findParentForm(q).submit(); + var form = findParentForm(q); + if (form) { + form.submit(); + } return true; } } else if (name === 'esc') { @@ -338,8 +345,11 @@ } } - // new character, let's reset the selected_pointer + // New character, let's reset the selected_pointer selected_pointer = 0; + // Also, reset that none of the results have been explicitly + // selected yet. + actually_selected_pointer = false; if (cache[q.value.trim()]) { var response = cache[q.value.trim()]; terms = response.terms; diff --git a/templates/index.tmpl b/templates/index.tmpl index 4ebf025..3d62723 100644 --- a/templates/index.tmpl +++ b/templates/index.tmpl @@ -102,8 +102,10 @@

Autocompeter

A really fast AJAX autocomplete service and widget


- +
+
+