diff options
Diffstat (limited to 'awesomplete.js')
-rw-r--r-- | awesomplete.js | 126 |
1 files changed, 65 insertions, 61 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) { |