diff options
author | Alex DiLiberto <alex@alexdiliberto.com> | 2015-02-24 21:04:32 -0500 |
---|---|---|
committer | Alex DiLiberto <alex@alexdiliberto.com> | 2015-02-24 21:04:32 -0500 |
commit | ce9aad862dd2f199160411a428632bc980b73632 (patch) | |
tree | 77c0da0ee4b6507236bd52a726719e1b5b81fdf5 | |
parent | 75834f2e6b9130a9bc1d1b732b71eafaca9ae72b (diff) | |
download | awesomplete-ce9aad862dd2f199160411a428632bc980b73632.zip awesomplete-ce9aad862dd2f199160411a428632bc980b73632.tar.gz awesomplete-ce9aad862dd2f199160411a428632bc980b73632.tar.bz2 |
[BUGFIX] Keydown events while `ul` is hidden should not trigger component actions
This fixes a bug where previously, if the `ul` was hidden, the component would still act upon keydown events for Enter/Esc/Up/Down
To replicate the previous bug: In the demo, you can select `Java` then keyup and down. You know see that the context is not within the input tag iself, however it's within the component which is still selecting items from the previously searched list.
-rw-r--r-- | awesomplete.js | 126 | ||||
-rw-r--r-- | awesomplete.min.js | 9 |
2 files changed, 66 insertions, 69 deletions
diff --git a/awesomplete.js b/awesomplete.js index 9b388ef..653b524 100644 --- a/awesomplete.js +++ b/awesomplete.js @@ -4,19 +4,19 @@ * @author Lea Verou http://leaverou.github.io/awesomplete * MIT license */ - + (function () { var _ = self.Awesomplete = function (input, o) { var me = this; - + // Setup - + this.input = input; input.setAttribute("aria-autocomplete", "list"); - + o = o || {}; - + configure.call(this, { minChars: 2, maxItems: 10, @@ -27,66 +27,70 @@ var _ = self.Awesomplete = function (input, o) { return $.create("li", { innerHTML: text.replace(RegExp($.regExpEscape(input.trim()), "gi"), "<mark>$&</mark>"), "aria-selected": "false" - }); + }); }, replace: function (text) { this.input.value = text; } }, o); - + this.index = -1; - + // Create necessary elements - + this.container = $.create("div", { className: "awesomplete", around: input }); - + this.ul = $.create("ul", { hidden: "", inside: this.container }); - + // Bind events - + $.bind(this.input, { "input": this.evaluate.bind(this), "blur": this.close.bind(this), "keydown": function(evt) { var c = evt.keyCode; - - if (c === 13 && me.selected) { // Enter - evt.preventDefault(); - me.select(); - } - else if (c === 27) { // Esc - me.close(); - } - else if (c === 38 || c === 40) { // Down/Up arrow - evt.preventDefault(); - me[c === 38? "previous" : "next"](); + + // If the dropdown `ul` is in view, then act on keydown for the following keys: + // Enter / Esc / Up / Down + if(me.ul && me.ul.getAttribute("hidden") == null) { + if (c === 13 && me.selected) { // Enter + evt.preventDefault(); + me.select(); + } + else if (c === 27) { // Esc + me.close(); + } + else if (c === 38 || c === 40) { // Down/Up arrow + evt.preventDefault(); + me[c === 38? "previous" : "next"](); + } } } }); - + $.bind(this.input.form, {"submit": me.close.bind(me)}); - + $.bind(this.ul, {"mousedown": function(evt) { var li = evt.target; - + if (li !== this) { - + while (li && !/li/i.test(li.nodeName)) { li = li.parentNode; } - + if (li) { - me.select(li); + me.select(li); } } }}); - + if (input.hasAttribute("list")) { this.list = "#" + input.getAttribute("list"); input.removeAttribute("list"); @@ -94,7 +98,7 @@ var _ = self.Awesomplete = function (input, o) { else { this.list = input.getAttribute("data-list") || o.list || []; } - + _.all.push(this); }; @@ -108,80 +112,80 @@ _.prototype = { } else { // Element or CSS selector list = $(list); - + if (list && list.children) { this._list = slice.apply(list.children).map(function (el) { return el.innerHTML.trim(); }); } } - + if (document.activeElement === this.input) { this.evaluate(); } }, - + get selected() { return this.index > -1; }, - + close: function () { this.ul.setAttribute("hidden", ""); this.index = -1; - + $.fire(this.input, "awesomplete-close"); }, - + open: function () { this.ul.removeAttribute("hidden"); - + if (this.autoFirst && this.index === -1) { this.goto(0); } - + $.fire(this.input, "awesomplete-open"); }, - + next: function () { var count = this.ul.children.length; this.goto(this.index < count - 1? this.index + 1 : -1); }, - + previous: function () { var count = this.ul.children.length; - + this.goto(this.selected? this.index - 1 : count - 1); }, - + // Should not be used, highlights specific item without any checks! goto: function (i) { var lis = this.ul.children; - + if (this.selected) { lis[this.index].setAttribute("aria-selected", "false"); } - + this.index = i; - + if (i > -1 && lis.length > 0) { lis[i].setAttribute("aria-selected", "true"); } }, - + select: function (selected) { selected = selected || this.ul.children[this.index]; if (selected) { var prevented; - + $.fire(this.input, "awesomplete-select", { text: selected.textContent, preventDefault: function () { prevented = true; } }); - + if (!prevented) { this.replace(selected.textContent); this.close(); @@ -189,11 +193,11 @@ _.prototype = { } } }, - + evaluate: function() { var me = this; var value = this.input.value; - + if (value.length >= this.minChars && this._list.length > 0) { this.index = -1; // Populate list with options that match @@ -206,10 +210,10 @@ _.prototype = { .sort(this.sort) .every(function(text, i) { me.ul.appendChild(me.item(text, value)); - + return i < me.maxItems - 1; }); - + this.open(); } else { @@ -234,7 +238,7 @@ _.SORT_BYLENGTH = function (a, b) { if (a.length !== b.length) { return a.length - b.length; } - + return a < b? -1 : 1; }; @@ -244,7 +248,7 @@ function configure(properties, o) { for (var i in properties) { var initial = properties[i], attrValue = this.input.getAttribute("data-" + i.toLowerCase()); - + if (typeof initial === "number") { this[i] = +attrValue; } @@ -257,7 +261,7 @@ function configure(properties, o) { else { this[i] = attrValue; } - + this[i] = this[i] || o[i] || initial; } } @@ -276,10 +280,10 @@ function $$(expr, con) { $.create = function(tag, o) { var element = document.createElement(tag); - + for (var i in o) { var val = o[i]; - + if (i === "inside") { $(val).appendChild(element); } @@ -295,7 +299,7 @@ $.create = function(tag, o) { element.setAttribute(i, val); } } - + return element; }; @@ -303,7 +307,7 @@ $.bind = function(element, o) { if (element) { for (var event in o) { var callback = o[event]; - + event.split(/\s+/).forEach(function (event) { element.addEventListener(event, callback); }); @@ -313,7 +317,7 @@ $.bind = function(element, o) { $.fire = function(target, type, properties) { var evt = document.createEvent("HTMLEvents"); - + evt.initEvent(type, true, true ); for (var j in properties) { diff --git a/awesomplete.min.js b/awesomplete.min.js index c7f82b3..3b7c534 100644 --- a/awesomplete.min.js +++ b/awesomplete.min.js @@ -1,9 +1,2 @@ // Awesomplete - Lea Verou - MIT license -(function(){function m(a,b){for(var c in a){var f=a[c],e=this.input.getAttribute("data-"+c.toLowerCase());this[c]="number"===typeof f?+e:!1===f?null!==e:f instanceof Function?null:e;this[c]=this[c]||b[c]||f}}function d(a,b){return"string"===typeof a?(b||document).querySelector(a):a||null}function h(a,b){return k.call((b||document).querySelectorAll(a))}function l(){h("input.awesomplete").forEach(function(a){new Awesomplete(a)})}var g=self.Awesomplete=function(a,b){var c=this;this.input=a;a.setAttribute("aria-autocomplete", -"list");b=b||{};m.call(this,{minChars:2,maxItems:10,autoFirst:!1,filter:g.FILTER_CONTAINS,sort:g.SORT_BYLENGTH,item:function(a,b){return d.create("li",{innerHTML:a.replace(RegExp(d.regExpEscape(b.trim()),"gi"),"<mark>$&</mark>"),"aria-selected":"false"})},replace:function(a){this.input.value=a}},b);this.index=-1;this.container=d.create("div",{className:"awesomplete",around:a});this.ul=d.create("ul",{hidden:"",inside:this.container});d.bind(this.input,{input:this.evaluate.bind(this),blur:this.close.bind(this), -keydown:function(a){var b=a.keyCode;if(13===b&&c.selected)a.preventDefault(),c.select();else if(27===b)c.close();else if(38===b||40===b)a.preventDefault(),c[38===b?"previous":"next"]()}});d.bind(this.input.form,{submit:c.close.bind(c)});d.bind(this.ul,{mousedown:function(a){a=a.target;if(a!==this){for(;a&&!/li/i.test(a.nodeName);)a=a.parentNode;a&&c.select(a)}}});a.hasAttribute("list")?(this.list="#"+a.getAttribute("list"),a.removeAttribute("list")):this.list=a.getAttribute("data-list")||b.list|| -[];g.all.push(this)};g.prototype={set list(a){Array.isArray(a)?this._list=a:"string"===typeof a&&-1<a.indexOf(",")?this._list=a.split(/\s*,\s*/):(a=d(a))&&a.children&&(this._list=k.apply(a.children).map(function(a){return a.innerHTML.trim()}));document.activeElement===this.input&&this.evaluate()},get selected(){return-1<this.index},close:function(){this.ul.setAttribute("hidden","");this.index=-1;d.fire(this.input,"awesomplete-close")},open:function(){this.ul.removeAttribute("hidden");this.autoFirst&& --1===this.index&&this.goto(0);d.fire(this.input,"awesomplete-open")},next:function(){this.goto(this.index<this.ul.children.length-1?this.index+1:-1)},previous:function(){var a=this.ul.children.length;this.goto(this.selected?this.index-1:a-1)},goto:function(a){var b=this.ul.children;this.selected&&b[this.index].setAttribute("aria-selected","false");this.index=a;-1<a&&0<b.length&&b[a].setAttribute("aria-selected","true")},select:function(a){if(a=a||this.ul.children[this.index]){var b;d.fire(this.input, -"awesomplete-select",{text:a.textContent,preventDefault:function(){b=!0}});b||(this.replace(a.textContent),this.close(),d.fire(this.input,"awesomplete-selectcomplete"))}},evaluate:function(){var a=this,b=this.input.value;b.length>=this.minChars&&0<this._list.length?(this.index=-1,this.ul.innerHTML="",this._list.filter(function(c){return a.filter(c,b)}).sort(this.sort).every(function(c,d){a.ul.appendChild(a.item(c,b));return d<a.maxItems-1}),this.open()):this.close()}};g.all=[];g.FILTER_CONTAINS=function(a, -b){return RegExp(d.regExpEscape(b.trim()),"i").test(a)};g.FILTER_STARTSWITH=function(a,b){return RegExp("^"+d.regExpEscape(b.trim()),"i").test(a)};g.SORT_BYLENGTH=function(a,b){return a.length!==b.length?a.length-b.length:a<b?-1:1};var k=Array.prototype.slice;d.create=function(a,b){var c=document.createElement(a),f;for(f in b){var e=b[f];"inside"===f?d(e).appendChild(c):"around"===f?(e=d(e),e.parentNode.insertBefore(c,e),c.appendChild(e)):f in c?c[f]=e:c.setAttribute(f,e)}return c};d.bind=function(a, -b){if(a)for(var c in b){var d=b[c];c.split(/\s+/).forEach(function(b){a.addEventListener(b,d)})}};d.fire=function(a,b,c){var d=document.createEvent("HTMLEvents");d.initEvent(b,!0,!0);for(var e in c)d[e]=c[e];a.dispatchEvent(d)};d.regExpEscape=function(a){return a.replace(/[-\\^$*+?.()|[\]{}]/g,"\\$&")};"loading"!==document.readyState?l():document.addEventListener("DOMContentLoaded",l);g.$=d;g.$$=h})();
\ No newline at end of file +!function(){function t(t,e){for(var i in t){var n=t[i],s=this.input.getAttribute("data-"+i.toLowerCase());this[i]="number"==typeof n?+s:n===!1?null!==s:n instanceof Function?null:s,this[i]=this[i]||e[i]||n}}function e(t,e){return"string"==typeof t?(e||document).querySelector(t):t||null}function i(t,e){return r.call((e||document).querySelectorAll(t))}function n(){i("input.awesomplete").forEach(function(t){new Awesomplete(t)})}var s=self.Awesomplete=function(i,n){var r=this;this.input=i,i.setAttribute("aria-autocomplete","list"),n=n||{},t.call(this,{minChars:2,maxItems:10,autoFirst:!1,filter:s.FILTER_CONTAINS,sort:s.SORT_BYLENGTH,item:function(t,i){return e.create("li",{innerHTML:t.replace(RegExp(e.regExpEscape(i.trim()),"gi"),"<mark>$&</mark>"),"aria-selected":"false"})},replace:function(t){this.input.value=t}},n),this.index=-1,this.container=e.create("div",{className:"awesomplete",around:i}),this.ul=e.create("ul",{hidden:"",inside:this.container}),e.bind(this.input,{input:this.evaluate.bind(this),blur:this.close.bind(this),keydown:function(t){var e=t.keyCode;r.ul&&null==r.ul.getAttribute("hidden")&&(13===e&&r.selected?(t.preventDefault(),r.select()):27===e?r.close():(38===e||40===e)&&(t.preventDefault(),r[38===e?"previous":"next"]()))}}),e.bind(this.input.form,{submit:r.close.bind(r)}),e.bind(this.ul,{mousedown:function(t){var e=t.target;if(e!==this){for(;e&&!/li/i.test(e.nodeName);)e=e.parentNode;e&&r.select(e)}}}),i.hasAttribute("list")?(this.list="#"+i.getAttribute("list"),i.removeAttribute("list")):this.list=i.getAttribute("data-list")||n.list||[],s.all.push(this)};s.prototype={set list(t){Array.isArray(t)?this._list=t:"string"==typeof t&&t.indexOf(",")>-1?this._list=t.split(/\s*,\s*/):(t=e(t),t&&t.children&&(this._list=r.apply(t.children).map(function(t){return t.innerHTML.trim()}))),document.activeElement===this.input&&this.evaluate()},get selected(){return this.index>-1},close:function(){this.ul.setAttribute("hidden",""),this.index=-1,e.fire(this.input,"awesomplete-close")},open:function(){this.ul.removeAttribute("hidden"),this.autoFirst&&-1===this.index&&this["goto"](0),e.fire(this.input,"awesomplete-open")},next:function(){var t=this.ul.children.length;this["goto"](this.index<t-1?this.index+1:-1)},previous:function(){var t=this.ul.children.length;this["goto"](this.selected?this.index-1:t-1)},"goto":function(t){var e=this.ul.children;this.selected&&e[this.index].setAttribute("aria-selected","false"),this.index=t,t>-1&&e.length>0&&e[t].setAttribute("aria-selected","true")},select:function(t){if(t=t||this.ul.children[this.index]){var i;e.fire(this.input,"awesomplete-select",{text:t.textContent,preventDefault:function(){i=!0}}),i||(this.replace(t.textContent),this.close(),e.fire(this.input,"awesomplete-selectcomplete"))}},evaluate:function(){var t=this,e=this.input.value;e.length>=this.minChars&&this._list.length>0?(this.index=-1,this.ul.innerHTML="",this._list.filter(function(i){return t.filter(i,e)}).sort(this.sort).every(function(i,n){return t.ul.appendChild(t.item(i,e)),n<t.maxItems-1}),this.open()):this.close()}},s.all=[],s.FILTER_CONTAINS=function(t,i){return RegExp(e.regExpEscape(i.trim()),"i").test(t)},s.FILTER_STARTSWITH=function(t,i){return RegExp("^"+e.regExpEscape(i.trim()),"i").test(t)},s.SORT_BYLENGTH=function(t,e){return t.length!==e.length?t.length-e.length:e>t?-1:1};var r=Array.prototype.slice;e.create=function(t,i){var n=document.createElement(t);for(var s in i){var r=i[s];if("inside"===s)e(r).appendChild(n);else if("around"===s){var l=e(r);l.parentNode.insertBefore(n,l),n.appendChild(l)}else s in n?n[s]=r:n.setAttribute(s,r)}return n},e.bind=function(t,e){if(t)for(var i in e){var n=e[i];i.split(/\s+/).forEach(function(e){t.addEventListener(e,n)})}},e.fire=function(t,e,i){var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!0);for(var s in i)n[s]=i[s];t.dispatchEvent(n)},e.regExpEscape=function(t){return t.replace(/[-\\^$*+?.()|[\]{}]/g,"\\$&")},"loading"!==document.readyState?n():document.addEventListener("DOMContentLoaded",n),s.$=e,s.$$=i}(); |