diff --git a/.vscode/settings.json b/.vscode/settings.json index 897800ae..755bf1a2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,6 +4,7 @@ "Tarek", "activedescendant", "afterend", + "ascendingly", "autocapitalize", "autocorrect", "combobox", diff --git a/dist/js/autoComplete.js b/dist/js/autoComplete.js index 24eb4c88..5a34db5d 100644 --- a/dist/js/autoComplete.js +++ b/dist/js/autoComplete.js @@ -160,7 +160,6 @@ var createList = (function (config) { var list = document.createElement(config.resultsList.element); list.setAttribute("id", config.resultsList.idName); - list.setAttribute("aria-label", config.name); list.setAttribute("class", config.resultsList.className); list.setAttribute("role", "listbox"); list.setAttribute("tabindex", "-1"); @@ -188,9 +187,9 @@ })); }); - var closeList = function closeList(config) { + var closeList = function closeList(config, element) { var list = document.getElementById(config.resultsList.idName); - if (list) { + if (list && element !== config.inputField) { list.remove(); config.inputField.removeAttribute("aria-activedescendant"); config.inputField.setAttribute("aria-expanded", false); @@ -228,14 +227,18 @@ _loop(index); } } else { - config.noResults(list, data.query); + if (!config.resultsList.noResults) { + list.remove(); + } else { + config.resultsList.noResults(list, data.query); + } } }; var keyboardEvent = "keydown"; var navigate = function navigate(config, dataFeedback) { var currentFocus = -1; - var update = function update(event, list, state, config) { + var update = function update(event, list, state) { event.preventDefault(); if (state) { currentFocus++; @@ -253,7 +256,7 @@ var removeActive = function removeActive(list) { for (var index = 0; index < list.length; index++) { list[index].removeAttribute("aria-selected"); - if (config.selection.className) list[index].classList.remove(config.selection.className); + if (config.resultItem.selected.className) list[index].classList.remove(config.resultItem.selected.className); } }; var addActive = function addActive(list) { @@ -262,7 +265,7 @@ if (currentFocus >= list.length) currentFocus = 0; if (currentFocus < 0) currentFocus = list.length - 1; list[currentFocus].setAttribute("aria-selected", "true"); - if (config.selection.className) list[currentFocus].classList.add(config.selection.className); + if (config.resultItem.selected.className) list[currentFocus].classList.add(config.resultItem.selected.className); }; var navigation = function navigation(event) { var list = document.getElementById(config.resultsList.idName); @@ -270,19 +273,25 @@ config.inputField.removeEventListener(keyboardEvent, navigate); } else { list = list.getElementsByTagName(config.resultItem.element); - if (event.keyCode === 27) { - config.inputField.value = ""; - closeList(config); - } else if (event.keyCode === 40 || event.keyCode === 9) { - update(event, list, true, config); - } else if (event.keyCode === 38 || event.keyCode === 9) { - update(event, list, false, config); - } else if (event.keyCode === 13) { - event.preventDefault(); - if (currentFocus > -1) { - list[currentFocus].click(); + switch (event.keyCode) { + case 27: + config.inputField.value = ""; closeList(config); - } + break; + case 9: + case 40: + update(event, list, true); + break; + case 38: + update(event, list, false); + break; + case 13: + event.preventDefault(); + if (currentFocus > -1) { + list[currentFocus].click(); + closeList(config); + } + break; } } }; @@ -301,7 +310,7 @@ for (var number = 0; number < recordLowerCase.length; number++) { var recordChar = record[number]; if (searchPosition < query.length && recordLowerCase[number] === query[searchPosition]) { - recordChar = config.highlight.render ? "").concat(recordChar, "") : recordChar; + recordChar = config.resultItem.highlight.render ? "").concat(recordChar, "") : recordChar; searchPosition++; } match.push(recordChar); @@ -313,7 +322,7 @@ if (recordLowerCase.includes(query)) { var pattern = new RegExp(query.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"), "i"); query = pattern.exec(record); - var _match = config.highlight.render ? record.replace(query, "").concat(query, "")) : record; + var _match = config.resultItem.highlight.render ? record.replace(query, "").concat(query, "")) : record; return _match; } } @@ -372,8 +381,7 @@ for (var index = 0; index < config.data.store.length; index++) { _loop(index); } - var list = config.sort ? resList.sort(config.sort) : resList; - return list; + return resList; }; var debouncer = (function (callback, delay) { @@ -391,10 +399,9 @@ var autoComplete = function () { function autoComplete(config) { _classCallCheck(this, autoComplete); - var _config$name = config.name, - name = _config$name === void 0 ? "Search" : _config$name, - _config$selector = config.selector, + var _config$selector = config.selector, selector = _config$selector === void 0 ? "#autoComplete" : _config$selector, + placeHolder = config.placeHolder, _config$observer = config.observer, observer = _config$observer === void 0 ? false : _config$observer, _config$data = config.data, @@ -411,14 +418,15 @@ event = _config$trigger$event === void 0 ? ["input"] : _config$trigger$event, _config$trigger$condi = _config$trigger.condition, condition = _config$trigger$condi === void 0 ? false : _config$trigger$condi, - _config$searchEngine = config.searchEngine, - searchEngine = _config$searchEngine === void 0 ? "strict" : _config$searchEngine, - _config$diacritics = config.diacritics, - diacritics = _config$diacritics === void 0 ? false : _config$diacritics, _config$threshold = config.threshold, threshold = _config$threshold === void 0 ? 1 : _config$threshold, _config$debounce = config.debounce, debounce = _config$debounce === void 0 ? 0 : _config$debounce, + _config$diacritics = config.diacritics, + diacritics = _config$diacritics === void 0 ? false : _config$diacritics, + _config$searchEngine = config.searchEngine, + searchEngine = _config$searchEngine === void 0 ? "strict" : _config$searchEngine, + feedback = config.feedback, _config$resultsList = config.resultsList; _config$resultsList = _config$resultsList === void 0 ? {} : _config$resultsList; var _config$resultsList$r = _config$resultsList.render, @@ -434,39 +442,34 @@ resultsListId = _config$resultsList$i === void 0 ? "autoComplete_list" : _config$resultsList$i, _config$resultsList$c2 = _config$resultsList.className, resultsListClass = _config$resultsList$c2 === void 0 ? "autoComplete_list" : _config$resultsList$c2, + _config$resultsList$m = _config$resultsList.maxResults, + maxResults = _config$resultsList$m === void 0 ? 5 : _config$resultsList$m, _config$resultsList$n = _config$resultsList.navigation, navigation = _config$resultsList$n === void 0 ? false : _config$resultsList$n, - _config$sort = config.sort, - sort = _config$sort === void 0 ? false : _config$sort, - placeHolder = config.placeHolder, - _config$maxResults = config.maxResults, - maxResults = _config$maxResults === void 0 ? 5 : _config$maxResults, + noResults = _config$resultsList.noResults, _config$resultItem = config.resultItem; _config$resultItem = _config$resultItem === void 0 ? {} : _config$resultItem; var _config$resultItem$co = _config$resultItem.content, content = _config$resultItem$co === void 0 ? false : _config$resultItem$co, _config$resultItem$el = _config$resultItem.element, resultItemElement = _config$resultItem$el === void 0 ? "li" : _config$resultItem$el, - _config$resultItem$id = _config$resultItem.idName, - resultItemId = _config$resultItem$id === void 0 ? "autoComplete_result" : _config$resultItem$id, + resultItemId = _config$resultItem.idName, _config$resultItem$cl = _config$resultItem.className, resultItemClass = _config$resultItem$cl === void 0 ? "autoComplete_result" : _config$resultItem$cl, - noResults = config.noResults, - _config$selection = config.selection; - _config$selection = _config$selection === void 0 ? {} : _config$selection; - var _config$selection$cla = _config$selection.className, - selectionClass = _config$selection$cla === void 0 ? "autoComplete_selected" : _config$selection$cla, - _config$highlight = config.highlight; - _config$highlight = _config$highlight === void 0 ? {} : _config$highlight; - var _config$highlight$ren = _config$highlight.render, - highlightRender = _config$highlight$ren === void 0 ? false : _config$highlight$ren, - _config$highlight$cla = _config$highlight.className, - highlightClass = _config$highlight$cla === void 0 ? "autoComplete_highlighted" : _config$highlight$cla, - feedback = config.feedback, + _config$resultItem$hi = _config$resultItem.highlight; + _config$resultItem$hi = _config$resultItem$hi === void 0 ? {} : _config$resultItem$hi; + var _config$resultItem$hi2 = _config$resultItem$hi.render, + highlightRender = _config$resultItem$hi2 === void 0 ? false : _config$resultItem$hi2, + _config$resultItem$hi3 = _config$resultItem$hi.className, + highlightClass = _config$resultItem$hi3 === void 0 ? "autoComplete_highlighted" : _config$resultItem$hi3, + _config$resultItem$se = _config$resultItem.selected; + _config$resultItem$se = _config$resultItem$se === void 0 ? {} : _config$resultItem$se; + var _config$resultItem$se2 = _config$resultItem$se.className, + selectedClass = _config$resultItem$se2 === void 0 ? "autoComplete_selected" : _config$resultItem$se2, onSelection = config.onSelection; - this.name = name; this.selector = selector; this.observer = observer; + this.placeHolder = placeHolder; this.data = { src: src, key: key, @@ -479,10 +482,11 @@ event: event, condition: condition }; - this.searchEngine = searchEngine; - this.diacritics = diacritics; this.threshold = threshold; this.debounce = debounce; + this.diacritics = diacritics; + this.searchEngine = searchEngine; + this.feedback = feedback; this.resultsList = { render: resultsListRender, container: container, @@ -491,26 +495,23 @@ element: resultsListElement, idName: resultsListId, className: resultsListClass, - navigation: navigation + maxResults: maxResults, + navigation: navigation, + noResults: noResults }; - this.sort = sort; - this.placeHolder = placeHolder; - this.maxResults = maxResults; this.resultItem = { content: content, element: resultItemElement, idName: resultItemId, - className: resultItemClass - }; - this.noResults = noResults; - this.selection = { - className: selectionClass - }; - this.highlight = { - render: highlightRender, - className: highlightClass + className: resultItemClass, + highlight: { + render: highlightRender, + className: highlightClass + }, + selected: { + className: selectedClass + } }; - this.feedback = feedback; this.onSelection = onSelection; this.inputField = typeof this.selector === "string" ? document.querySelector(this.selector) : this.selector(); this.observer ? this.preInit() : this.init(); @@ -524,7 +525,7 @@ input: input, query: query, matches: results, - results: results.slice(0, this.maxResults) + results: results.slice(0, this.resultsList.maxResults) }; eventEmitter(this.inputField, dataFeedback, "results"); if (!this.resultsList.render) return this.feedback(dataFeedback); @@ -532,7 +533,7 @@ navigate(this, dataFeedback); eventEmitter(this.inputField, dataFeedback, "open"); document.addEventListener("click", function (event) { - return closeList(_this); + return closeList(_this, event.target); }); } }, { diff --git a/dist/js/autoComplete.js.gz b/dist/js/autoComplete.js.gz index 2ab799ba..1cf412c2 100644 Binary files a/dist/js/autoComplete.js.gz and b/dist/js/autoComplete.js.gz differ diff --git a/dist/js/autoComplete.min.js b/dist/js/autoComplete.min.js index ba64dce3..93c322fa 100644 --- a/dist/js/autoComplete.min.js +++ b/dist/js/autoComplete.min.js @@ -1 +1 @@ -var e,t;e=this,t=function(){"use strict";function e(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,i=new Array(t);n=e.length?{done:!0}:{done:!1,value:e[i++]}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,a=!0,l=!1;return{s:function(){n=e[Symbol.iterator]()},n:function(){var e=n.next();return a=e.done,e},e:function(e){l=!0,s=e},f:function(){try{a||null==n.return||n.return()}finally{if(l)throw s}}}}var s=function(e,t,n){e.dispatchEvent(new CustomEvent(n,{bubbles:!0,detail:t,cancelable:!0}))},a=function(e){var t=document.getElementById(e.resultsList.idName);t&&(t.remove(),e.inputField.removeAttribute("aria-activedescendant"),e.inputField.setAttribute("aria-expanded",!1),s(e.inputField,null,"close"))},l=function(e,t,n){var r=document.getElementById(e.resultsList.idName);if(r?r.innerHTML="":r=function(e){var t=document.createElement(e.resultsList.element);return t.setAttribute("id",e.resultsList.idName),t.setAttribute("aria-label",e.name),t.setAttribute("class",e.resultsList.className),t.setAttribute("role","listbox"),t.setAttribute("tabindex","-1"),e.resultsList.container&&e.resultsList.container(t),("string"==typeof e.resultsList.destination?document.querySelector(e.resultsList.destination):e.resultsList.destination()).insertAdjacentElement(e.resultsList.position,t),t}(e),e.inputField.setAttribute("aria-expanded",!0),n.length)for(var o=function(o){var s=t.results[o],a=function(e,t,n){var i=document.createElement(n.resultItem.element);return i.setAttribute("id","".concat(n.resultItem.idName,"_").concat(t)),i.setAttribute("class",n.resultItem.className),i.setAttribute("role","option"),i.innerHTML=e.match,n.resultItem.content&&n.resultItem.content(e,i),i}(s,o,e);a.addEventListener("click",(function(r){var a={event:r,matches:n,input:t.input,query:t.query,results:t.results,selection:i(i({},s),{},{index:o})};e.onSelection&&e.onSelection(a)})),r.appendChild(a)},s=0;s=t.length&&(n=0),n<0&&(n=t.length-1),t[n].setAttribute("aria-selected","true"),e.selection.className&&t[n].classList.add(e.selection.className)},l=e.resultsList.navigation||function(t){var i=document.getElementById(e.resultsList.idName);i?(i=i.getElementsByTagName(e.resultItem.element),27===t.keyCode?(e.inputField.value="",a(e)):40===t.keyCode||9===t.keyCode?r(t,i,!0,e):38===t.keyCode||9===t.keyCode?r(t,i,!1,e):13===t.keyCode&&(t.preventDefault(),n>-1&&(i[n].click(),a(e)))):e.inputField.removeEventListener(u,l)};e.inputField.autoCompleteNavigate&&e.inputField.removeEventListener(u,e.inputField.autoCompleteNavigate),e.inputField.autoCompleteNavigate=l,e.inputField.addEventListener(u,l)},d=function(e,t){for(var n=[],i=function(i){var r=e.data.store[i],s=function(o){var s=(o?r[o]:r).toString();if(s){var a="function"==typeof e.searchEngine?e.searchEngine(t,s):function(e,t,n){var i=n.diacritics?t.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g,"").normalize("NFC"):t.toLowerCase();if("loose"===n.searchEngine){e=e.replace(/ /g,"");for(var r=[],o=0,s=0;s').concat(a,""):a,o++),r.push(a)}if(o===e.length)return r.join("")}else if(i.includes(e)){var l=new RegExp(e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"),"i");return e=l.exec(t),n.highlight.render?t.replace(e,'').concat(e,"")):t}}(t,s,e);a&&o?n.push({key:o,index:i,match:a,value:r}):a&&!o&&n.push({index:i,match:a,value:r})}};if(e.data.key){var a,l=o(e.data.key);try{for(l.s();!(a=l.n()).done;)s(a.value)}catch(e){l.e(e)}finally{l.f()}}else s()},r=0;r=e.threshold&&n.replace(/ /g,"").length}(t,e,o)?t.dataStore().then((function(e){try{return t.start(r,o),c.call(t)}catch(e){return i(e)}}),i):(a(t),c.call(t));function c(){return n()}}))}},{key:"init",value:function(){var e,t,n,i,r=this;(e=this).inputField.setAttribute("role","combobox"),e.inputField.setAttribute("aria-haspopup",!0),e.inputField.setAttribute("aria-expanded",!1),e.inputField.setAttribute("aria-controls",e.resultsList.idName),e.inputField.setAttribute("aria-autocomplete","both"),this.placeHolder&&this.inputField.setAttribute("placeholder",this.placeHolder),this.hook=(t=function(e){r.compose(e)},n=this.debounce,function(){var e=this,r=arguments;clearTimeout(i),i=setTimeout((function(){return t.apply(e,r)}),n)}),this.trigger.event.forEach((function(e){r.inputField.removeEventListener(e,r.hook),r.inputField.addEventListener(e,r.hook)})),s(this.inputField,null,"init")}},{key:"preInit",value:function(){var e=this;new MutationObserver((function(t,n){var i,r=o(t);try{for(r.s();!(i=r.n()).done;)i.value,e.inputField&&(n.disconnect(),e.init())}catch(e){r.e(e)}finally{r.f()}})).observe(document,{childList:!0,subtree:!0})}},{key:"unInit",value:function(){this.inputField.removeEventListener("input",this.hook),s(this.inputField,null,"unInit")}}])&&e(n.prototype,i),r&&e(n,r),t}()},"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).autoComplete=t(); +var e,t;e=this,t=function(){"use strict";function e(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,i=new Array(t);n=e.length?{done:!0}:{done:!1,value:e[i++]}},e:function(e){throw e},f:s}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,a=!0,l=!1;return{s:function(){n=e[Symbol.iterator]()},n:function(){var e=n.next();return a=e.done,e},e:function(e){l=!0,o=e},f:function(){try{a||null==n.return||n.return()}finally{if(l)throw o}}}}var o=function(e,t,n){e.dispatchEvent(new CustomEvent(n,{bubbles:!0,detail:t,cancelable:!0}))},a=function(e,t){var n=document.getElementById(e.resultsList.idName);n&&t!==e.inputField&&(n.remove(),e.inputField.removeAttribute("aria-activedescendant"),e.inputField.setAttribute("aria-expanded",!1),o(e.inputField,null,"close"))},l=function(e,t,n){var r=document.getElementById(e.resultsList.idName);if(r?r.innerHTML="":r=function(e){var t=document.createElement(e.resultsList.element);return t.setAttribute("id",e.resultsList.idName),t.setAttribute("class",e.resultsList.className),t.setAttribute("role","listbox"),t.setAttribute("tabindex","-1"),e.resultsList.container&&e.resultsList.container(t),("string"==typeof e.resultsList.destination?document.querySelector(e.resultsList.destination):e.resultsList.destination()).insertAdjacentElement(e.resultsList.position,t),t}(e),e.inputField.setAttribute("aria-expanded",!0),n.length)for(var s=function(s){var o=t.results[s],a=function(e,t,n){var i=document.createElement(n.resultItem.element);return i.setAttribute("id","".concat(n.resultItem.idName,"_").concat(t)),i.setAttribute("class",n.resultItem.className),i.setAttribute("role","option"),i.innerHTML=e.match,n.resultItem.content&&n.resultItem.content(e,i),i}(o,s,e);a.addEventListener("click",(function(r){var a={event:r,matches:n,input:t.input,query:t.query,results:t.results,selection:i(i({},o),{},{index:s})};e.onSelection&&e.onSelection(a)})),r.appendChild(a)},o=0;o=t.length&&(n=0),n<0&&(n=t.length-1),t[n].setAttribute("aria-selected","true"),e.resultItem.selected.className&&t[n].classList.add(e.resultItem.selected.className)},l=e.resultsList.navigation||function(t){var i=document.getElementById(e.resultsList.idName);if(i)switch(i=i.getElementsByTagName(e.resultItem.element),t.keyCode){case 27:e.inputField.value="",a(e);break;case 9:case 40:r(t,i,!0);break;case 38:r(t,i,!1);break;case 13:t.preventDefault(),n>-1&&(i[n].click(),a(e))}else e.inputField.removeEventListener(u,l)};e.inputField.autoCompleteNavigate&&e.inputField.removeEventListener(u,e.inputField.autoCompleteNavigate),e.inputField.autoCompleteNavigate=l,e.inputField.addEventListener(u,l)},d=function(e,t){for(var n=[],i=function(i){var r=e.data.store[i],o=function(s){var o=(s?r[s]:r).toString();if(o){var a="function"==typeof e.searchEngine?e.searchEngine(t,o):function(e,t,n){var i=n.diacritics?t.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g,"").normalize("NFC"):t.toLowerCase();if("loose"===n.searchEngine){e=e.replace(/ /g,"");for(var r=[],s=0,o=0;o').concat(a,""):a,s++),r.push(a)}if(s===e.length)return r.join("")}else if(i.includes(e)){var l=new RegExp(e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"),"i");return e=l.exec(t),n.resultItem.highlight.render?t.replace(e,'').concat(e,"")):t}}(t,o,e);a&&s?n.push({key:s,index:i,match:a,value:r}):a&&!s&&n.push({index:i,match:a,value:r})}};if(e.data.key){var a,l=s(e.data.key);try{for(l.s();!(a=l.n()).done;)o(a.value)}catch(e){l.e(e)}finally{l.f()}}else o()},r=0;r=e.threshold&&n.replace(/ /g,"").length}(t,e,s)?t.dataStore().then((function(e){try{return t.start(r,s),c.call(t)}catch(e){return i(e)}}),i):(a(t),c.call(t));function c(){return n()}}))}},{key:"init",value:function(){var e,t,n,i,r=this;(e=this).inputField.setAttribute("role","combobox"),e.inputField.setAttribute("aria-haspopup",!0),e.inputField.setAttribute("aria-expanded",!1),e.inputField.setAttribute("aria-controls",e.resultsList.idName),e.inputField.setAttribute("aria-autocomplete","both"),this.placeHolder&&this.inputField.setAttribute("placeholder",this.placeHolder),this.hook=(t=function(e){r.compose(e)},n=this.debounce,function(){var e=this,r=arguments;clearTimeout(i),i=setTimeout((function(){return t.apply(e,r)}),n)}),this.trigger.event.forEach((function(e){r.inputField.removeEventListener(e,r.hook),r.inputField.addEventListener(e,r.hook)})),o(this.inputField,null,"init")}},{key:"preInit",value:function(){var e=this;new MutationObserver((function(t,n){var i,r=s(t);try{for(r.s();!(i=r.n()).done;)i.value,e.inputField&&(n.disconnect(),e.init())}catch(e){r.e(e)}finally{r.f()}})).observe(document,{childList:!0,subtree:!0})}},{key:"unInit",value:function(){this.inputField.removeEventListener("input",this.hook),o(this.inputField,null,"unInit")}}])&&e(n.prototype,i),r&&e(n,r),t}()},"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).autoComplete=t(); diff --git a/dist/js/autoComplete.min.js.gz b/dist/js/autoComplete.min.js.gz index 8680b983..bbcbff02 100644 Binary files a/dist/js/autoComplete.min.js.gz and b/dist/js/autoComplete.min.js.gz differ diff --git a/dist/js/index.js b/dist/js/index.js index 2a19fe41..5e0b7e72 100644 --- a/dist/js/index.js +++ b/dist/js/index.js @@ -1,67 +1,18 @@ -// // autoComplete.js input eventListener on ready event after successful connection -// document.querySelector("#autoComplete").addEventListener("ready", function (event) { -// console.log(event); -// }); -// autoComplete.js input eventListener on initialization event -document.querySelector("#autoComplete").addEventListener("init", function (event) { - console.log(event); -}); -// // autoComplete.js input eventListener on input event -// document.querySelector("#autoComplete").addEventListener("input", function (event) { -// console.log(event); -// }); -// // autoComplete.js input eventListener on data response event -// document.querySelector("#autoComplete").addEventListener("fetch", function (event) { -// console.log(event.detail); -// }); -// // autoComplete.js input eventListener on search results event -// document.querySelector("#autoComplete").addEventListener("results", function (event) { -// console.log(event.detail); -// }); -// // autoComplete.js input eventListener on results list opening event -// document.querySelector("#autoComplete").addEventListener("open", function (event) { -// console.log(event); -// }); -// // autoComplete.js input eventListener on results list navigation -// document.querySelector("#autoComplete").addEventListener("navigate", function (event) { -// console.log(event.detail); -// }); -// autoComplete.js input eventListener on results list navigation -document.querySelector("#autoComplete").addEventListener("close", function (event) { - console.log(event); -}); -// // autoComplete.js input eventListener on post un-initialization event -// document.querySelector("#autoComplete").addEventListener("unInit", function (event) { -// console.log(event); -// }); - // The autoComplete.js Engine instance creator const autoCompleteJS = new autoComplete({ - name: "food & drinks", - selector: "#autoComplete", - observer: false, data: { src: async () => { // Loading placeholder text document.querySelector("#autoComplete").setAttribute("placeholder", "Loading..."); - - if (!JSON.parse(localStorage.getItem("acData"))) { - // Fetch External Data Source - const source = await fetch("./db/generic.json"); - const data = await source.json(); - // Post Loading placeholder text - document.querySelector("#autoComplete").setAttribute("placeholder", autoCompleteJS.placeHolder); - // Returns Fetched data - return data; - } - + // Fetch External Data Source + const source = await fetch("./db/generic.json"); + const data = await source.json(); // Post Loading placeholder text document.querySelector("#autoComplete").setAttribute("placeholder", autoCompleteJS.placeHolder); - - return JSON.parse(localStorage.getItem("acData")); + // Returns Fetched data + return data; }, key: ["food", "cities", "animals"], - cache: true, results: (list) => { // Filter duplicates const filteredResults = Array.from(new Set(list.map((value) => value.match))).map((food) => { @@ -73,45 +24,41 @@ const autoCompleteJS = new autoComplete({ }, searchEngine: "strict", placeHolder: "Search for Food & Drinks!", - maxResults: 5, - sort: (a, b) => { - if (a.match < b.match) return -1; - if (a.match > b.match) return 1; - return 0; - }, - highlight: { - render: true, - }, debounce: 100, threshold: 1, trigger: { event: ["input", "focus"], }, + resultsList: { + noResults: (list, query) => { + // No Results List Message + const message = document.createElement("li"); + message.setAttribute("class", "no_result"); + message.setAttribute("tabindex", "1"); + message.innerHTML = `Found No Results for "${query}"`; + list.appendChild(message); + }, + }, resultItem: { content: (data, element) => { // Modify Results Item Style element.style = "display: flex; justify-content: space-between;"; // Modify Results Item Content element.innerHTML = ` - - ${data.match} - - - ${data.key} - `; + + ${data.match} + + + ${data.key} + `; + }, + highlight: { + render: true, }, }, - noResults: (list, query) => { - // No Results List Message - const message = document.createElement("li"); - message.setAttribute("class", "no_result"); - message.setAttribute("tabindex", "1"); - message.innerHTML = `Found No Results for "${query}"`; - list.appendChild(message); - }, - feedback: (data) => { - console.log(data); - }, + // feedback: (data) => { + // console.log(data); + // }, onSelection: (feedback) => { document.querySelector("#autoComplete").blur(); // Prepare User's Selected Value diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 2ee3335c..00000000 --- a/docs/README.md +++ /dev/null @@ -1,444 +0,0 @@ -# Introduction - -[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) -[![GitHub package.json version](https://img.shields.io/github/package-json/v/TarekRaafat/autoComplete.js)](https://badge.fury.io/gh/tarekraafat%2FautoComplete.js) -[![npm](https://img.shields.io/npm/v/@tarekraafat/autocomplete.js)](https://badge.fury.io/js/%40tarekraafat%2Fautocomplete.js) -![GitHub top language](https://img.shields.io/github/languages/top/TarekRaafat/autoComplete.js?color=yellow) -![\[Zero Dependencies\]()](https://img.shields.io/badge/Dependencies-0-blue.svg) -![\[Size\]()](https://img.shields.io/badge/Size-10%20KB-green.svg) -![Maintained](https://img.shields.io/badge/Maintained%3F-yes-success) -[![](https://data.jsdelivr.com/v1/package/npm/@tarekraafat/autocomplete.js/badge)](https://www.jsdelivr.com/package/npm/@tarekraafat/autocomplete.js) -![npm](https://img.shields.io/npm/dm/@tarekraafat/autocomplete.js?label=npm) -[![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.svg?v=103)](https://github.com/TarekRaafat/autoComplete.js) - -
-
- -

autoComplete.js

- -> Simple autocomplete pure vanilla Javascript library. :rocket: Live Demo **v9.0** - -autoComplete.js is a simple pure vanilla Javascript library that's progressively designed for speed, high versatility and seamless integration with a wide range of projects & systems, made for users and developers in mind. - -## Features - -- Pure Vanilla Javascript -- Zero Dependencies -- Simple & Easy to use -- Extremely Lightweight -- Blazing Fast -- Versatile -- Hackable & highly customizable - -[![autoComplete.js Code Example](./img/autoComplete.init.png "autoComplete.js Code Example")](https://codepen.io/tarekraafat/pen/rQopdW?editors=0010) - -## 1. Get Started - -### Clone: - -- Clone autoComplete.js to your local machine - -```shell -git clone https://github.com/TarekRaafat/autoComplete.js.git -``` - -### Setup: - -1. Install Dependencies - -```shell -npm i -``` - -2. For Development - -```shell -npm run dev -``` - -3. Build Production Package - -```shell -npm run build -``` - -### Installation: - -- jsDelivr Logo CDN - -`CSS` - -```html - -``` - -`JS` - -```html - -``` - -- cdnjs Logo CDN - -`CSS` - -```html - -``` - -`JS` - -```html - -``` - -- unpkg Logo CDN - -`CSS` - -```html - -``` - -`JS` - -```html - -``` - -- HTML Logo HTML Local load - -```html - -``` - -- HTML Logo HTML Local load - ES6 module `(Use with Import)` - -```html - -``` - -- Javascript Logo Import module ES6 - -```js -import autoComplete from "./autoComplete"; -``` - -- install `(Node Package Manager)` - -```shell -npm i @tarekraafat/autocomplete.js -``` - -- Yarn Logo install `(Javascript Package Manager)` - -```shell -yarn add @tarekraafat/autocomplete.js -``` - -- Node.js Node.js - -```js -const autoComplete = require("@tarekraafat/autocomplete.js/dist/js/autoComplete"); -``` - -### How to use: - -> HTML file - -1. Place the `CSS` stylesheet inside the `HEAD` tag - -```html - -OR - -``` - -2. Assign the default `id` value `"autoComplete"` to the desired input field or use any custom `id/class` and configure the API selector accordingly in `Step 4` - -```html - -``` - -3. Place autoComplete `JS` file & the custom `JS` file at the bottom `BODY` tag - -```html - - -OR - - -``` - -> Custom JS file - -4. Create new instance of autoComplete engine and configure it `NOT all API configurations are required` - -```js -new autoComplete({ - data: { // Data src [Array, Function, Async] | (REQUIRED) - src: async () => { - // API key token - const token = "this_is_the_API_token_number"; - // User search query - const query = document.querySelector("#autoComplete").value; - // Fetch External Data Source - const source = await fetch(`https://www.food2fork.com/api/search?key=${token}&q=${query}`); - // Format data into JSON - const data = await source.json(); - // Return Fetched data - return data.recipes; - }, - key: ["title"], - cache: false - }, - query: { // Query Interceptor | (Optional) - manipulate: (query) => { - return query.replace("pizza", "burger"); - } - }, - sort: (a, b) => { // Sort rendered results ascendingly | (Optional) - if (a.match < b.match) return -1; - if (a.match > b.match) return 1; - return 0; - }, - placeHolder: "Food & Drinks...", // Place Holder text | (Optional) - selector: "#autoComplete", // Input field selector | (Optional) - observer: true, // Input field observer | (Optional) - threshold: 3, // Min. Chars length to start Engine | (Optional) - debounce: 300, // Post duration for engine to start | (Optional) - searchEngine: "strict", // Search Engine type/mode | (Optional) - resultsList: { // Rendered results list object | (Optional) - container: source => { - source.setAttribute("id", "food_list"); - }, - destination: "#autoComplete", - position: "afterend", - element: "ul" - }, - maxResults: 5, // Max. number of rendered results | (Optional) - highlight: { - render: true, // Highlight matching results | (Optional) - } - resultItem: { // Rendered result item | (Optional) - content: (data, source) => { - source.innerHTML = data.match; - }, - element: "li" - }, - noResults: (dataFeedback, generateList) => { - // Generate autoComplete List - generateList(autoCompleteJS, dataFeedback, dataFeedback.results); - // No Results List Item - const result = document.createElement("li"); - result.setAttribute("class", "no_result"); - result.setAttribute("tabindex", "1"); - result.innerHTML = `Found No Results for "${dataFeedback.query}"`; - document.querySelector(`#${autoCompleteJS.resultsList.idName}`).appendChild(result); - }, - onSelection: feedback => { // Action script onSelection event | (Optional) - console.log(feedback.selection.value.image_url); - } -}); -``` - -### API Configuration: - -
- -| Keys | Description | Values | Default | -| -------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `data` | Data Source, Data Key, Data Caching & Data Results | `Object` with 4 methods
**1- src**:
- `Array` of `Strings` / `Objects`
**OR**
- `Function` ( ) => `Array` of `Strings` / `Objects`
**2- key**:
- `Array` of `Strings`
**Required** if `src` is `Object`, for search to point to desired `keys`
**3- Cache**:
- `true` for static data `src`
- `false` for dynamic data `src` "API" with queries
**4- Results**:
- `Function` (resultsList) => `Array` of `Strings` / `Objects` | Data `src` | -| `trigger` | Engine event & condition trigger | `Object` with 2 methods
**1- event**:
- `Array` of event name `Strings`
**2- condition**:
- `Boolean`
**OR**
- `Function` (even, query) => `Boolean` | 1- event: `["input"]`
2- condition:
`Function` => (query.length > this.threshold && query !== " ")` | -| `query` | Query Interceptor | `Object` with 1 method
1- manipulate: `Function` (inputValue) => `String` | `Raw` Input Value | -| `sort` | Sort rendered results | **-** `Function` (firstResult, secondResult) => { ... } | `false` **(Random Results)** | -| `placeHolder` | Place Holder text | **-** `String` | Blank / Empty | -| `selector` | Input field selector | **-** `String` `id`/`class`
**OR**
**-** `Function` ( ) => `document.querySelector("")` | `"#autoComplete"` | -| `observer` | Input field observer | **-** `Boolean` | `false` | -| `threshold` | Minimum characters length before engine starts rendering results | **-** `Number` | `1` | -| `debounce` | Minimum duration after typing idle state for engine to kick in | **-** `Number`
In milliseconds value | `0` | -| `searchEngine` | Search Engine Type/Mode | **-** `"strict"` lowerCase string
**OR**
**-** `"loose"` lowerCase string
**OR**
**-** customEngine `Function` (query, record) => `each match individually` | `"strict"` | -| `diacritics` | Search Engine Diacritics handler | **-** `Boolean` | `false` | -| `resultsList` | Rendered results list destination, position, element & navigation | `Object` with 8 methods
1- render: `Boolean`
2- container:
`Function` (source) => { ... }
3- destination:
**-** `String` `(id/class/tag)` value
**OR**
**-** `Function` ( ) => `document.querySelector("")`
4- position:
`"beforebegin"`, `"afterbegin"`, `"beforeend"`, `"afterend"` lowerCase string
5- element:
- `String` tag `(ul/span/div/etc..)` value
6- idName: `String`
7- className: `String`
8- navigation: `Function` (event, input, resListElement, onSelection, resListData) => { ... } | 1- render: `true`
2- container: (source) => { ... }
3- destination: `"#autoComplete"`
4- position: `"afterend"`
5- element: `"ul"`
6- idName: `"autoComplete_list"`
7- className: `"autoComplete_list"`
8- navigation: `default` | -| `resultItem` | Rendered result Item content & element | `Object` with 4 methods
1- content:
**-** `Function` (data, source) => { ... }
**-** `data.match` has to be used for **Highlighted** result
2- element:
- `String` tag `(li/span/div/etc..)`
3- idName: `String`
4- className: `String` | 1- content: `(data, source)` => { ... }
2- element: `"li"`
3- idName: `"autoComplete_result"`
4- className: `"autoComplete_result"` | -| `noResults` | Action script on noResults found | **-** `Function` (list, query) => { ... } | No Action | -| `selection` | Format selected result item | `Object` with 1 method
1- className: `String` | 1- className: `autoComplete_selected` | -| `highlight` | Highlight matching results | `Object` with 2 methods
1- render: `Boolean`
2- className: `String` | 1- render: `false`
2- className: `autoComplete_highlighted` | -| `maxResults` | Maximum number of displayed results | **-** `Number` (Integer) | `5` | -| `feedback` | Action script on dataFeedback event | **-** `Function` (data) => { ... } | No Action | -| `onSelection` | Action script onSelection event | **-** `Function` (feedback) => { ... } | No Action | - -1. That's it, you're ready to go! - -* * * - -### Life Cycle Events: - -1. `init`: Fires after "autoComplete.js" engine is initialized -2. `fetch`: Fires after fetching data is complete -3. `input`: Fires on every user input -4. `results`: Fires after search is done and matching results are ready -5. `open`: Fires after opening the results list -6. `navigate`: Fires on every "resultsList" navigation interaction -7. `close`: Fires on "resultsList" close -8. `unInit`: Fires after "autoComplete.js" engine is un-initialized - -* * * - -## 2. Examples - -- Live working [Demo] - - -- Try it on [CodePen Logo](https://codepen.io/tarekraafat/pen/rQopdW?editors=0010) - -[demo]: https://tarekraafat.github.io/autoComplete.js/demo/ - -- Download [Demo] files locally from `/dist` folder - -* * * - -## 3. Third-Party Plugins - -- [Contao autoComplete.js Bundle](https://github.com/heimrichhannot/contao-autocompletejs-bundle) by [@heimrichhannot](https://github.com/heimrichhannot) - -* * * - -## 4. Support - -For general questions about autoComplete.js, tweet at [@TarekRaafat]. - -For technical questions, you should post a question on [Stack Overflow] and tag -it with [autoComplete.js][so tag]. - - - -[stack overflow]: https://stackoverflow.com/ - -[@tarekraafat]: https://twitter.com/TarekRaafat - -[so tag]: https://stackoverflow.com/questions/tagged/autoComplete.js - -* * * - -## 5. Browsers Support - -| [IE / Edge](http://godban.github.io/browsers-support-badges/)IE / Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [iOS Safari](http://godban.github.io/browsers-support-badges/)
iOS Safari | [Samsung](http://godban.github.io/browsers-support-badges/)
Samsung | [Opera](http://godban.github.io/browsers-support-badges/)
Opera | [Opera Mini](http://godban.github.io/browsers-support-badges/)
Opera Mini | [Electron](http://godban.github.io/browsers-support-badges/)
Electron | -| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Edge | last version | last version | last version | last version | last version | last version | last version | last version | - -* * * - -## 6. What's New in v9.0? - -Check out Releases Information :sparkles: - -* * * - -## 7. Roadmap - -### Functionality: - -- [x] Add support for different types of data source - - [x] Function - - [x] JSON - - [x] Array of Object - - [x] External data source via Promises & Async/Await function -- [x] Multi-keyword Search -- [x] Different types/modes of Search Logic -- [x] Choose different results render destination & position -- [x] Sort rendered results -- [x] Results list Keyboard `ARROW` or `TAB` Navigation -- [x] Enhance error Handling (Ongoing) -- [x] Number of matching results -- [x] Fetching dynamically External API data source -- [x] Multiple searchable `keys` for data `src` -- [x] Event emitter on input field events -- [x] Handling large data sets -- [x] Event emitter fires on cleared empty input field state -- [x] `Query` Interception & Manipulation -- [x] Improve `Promise` usage for external data source handling -- [x] Add support for `Diacritics` -- [x] Input field Observer -- [ ] Automatic deep search over all keys in multiple nested object data source - -### Usability: - -- [x] Avail Gzip files options -- [x] Comprehensive data feedback on user selection -- [x] Dynamic input field selector -- [x] Minimum characters length before results start getting rendered for more focused results -- [x] No matches found response & text -- [x] API for Rendered result item customization -- [x] API for Rendered results list customization -- [x] Capability for multiple instances -- [x] Render `results` in default case -- [x] Render `resultsList` & `resultItem` in different/custom elements -- [x] HTML elements `ContentEditable` Input Support -- [x] Serve results without rendering list through `resultsList.render` API -- [x] Custom Search Engine Capability -- [x] `ShadowDom` Support -- [x] API support for `customNavigation` -- [x] API support for `customEventTriggers` & `customTriggerConditions` -- [x] Better `resultsList` navigation [Without loosing cursor] -- [x] Add event emitters for navigation -- [x] Life Cycle Events -- [ ] Add more use examples & cases of the library to the documentation -- [ ] Better code compression / optimization for the library to squeeze it back under `[5kb]` - -### Plugins: - -- [ ] Recent / Most Searches -- [ ] Inline Suggestions -- [ ] Input Tags -- [ ] Virtual Scrolling -- [ ] Results List Category Separator -- [ ] `IndexedDB` for large data sets handling & offline usage -- [ ] Themes / Styles & Interactions - -### Styles: - -- [x] autoComplete.js default style -- [x] Neutral style [01] -- [x] Light style [02] - -### Reported Issues: - -- [ ] Duplicated results when using multiple data source `keys` - -* * * - -## 8. Contribution - -> Contributions are always more than welcome! - -If you have any ideas, just [open an issue](https://github.com/TarekRaafat/autoComplete.js/issues) and tell me what you think. - -- Please fork the repository and make changes as you'd like. - Pull requests are warmly welcome. - -> If you'd like to contribute: - -1. Fork it () -2. Create your feature branch (`git checkout -b feature/fooBar`) -3. Commit your changes (`git commit -am 'Add some fooBar'`) -4. Push to the branch (`git push origin feature/fooBar`) -5. Create a new Pull Request - -* * * - -## 9. Author - -**Tarek Raafat** - -- Email: tarek.m.raafat@gmail.com -- Website: -- Github: - -Distributed under the Apache 2.0 license. See `Apache 2.0` for more information. - -* * * - -## 10. License - -Apache 2.0 Β© [Tarek Raafat](http://www.tarekraafat.com) diff --git a/docs/_404.md b/docs/_404.md new file mode 100644 index 00000000..7157eef3 --- /dev/null +++ b/docs/_404.md @@ -0,0 +1,5 @@ +
+ +# Page not found + +
\ No newline at end of file diff --git a/docs/_coverpage.md b/docs/_coverpage.md deleted file mode 100644 index 6815415c..00000000 --- a/docs/_coverpage.md +++ /dev/null @@ -1,22 +0,0 @@ - - autoComplete.js Logo - - -> Simple autocomplete pure vanilla Javascript library. Live Demo **v9.0** - -autoComplete.js is a simple pure vanilla Javascript library that's progressively designed for speed,
high versatility and seamless integration with a wide range of projects & systems. - -autoComplete.js - Simple autocomplete pure vanilla Javascript library. | Product Hunt Embed - -
- -
- -
- - - -[GitHub](https://github.com/TarekRaafat/autoComplete.js) -[Get Started](#introduction) - -![color](#fff) diff --git a/docs/_sidebar.md b/docs/_sidebar.md new file mode 100644 index 00000000..6128a73f --- /dev/null +++ b/docs/_sidebar.md @@ -0,0 +1,17 @@ +- [
Introduction](/ "autoComplete.js - Vanilla Javascript library") +- [
Getting Started
](getting-started.md "Getting Started - Documentation | autoComplete.js") +- + - [
Installation](installation.md "Installation | autoComplete.js") + - [
Usage](usage.md "Usage | autoComplete.js") + - [
Configuration](configuration.md "Configuration | autoComplete.js") + - [
Playground](playground.md "Playground | autoComplete.js") +-
Extras
+- + - [
Plugins](plugins.md "Plugins | autoComplete.js") + - [
Browser Support](browsers-support.md "Browser Support | autoComplete.js") + -
How-to Guides (Coming Soon)
+-
References
+- + - [
Support](support.md "Support | autoComplete.js") + - [
Releases](releases.md "Releases | autoComplete.js") + - [
Contributions](contributions.md "Contributions | autoComplete.js") diff --git a/docs/assets/fonts/prestashop-icon-font.eot b/docs/assets/fonts/prestashop-icon-font.eot new file mode 100644 index 00000000..41ced916 Binary files /dev/null and b/docs/assets/fonts/prestashop-icon-font.eot differ diff --git a/docs/assets/fonts/prestashop-icon-font.ttf b/docs/assets/fonts/prestashop-icon-font.ttf new file mode 100644 index 00000000..7074370b Binary files /dev/null and b/docs/assets/fonts/prestashop-icon-font.ttf differ diff --git a/docs/assets/fonts/prestashop-icon-font.woff b/docs/assets/fonts/prestashop-icon-font.woff new file mode 100644 index 00000000..5db97d81 Binary files /dev/null and b/docs/assets/fonts/prestashop-icon-font.woff differ diff --git a/docs/assets/ps-icon-pack.min.css b/docs/assets/ps-icon-pack.min.css new file mode 100644 index 00000000..a06e3326 --- /dev/null +++ b/docs/assets/ps-icon-pack.min.css @@ -0,0 +1,408 @@ +@charset "UTF-8"; +[class*=" ps-icon-"]:before, [class^=ps-icon-]:before, [data-ps-icon]:before { + font-family: prestashop-icon-font !important; + font-style: normal !important; + font-weight: 400 !important; + font-variant: normal !important; + text-transform: none !important; + speak: none; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale +} + +.ps-icon { + display: inline-block; + vertical-align: middle; + position: relative; + top: 1px; + font-size: 18px; + margin-right: 5px; +} + +@font-face { + font-family: prestashop-icon-font; + src: url(fonts/prestashop-icon-font.eot); + src: url(fonts/prestashop-icon-font.eot?#iefix) format("embedded-opentype"), url(fonts/prestashop-icon-font.woff) format("woff"), url(fonts/prestashop-icon-font.ttf) format("truetype"), url(fonts/prestashop-icon-font.svg#prestashop-icon-font) format("svg"); + font-weight: 400; + font-style: normal +} + +[data-ps-icon]:before { + content: attr(data-ps-icon) +} + +.ps-icon-aim:before { + content: "a" +} + +.ps-icon-arto:before { + content: "b" +} + +.ps-icon-aws:before { + content: "c" +} + +.ps-icon-baidu:before { + content: "d" +} + +.ps-icon-basecamp:before { + content: "e" +} + +.ps-icon-bebo:before { + content: "f" +} + +.ps-icon-behance:before { + content: "g" +} + +.ps-icon-bing:before { + content: "h" +} + +.ps-icon-blip:before { + content: "i" +} + +.ps-icon-blogger:before { + content: "j" +} + +.ps-icon-bnter:before { + content: "k" +} + +.ps-icon-brightkite:before { + content: "l" +} + +.ps-icon-cinch:before { + content: "m" +} + +.ps-icon-cloudapp:before { + content: "n" +} + +.ps-icon-coroflot:before { + content: "o" +} + +.ps-icon-creative-commons:before { + content: "p" +} + +.ps-icon-dailybooth:before { + content: "q" +} + +.ps-icon-delicious:before { + content: "r" +} + +.ps-icon-designbump:before { + content: "s" +} + +.ps-icon-designfloat:before { + content: "t" +} + +.ps-icon-designmoo:before { + content: "u" +} + +.ps-icon-deviantart:before { + content: "v" +} + +.ps-icon-digg:before { + content: "w" +} + +.ps-icon-digg-alt:before { + content: "x" +} + +.ps-icon-diigo:before { + content: "y" +} + +.ps-icon-dribbble:before { + content: "z" +} + +.ps-icon-dropbox:before { + content: "A" +} + +.ps-icon-drupal:before { + content: "B" +} + +.ps-icon-dzone:before { + content: "C" +} + +.ps-icon-ebay:before { + content: "D" +} + +.ps-icon-ember:before { + content: "E" +} + +.ps-icon-etsy:before { + content: "F" +} + +.ps-icon-evernote:before { + content: "G" +} + +.ps-icon-facebook:before { + content: "H" +} + +.ps-icon-facebook-alt:before { + content: "I" +} + +.ps-icon-facebook-places:before { + content: "J" +} + +.ps-icon-facto:before { + content: "K" +} + +.ps-icon-feedburner:before { + content: "L" +} + +.ps-icon-flickr:before { + content: "M" +} + +.ps-icon-folkd:before { + content: "N" +} + +.ps-icon-formspring:before { + content: "O" +} + +.ps-icon-forrst:before { + content: "P" +} + +.ps-icon-foursquare:before { + content: "Q" +} + +.ps-icon-friendfeed:before { + content: "R" +} + +.ps-icon-friendster:before { + content: "S" +} + +.ps-icon-gdgt:before { + content: "T" +} + +.ps-icon-github:before { + content: "U" +} + +.ps-icon-github-alt:before { + content: "V" +} + +.ps-icon-goodreads:before { + content: "W" +} + +.ps-icon-google:before { + content: "X" +} + +.ps-icon-google-buzz:before { + content: "Y" +} + +.ps-icon-google-talk:before { + content: "Z" +} + +.ps-icon-gowalla:before { + content: "0" +} + +.ps-icon-gowalla-alt:before { + content: "1" +} + +.ps-icon-grooveshark:before { + content: "2" +} + +.ps-icon-hacker-news:before { + content: "3" +} + +.ps-icon-hi5:before { + content: "4" +} + +.ps-icon-hype-machine:before { + content: "5" +} + +.ps-icon-hyves:before { + content: "6" +} + +.ps-icon-icq:before { + content: "7" +} + +.ps-icon-identi:before { + content: "8" +} + +.ps-icon-instapaper:before { + content: "9" +} + +.ps-icon-itunes:before { + content: "!" +} + +.ps-icon-kik:before { + content: "\"" +} + +.ps-icon-krop:before { + content: "#" +} + +.ps-icon-last:before { + content: "$" +} + +.ps-icon-linkedin:before { + content: "%" +} + +.ps-icon-linkedin-alt:before { + content: "&" +} + +.ps-icon-livejournal:before { + content: "'" +} + +.ps-icon-lovedsgn:before { + content: "(" +} + +.ps-icon-meetup:before { + content: ")" +} + +.ps-icon-metacafe:before { + content: "*" +} + +.ps-icon-ming:before { + content: "+" +} + +.ps-icon-mister-wong:before { + content: "," +} + +.ps-icon-mixx:before { + content: "-" +} + +.ps-icon-mixx-alt:before { + content: "." +} + +.ps-icon-mobileme:before { + content: "/" +} + +.ps-icon-msn-messenger:before { + content: ":" +} + +.ps-icon-myspace:before { + content: ";" +} + +.ps-icon-myspace-alt:before { + content: "<" +} + +.ps-icon-newsvine:before { + content: "=" +} + +.ps-icon-official:before { + content: ">" +} + +.ps-icon-openid:before { + content: "?" +} + +.ps-icon-orkut:before { + content: "@" +} + +.ps-icon-pandora:before { + content: "[" +} + +.ps-icon-path:before { + content: "]" +} + +.ps-icon-paypal:before { + content: "^" +} + +.ps-icon-photobucket:before { + content: "_" +} + +.ps-icon-picasa:before { + content: "`" +} + +.ps-icon-picassa:before { + content: "{" +} + +.ps-icon-pinboard:before { + content: "|" +} + +.ps-icon-ping:before { + content: "}" +} + +.ps-icon-pingchat:before { + content: "~" +} + +.ps-icon-playstation:before { + content: "\\"}.ps-icon-plixi:before{content:" \e000 "}.ps-icon-plurk:before{content:" \e001 "}.ps-icon-podcast:before{content:" \e002 "}.ps-icon-posterous:before{content:" \e003 "}.ps-icon-qik:before{content:" \e004 "}.ps-icon-quik:before{content:" \e005 "}.ps-icon-quora:before{content:" \e006 "}.ps-icon-rdio:before{content:" \e007 "}.ps-icon-readernaut:before{content:" \e008 "}.ps-icon-reddit:before{content:" \e009 "}.ps-icon-retweet:before{content:" \e00a "}.ps-icon-robo:before{content:" \e00b "}.ps-icon-rss:before{content:" \e00c "}.ps-icon-scribd:before{content:" \e00d "}.ps-icon-sharethis:before{content:" \e00e "}.ps-icon-simplenote:before{content:" \e00f "}.ps-icon-skype:before{content:" \e010 "}.ps-icon-slashdot:before{content:" \e011 "}.ps-icon-slideshare:before{content:" \e012 "}.ps-icon-smugmug:before{content:" \e013 "}.ps-icon-soundcloud:before{content:" \e014 "}.ps-icon-spotify:before{content:" \e015 "}.ps-icon-squarespace:before{content:" \e016 "}.ps-icon-squidoo:before{content:" \e017 "}.ps-icon-steam:before{content:" \e018 "}.ps-icon-stumbleupon:before{content:" \e019 "}.ps-icon-technorati:before{content:" \e01a "}.ps-icon-threewords:before{content:" \e01b "}.ps-icon-tribe:before{content:" \e01c "}.ps-icon-tripit:before{content:" \e01d "}.ps-icon-tumblr:before{content:" \e01e "}.ps-icon-twitter:before{content:" \e01f "}.ps-icon-twitter-alt:before{content:" \e020 "}.ps-icon-vcard:before{content:" \e021 "}.ps-icon-viddler:before{content:" \e022 "}.ps-icon-vimeo:before{content:" \e023 "}.ps-icon-virb:before{content:" \e024 "}.ps-icon-w3:before{content:" \e025 "}.ps-icon-whatsapp:before{content:" \e026 "}.ps-icon-wikipedia:before{content:" \e027 "}.ps-icon-windows:before{content:" \e028 "}.ps-icon-wists:before{content:" \e029 "}.ps-icon-wordpress:before{content:" \e02a "}.ps-icon-wordpress-alt:before{content:" \e02b "}.ps-icon-xing:before{content:" \e02c "}.ps-icon-yahoo:before{content:" \e02d "}.ps-icon-yahoo-buzz:before{content:" \e02e "}.ps-icon-yahoo-messenger:before{content:" \e02f "}.ps-icon-yelp:before{content:" \e030 "}.ps-icon-youtube:before{content:" \e031 "}.ps-icon-youtube-alt:before{content:" \e032 "}.ps-icon-zerply:before{content:" \e033 "}.ps-icon-zootool:before{content:" \e034 "}.ps-icon-zynga:before{content:" \e035 "}.ps-icon-aim-alt:before{content:" \e036 "}.ps-icon-amazon:before{content:" \e037 "}.ps-icon-app-store:before{content:" \e038 "}.ps-icon-apple:before{content:" \e039 "}.ps-icon-girl:before{content:" \e03a "}.ps-icon-girl-sad:before{content:" \e03b "}.ps-icon-girl-confused:before{content:" \e03c "}.ps-icon-bank-safe:before{content:" \e03d "}.ps-icon-shopping-cart:before{content:" \e03e "}.ps-icon-blaster:before{content:" \e03f "}.ps-icon-helm:before{content:" \e040 "}.ps-icon-boiled-egg:before{content:" \e041 "}.ps-icon-boiled-egg-finger:before{content:" \e042 "}.ps-icon-cart:before{content:" \e043 "}.ps-icon-coin:before{content:" \e044 "}.ps-icon-coins:before{content:" \e045 "}.ps-icon-couple:before{content:" \e046 "}.ps-icon-credit-card:before{content:" \e047 "}.ps-icon-crown:before{content:" \e048 "}.ps-icon-daft-punk:before{content:" \e049 "}.ps-icon-dollar-bill:before{content:" \e04a "}.ps-icon-dollars:before{content:" \e04b "}.ps-icon-music:before{content:" \e04c "}.ps-icon-headphones:before{content:" \e04d "}.ps-icon-headset:before{content:" \e04e "}.ps-icon-egg:before{content:" \e04f "}.ps-icon-fried-egg:before{content:" \e050 "}.ps-icon-euro-bill:before{content:" \e051 "}.ps-icon-extinguisher:before{content:" \e052 "}.ps-icon-fuck:before{content:" \e053 "}.ps-icon-full-screen:before{content:" \e054 "}.ps-icon-gamepad:before{content:" \e055 "}.ps-icon-girl-2:before{content:" \e056 "}.ps-icon-girl-angel:before{content:" \e057 "}.ps-icon-girl-angry:before{content:" \e058 "}.ps-icon-girl-big-smile:before{content:" \e059 "}.ps-icon-girl-cry:before{content:" \e05a "}.ps-icon-girl-flushed:before{content:" \e05b "}.ps-icon-girl-open-mouth:before{content:" \e05c "}.ps-icon-girl-sleep:before{content:" \e05d "}.ps-icon-girl-smile:before{content:" \e05e "}.ps-icon-girl-user:before{content:" \e05f "}.ps-icon-guy:before{content:" \e060 "}.ps-icon-guy-angel:before{content:" \e061 "}.ps-icon-guy-angry:before{content:" \e062 "}.ps-icon-guy-big-smile:before{content:" \e063 "}.ps-icon-guy-confused:before{content:" \e064 "}.ps-icon-guy-cry:before{content:" \e065 "}.ps-icon-guy-flushed:before{content:" \e066 "}.ps-icon-guy-happy:before{content:" \e067 "}.ps-icon-guy-o-mouth:before{content:" \e068 "}.ps-icon-girl-o-mouth:before{content:" \e069 "}.ps-icon-guy-open-mouth:before{content:" \e06a "}.ps-icon-guy-sad:before{content:" \e06b "}.ps-icon-guy-sleep:before{content:" \e06c "}.ps-icon-guy-smile:before{content:" \e06d "}.ps-icon-guy-user:before{content:" \e06e "}.ps-icon-guy-wrong:before{content:" \e06f "}.ps-icon-hand:before{content:" \e070 "}.ps-icon-hand-pointer-left:before{content:" \e071 "}.ps-icon-hand-pointer-right:before{content:" \e072 "}.ps-icon-hand-pointer-top:before{content:" \e073 "}.ps-icon-mayo-hotdog:before{content:" \e074 "}.ps-icon-hotdog:before{content:" \e075 "}.ps-icon-hungry:before{content:" \e076 "}.ps-icon-enlarge:before{content:" \e077 "}.ps-icon-laptop:before{content:" \e078 "}.ps-icon-mail:before{content:" \e079 "}.ps-icon-mail-back:before{content:" \e07a "}.ps-icon-mail-bill:before{content:" \e07b "}.ps-icon-mail-stamp:before{content:" \e07c "}.ps-icon-moon:before{content:" \e07d "}.ps-icon-music-score:before{content:" \e07e "}.ps-icon-open-padlock:before{content:" \e07f "}.ps-icon-organisation:before{content:" \e080 "}.ps-icon-padlock:before{content:" \e081 "}.ps-icon-paper-tablet:before{content:" \e082 "}.ps-icon-pdiddy:before{content:" \e083 "}.ps-icon-people-team:before{content:" \e084 "}.ps-icon-piggy-bank:before{content:" \e085 "}.ps-icon-piggy-bank-coins:before{content:" \e086 "}.ps-icon-power:before{content:" \e087 "}.ps-icon-printer:before{content:" \e088 "}.ps-icon-promo:before{content:" \e089 "}.ps-icon-puzzle:before{content:" \e08a "}.ps-icon-resize:before{content:" \e08b "}.ps-icon-road:before{content:" \e08c "}.ps-icon-rss-icon:before{content:" \e08d "}.ps-icon-safe:before{content:" \e08e "}.ps-icon-sale-tag:before{content:" \e08f "}.ps-icon-save:before{content:" \e090 "}.ps-icon-shield:before{content:" \e091 "}.ps-icon-store:before{content:" \e092 "}.ps-icon-sign:before{content:" \e093 "}.ps-icon-sreenshot:before{content:" \e094 "}.ps-icon-sun:before{content:" \e095 "}.ps-icon-cart-supermarket:before{content:" \e096 "}.ps-icon-tag:before{content:" \e097 "}.ps-icon-token:before{content:" \e098 "}.ps-icon-delete:before{content:" \e099 "}.ps-icon-user:before{content:" \e09a "}.ps-icon-wallet:before{content:" \e09b "}.ps-icon-watch:before{content:" \e09c "}.ps-icon-30-80:before{content:" \e09d "}.ps-icon-40-105:before{content:" \e09e "}.ps-icon-50-120:before{content:" \e09f "}.ps-icon-60-140:before{content:" \e0a0 "}.ps-icon-70-160:before{content:" \e0a1 "}.ps-icon-95-200:before{content:" \e0a2 "}.ps-icon-airplane:before{content:" \e0a3 "}.ps-icon-any-solvent:before{content:" \e0a4 "}.ps-icon-any-solvent-without-tetrachlorethylene:before{content:" \e0a5 "}.ps-icon-attachment:before{content:" \e0a6 "}.ps-icon-warning:before{content:" \e0a7 "}.ps-icon-barrel:before{content:" \e0a8 "}.ps-icon-bike:before{content:" \e0a9 "}.ps-icon-triangle:before{content:" \e0aa "}.ps-icon-broken-link:before{content:" \e0ab "}.ps-icon-bubble:before{content:" \e0ac "}.ps-icon-prison-school-bus:before{content:" \e0ad "}.ps-icon-car:before{content:" \e0ae "}.ps-icon-cocktail:before{content:" \e0af "}.ps-icon-do-not-bleach:before{content:" \e0b0 "}.ps-icon-do-not-dry:before{content:" \e0b1 "}.ps-icon-do-not-iron:before{content:" \e0b2 "}.ps-icon-do-not-wash:before{content:" \e0b3 "}.ps-icon-do-not-wring:before{content:" \e0b4 "}.ps-icon-double-arrow:before{content:" \e0b5 "}.ps-icon-drip-dry:before{content:" \e0b6 "}.ps-icon-drop:before{content:" \e0b7 "}.ps-icon-dry:before{content:" \e0b8 "}.ps-icon-dry-flat:before{content:" \e0b9 "}.ps-icon-dry-in-the-shade:before{content:" \e0ba "}.ps-icon-dry-normal-hight-heat:before{content:" \e0bb "}.ps-icon-dry-normal-low-heat:before{content:" \e0bc "}.ps-icon-heat:before{content:" \e0bd "}.ps-icon-dry-normal-no-heat:before{content:" \e0be "}.ps-icon-eject:before{content:" \e0bf "}.ps-icon-switch:before{content:" \e0c0 "}.ps-icon-film:before{content:" \e0c1 "}.ps-icon-apps:before{content:" \e0c2 "}.ps-icon-gun:before{content:" \e0c3 "}.ps-icon-hand-wash:before{content:" \e0c4 "}.ps-icon-disabled:before{content:" \e0c5 "}.ps-icon-hang-to-dry:before{content:" \e0c6 "}.ps-icon-hard-drive:before{content:" \e0c7 "}.ps-icon-hourglass:before{content:" \e0c8 "}.ps-icon-important:before{content:" \e0c9 "}.ps-icon-iron-any-temp:before{content:" \e0ca "}.ps-icon-justice:before{content:" \e0cb "}.ps-icon-keyboard:before{content:" \e0cc "}.ps-icon-link:before{content:" \e0cd "}.ps-icon-branch:before{content:" \e0ce "}.ps-icon-liquor:before{content:" \e0cf "}.ps-icon-bus-london:before{content:" \e0d0 "}.ps-icon-machine-wash:before{content:" \e0d1 "}.ps-icon-machine-wash-gentle-or-delicate:before{content:" \e0d2 "}.ps-icon-machine-wash-permanent-press:before{content:" \e0d3 "}.ps-icon-wand:before{content:" \e0d4 "}.ps-icon-magnifying-glass:before{content:" \e0d5 "}.ps-icon-maximum-temp-110-230:before{content:" \e0d6 "}.ps-icon-maximum-temp-150-300:before{content:" \e0d7 "}.ps-icon-maximum-temp-200-390:before{content:" \e0d8 "}.ps-icon-megaphone:before{content:" \e0d9 "}.ps-icon-man:before{content:" \e0da "}.ps-icon-mic:before{content:" \e0db "}.ps-icon-mic-off:before{content:" \e0dc "}.ps-icon-next:before{content:" \e0dd "}.ps-icon-non-chlorine-bleach-if-needed:before{content:" \e0de "}.ps-icon-penknife:before{content:" \e0df "}.ps-icon-petroleum-solvent-steam:before{content:" \e0e0 "}.ps-icon-phone:before{content:" \e0e1 "}.ps-icon-piano:before{content:" \e0e2 "}.ps-icon-pin:before{content:" \e0e3 "}.ps-icon-filter:before{content:" \e0e4 "}.ps-icon-plane:before{content:" \e0e5 "}.ps-icon-previous:before{content:" \e0e6 "}.ps-icon-quote:before{content:" \e0e7 "}.ps-icon-retweet-1:before{content:" \e0e8 "}.ps-icon-sound:before{content:" \e0e9 "}.ps-icon-sound-down:before{content:" \e0ea "}.ps-icon-sound-level-one:before{content:" \e0eb "}.ps-icon-sound-level-two:before{content:" \e0ec "}.ps-icon-sound-plus:before{content:" \e0ed "}.ps-icon-stethoscope:before{content:" \e0ee "}.ps-icon-suitcase:before{content:" \e0ef "}.ps-icon-target:before{content:" \e0f0 "}.ps-icon-ticket:before{content:" \e0f1 "}.ps-icon-trophy:before{content:" \e0f2 "}.ps-icon-tumble-dry:before{content:" \e0f3 "}.ps-icon-ufo:before{content:" \e0f4 "}.ps-icon-video-camera:before{content:" \e0f5 "}.ps-icon-truck-1:before{content:" \e0f6 "}.ps-icon-water-temperature-30:before{content:" \e0f7 "}.ps-icon-water-temperature-40:before{content:" \e0f8 "}.ps-icon-water-temperature-50:before{content:" \e0f9 "}.ps-icon-water-temperature-60:before{content:" \e0fa "}.ps-icon-water-temperature-70:before{content:" \e0fb "}.ps-icon-water-temperature-95:before{content:" \e0fc "}.ps-icon-clothes-water:before{content:" \e0fd "}.ps-icon-woman:before{content:" \e0fe "}.ps-icon-zoom-in:before{content:" \e0ff "}.ps-icon-zoom-out:before{content:" \e100 "}.ps-icon-anchor:before{content:" \e101 "}.ps-icon-left:before{content:" \e102 "}.ps-icon-right:before{content:" \e103 "}.ps-icon-up:before{content:" \e104 "}.ps-icon-down:before{content:" \e105 "}.ps-icon-play:before{content:" \e106 "}.ps-icon-forward:before{content:" \e107 "}.ps-icon-rewind:before{content:" \e108 "}.ps-icon-forbidden:before{content:" \e109 "}.ps-icon-stats:before{content:" \e10a "}.ps-icon-bar-code:before{content:" \e10b "}.ps-icon-lab:before{content:" \e10c "}.ps-icon-beer:before{content:" \e10d "}.ps-icon-bell:before{content:" \e10e "}.ps-icon-book-tag:before{content:" \e10f "}.ps-icon-minus-circle-1:before{content:" \e110 "}.ps-icon-plus-box:before{content:" \e111 "}.ps-icon-minus-box:before{content:" \e112 "}.ps-icon-plus:before{content:" \e113 "}.ps-icon-minus:before{content:" \e114 "}.ps-icon-arrow-right:before{content:" \e115 "}.ps-icon-down-arrow-circle:before{content:" \e116 "}.ps-icon-up-arrow-circle:before{content:" \e117 "}.ps-icon-right-arrow-circle:before{content:" \e118 "}.ps-icon-left-arrow-circle:before{content:" \e119 "}.ps-icon-contrast:before{content:" \e11a "}.ps-icon-align-justified:before{content:" \e11b "}.ps-icon-align-right:before{content:" \e11c "}.ps-icon-align-left:before{content:" \e11d "}.ps-icon-minus-circle:before{content:" \e11e "}.ps-icon-book:before{content:" \e11f "}.ps-icon-label-hogwarts:before{content:" \e120 "}.ps-icon-label:before{content:" \e121 "}.ps-icon-leaf:before{content:" \e122 "}.ps-icon-work-case:before{content:" \e123 "}.ps-icon-bug:before{content:" \e124 "}.ps-icon-building:before{content:" \e125 "}.ps-icon-calendar:before{content:" \e126 "}.ps-icon-calendar-grid:before{content:" \e127 "}.ps-icon-align-centered:before{content:" \e128 "}.ps-icon-camera:before{content:" \e129 "}.ps-icon-check-box-empty:before{content:" \e12a "}.ps-icon-check-box:before{content:" \e12b "}.ps-icon-radio-empty:before{content:" \e12c "}.ps-icon-radio:before{content:" \e12d "}.ps-icon-coffee:before{content:" \e12e "}.ps-icon-coffee-hot:before{content:" \e12f "}.ps-icon-compass:before{content:" \e130 "}.ps-icon-bull-right:before{content:" \e131 "}.ps-icon-bull-left:before{content:" \e132 "}.ps-icon-chat-alt:before{content:" \e133 "}.ps-icon-chat:before{content:" \e134 "}.ps-icon-code:before{content:" \e135 "}.ps-icon-flag-corner:before{content:" \e136 "}.ps-icon-flag-scout:before{content:" \e137 "}.ps-icon-flag:before{content:" \e138 "}.ps-icon-row-setting:before{content:" \e139 "}.ps-icon-copy:before{content:" \e13a "}.ps-icon-file:before{content:" \e13b "}.ps-icon-crop:before{content:" \e13c "}.ps-icon-iphone:before{content:" \e13d "}.ps-icon-ipad:before{content:" \e13e "}.ps-icon-mac:before{content:" \e13f "}.ps-icon-random:before{content:" \e140 "}.ps-icon-arrow-box:before{content:" \e141 "}.ps-icon-scissors:before{content:" \e142 "}.ps-icon-dashboard:before{content:" \e143 "}.ps-icon-world:before{content:" \e144 "}.ps-icon-download:before{content:" \e145 "}.ps-icon-upload:before{content:" \e146 "}.ps-icon-fire:before{content:" \e147 "}.ps-icon-eye:before{content:" \e148 "}.ps-icon-no-eye:before{content:" \e149 "}.ps-icon-folder:before{content:" \e14a "}.ps-icon-clock:before{content:" \e14b "}.ps-icon-mouse:before{content:" \e14c "}.ps-icon-backpack:before{content:" \e14d "}.ps-icon-ipod:before{content:" \e14e "}.ps-icon-iwatch:before{content:" \e14f "}.ps-icon-battery:before{content:" \e150 "}.ps-icon-battery-charge:before{content:" \e151 "}.ps-icon-lightning:before{content:" \e152 "}.ps-icon-image:before{content:" \e153 "}.ps-icon-gift:before{content:" \e154 "}.ps-icon-cutlery:before{content:" \e155 "}.ps-icon-pen:before{content:" \e156 "}.ps-icon-archive:before{content:" \e157 "}.ps-icon-arrow-down:before{content:" \e158 "}.ps-icon-arrow-left:before{content:" \e159 "}.ps-icon-arrow-up:before{content:" \e15a "}.ps-icon-asterisk:before{content:" \e15b "}.ps-icon-browser:before{content:" \e15c "}.ps-icon-check:before{content:" \e15d "}.ps-icon-cloud:before{content:" \e15e "}.ps-icon-download-from-cloud:before{content:" \e15f "}.ps-icon-upload-to-cloud:before{content:" \e160 "}.ps-icon-checked:before{content:" \e161 "}.ps-icon-ambulance:before{content:" \e162 "}.ps-icon-mailbox:before{content:" \e163 "}.ps-icon-plus-circle:before{content:" \e164 "}.ps-icon-truck:before{content:" \e165 "}.ps-icon-girl-sad-hunappy:before{content:" \e166 "}.ps-icon-spades-card:before{content:" \e167 "}.ps-icon-diamonds-card:before{content:" \e168 "}.ps-icon-clubs-card:before{content:" \e169 "}.ps-icon-hearts-card:before{content:" \e16a "}.ps-icon-pull:before{content:" \e16b "}.ps-icon-pant:before{content:" \e16c "}.ps-icon-data-board:before{content:" \e16d "}.ps-icon-board:before{content:" \e16e "}.ps-icon-shoe:before{content:" \e16f "}.ps-icon-globe:before{content:" \e170 "}.ps-icon-pin-map:before{content:" \e171 "}.ps-icon-bonnet:before{content:" \e172 "}.ps-icon-contact:before{content:" \e173 "}.ps-icon-fish:before{content:" \e174 "}.ps-icon-cookie:before{content:" \e175 "}.ps-icon-pizza:before{content:" \e176 "}.ps-icon-birthday:before{content:" \e177 "}.ps-icon-pc:before{content:" \e178 "}.ps-icon-ram:before{content:" \e179 "}.ps-icon-cpu:before{content:" \e17a "}.ps-icon-milkshake:before{content:" \e17b "}.ps-icon-tacos:before{content:" \e17c "}.ps-icon-burger:before{content:" \e17d "}.ps-icon-home:before{content:" \e17e "}.ps-icon-lego:before{content:" \e17f "}.ps-icon-preston:before{content:" \e180 "} \ No newline at end of file diff --git a/docs/browsers-support.md b/docs/browsers-support.md new file mode 100644 index 00000000..b6e643e4 --- /dev/null +++ b/docs/browsers-support.md @@ -0,0 +1,6 @@ +# Browsers Support +autoComplete.js comes with native support for all latest stable versions of current major browsers + +| [IE / Edge](http://godban.github.io/browsers-support-badges/)
IE / Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [iOS Safari](http://godban.github.io/browsers-support-badges/)
iOS Safari | [Samsung](http://godban.github.io/browsers-support-badges/)
Samsung | [Opera](http://godban.github.io/browsers-support-badges/)
Opera | [Opera Mini](http://godban.github.io/browsers-support-badges/)
Opera Mini | [Electron](http://godban.github.io/browsers-support-badges/)
Electron | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Edge | last version | last version | last version | last version | last version | last version | last version | last version | \ No newline at end of file diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 00000000..427a78e3 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,522 @@ +# Configuration + +API configuration options and events + +## Options + +#### selector (optional) + +*** + +> Input field selector. + +- Type: `String` of [selector](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors) | `Function` (optional) + +- Defaults: `#autoComplete` + +- Example + + + +#### ** String ** +```js +selector: "#autoComplete", // Any valid selector +``` + +#### ** Function ** +```js +selector: () => { + return "#customID"; // Any valid selector +}, +``` + + + +#### data (required) + +*** + +> Data Source. + +- Type: `Object` +- Methods: + - src: `Array`|`Function` (required) + - key: `Array` (required only if `data.src` is `Array` of `Objects`) + - cache: `Boolean` (optional) + - results: `Function` (optional) + - 1 parameter `(list)` returns `Array` of results values + +- Defaults: + - src: `null` + - key: `null` + - cache: `false` + - results: No action + +- Example: + + +#### ** Array (Strings) ** + +```js +data: { + src: ["Sauce - Thousand Island", "Wild Boar - Tenderloin", "Goat - Whole Cut"], + cache: false +}, +``` + +#### ** Array (Objects) ** + +```js +data: { + src: [ + { "food": "Sauce - Thousand Island" }, + { "food": "Wild Boar - Tenderloin" }, + { "food": "Goat - Whole Cut" } + ], + key: ["food"], + cache: false +}, +``` + +#### ** Function ** + +```js +data: { + src: () => { + + }, + key: ["food"], + cache: false +}, +``` + +#### ** Async ** + +```js +data: { + src: async () => { + // Fetch Data from external Source + const source = await fetch("https://www.url.com/data.json"); + const data = await source.json(); + + // Returns Fetched data + return data; + }, + key: ["food"], + cache: true +}, +``` + + +#### trigger (optional) + +*** + +> Engine event & condition trigger. + +- Type: `Object` +- Methods: + - event: `Array` of [events](https://developer.mozilla.org/en-US/docs/Web/Events) (optional) + - condition: `Function` (optional) + - 2 parameters `(event, queryValue)` returns `Boolean` + +- Defaults: + - event: `["input"]` + - condition: if input field **NOT** empty and greater or equal threshold + +- Example: + +```js +trigger: { + event: ["input"], // Any valid event type name + condition: (event, queryValue) => { + return queryValue.replace(/ /g, "").length; // Returns "Boolean" + } +}, +``` + +#### query (optional) + +*** + +> Query interceptor. + +- Type: `Object` +- Methods: + - manipulate: `Function` (optional) + - 1 parameter `(query)` returns `String` + +- Defaults: + - manipulate: Returns raw input value + +- Example: + +```js +query: { + manipulate: (query) => { + return query.replace("pizza", "burger"); + } +}, +``` + +#### placeHolder (optional) + +*** + +> Input field place holder text value. + +- Type: `String` (optional) + +- Defaults: `Blank/Empty` + +- Example: + +```js +placeHolder: "Search...", +``` + +#### observer (optional) + +*** + +> Input field observer. + +- Type: `Boolean` (optional) + +- Defaults: `false` + +- Example: + +```js +observer: false, +``` + +#### threshold (optional) + +*** + +> Minimum characters length before engine starts rendering results. + +- Type: `Integer` (optional) + +- Defaults: `1` + +- Example: + +```js +threshold: 2, +``` + +#### debounce (optional) + +*** + +> Minimum duration after typing is in idle state for engine to kick in. + +- Type: `Integer` (optional) + +- Defaults: `0` + +- Example: + +```js +debounce: 300, // Milliseconds value +``` + +#### searchEngine (optional) + +*** + +> Search engine Type/Mode. + +- Type: `String` | `Function` (optional) + - `String` lowerCase `"strict"` | `"loose"` + - `Function` with 2 parameters `(query, record)` returns 1 `String` of each match individually + +- Defaults: `"strict"` + +- Example: + +```js +searchEngine: "strict", +``` + +#### diacritics (optional) + +*** + +> Search engine diacritics handler. + +- Type: `Boolean` (optional) + +- Defaults: `false` + +- Example: + +```js +diacritics: "strict", +``` + +#### resultsList (optional) + +*** + +> Rendered results list element. + +- Type: `Object` (optional) + +- Methods: + - render: `Boolean` (optional) + - element: `String` of [element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element) (optional) + - idName: `String` of id value (optional) + - className: `String` of class value (optional) + - destination: `String` of [selector](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors) | `Function` (optional) + - position: `String` of [position](https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentElement#parameters) (optional) + - container: `Function` (optional) + - 1 parameter (element) with no return + - maxResults: `Integer` (optional) + - navigation: `Function` (optional) + - 1 parameter (event) with no return + - noResults: `Function` (optional) + - 2 parameters (list, query) with no return + +- Defaults: + - render: `true` + - element: `ul` + - idName: `autoComplete_list` + - className: `autoComplete_list` + - destination: `#autoComplete` + - position: `afterend` + - container: `Function` + - maxResults: `5` + - navigation: `default` navigation behavior + - noResults: No action + +- Example: + +```js +resultsList: { + render: true, + element: "ul", + idName: "autoComplete_list", + className: "autoComplete_list", + destination: "#autoComplete", + position: "afterend", + maxResults: 5, + container: (element) => { + element.setAttribute("data-parent", "food-list"); + }, + noResults: (list, query) => { + // Create no results element + const message = document.createElement("li"); + message.setAttribute("class", "no_result"); + message.setAttribute("tabindex", "1"); + // Add text content + message.innerHTML = `Found No Results for "${query}"`; + // Append message to results list + list.appendChild(message); + }, +}, +``` + +#### resultItem (optional) + +*** + +> Rendered result item element. + +- Type: `Object` (optional) + +- Methods: + - element: `String` of [element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element) (optional) + - idName: `String` of id value (optional) + - className: `String` of class value (optional) + - content: `Function` (optional) + - 2 parameters (item, element) with no return + - highlight: `Object` (optional) + - render: `Boolean` (optional) + - className: `String` of class value (optional) + - selected: `Object` (optional> + - className: `String` of class value (optional) + +- Defaults: + - element: `li` + - idName: `undefined_[index]` + - className: `autoComplete_result` + - content: `Function` + - highlight: + - render: `false` + - className: `"autoComplete_highlighted"` + - selected: + - className: `"autoComplete_selected"` + +- Example: + +```js +resultItem: { + element: "li", + className: "autoComplete_result", + content: (item, element) => { + element.setAttribute("data-parent", "food-item"); + }, + highlight: { + render: true, + className: "autoComplete_highlighted" + }, + selected: { + className: "autoComplete_selected" + } +}, +``` + +#### feedback (optional) + +*** + +> Action script on dataFeedback event. + +- Type: `Function` (optional) + - 1 parameter (data) with no return + +- Defaults: No action + +- Example: + +```js +feedback: (data) => { + console.log(data); +}, +``` + +#### onSelection (optional) + +*** + +> Action script onSelection event. + +- Type: `Function` (optional) + - 1 parameter (feedback) with no return + +- Defaults: No action + +- Example: + +```js +onSelection: (feedback) => { + console.log(feedback); +}, +``` + +## Events + +#### init + +*** + +> Fires after `autoComplete.js` engine is initialized and ready + +- Example: + +```js +document.querySelector("#autoComplete").addEventListener("init", function (event) { + console.log(event); +}); +``` + +#### fetch + +*** + +> Fires after fetching data is complete and data is ready + +- Example: + +```js +document.querySelector("#autoComplete").addEventListener("fetch", function (event) { + console.log(event.detail); +}); +``` + +#### input + +*** + +> Fires on every user input interaction + +- Example: + +```js +document.querySelector("#autoComplete").addEventListener("input", function (event) { + console.log(event); +}); +``` + +#### results + +*** + +> Fires after search operation is done and matching results are ready + +- Example: + +```js +document.querySelector("#autoComplete").addEventListener("results", function (event) { + console.log(event.detail); +}); +``` + +#### open + +*** + +> Fires after opening the results list + +- Example: + +```js +document.querySelector("#autoComplete").addEventListener("open", function (event) { + console.log(event); +}); +``` + +#### navigate + +*** + +> Fires on every "resultsList" navigation interaction + +- Example: + +```js +document.querySelector("#autoComplete").addEventListener("navigate", function (event) { + console.log(event.detail); +}); +``` + +#### close + +*** + +> Fires after "resultsList" is closed + +- Example: + +```js +document.querySelector("#autoComplete").addEventListener("close", function (event) { + console.log(event); +}); +``` + +#### unInit + +*** + +> Fires after `autoComplete.js` engine is un-initialized and detached + +- Example: + +```js +document.querySelector("#autoComplete").addEventListener("unInit", function (event) { + console.log(event); +}); +``` diff --git a/docs/contributions.md b/docs/contributions.md new file mode 100644 index 00000000..bb84651e --- /dev/null +++ b/docs/contributions.md @@ -0,0 +1,18 @@ +# Contributions + +*** + +> Contributions are always more than welcome! + +If you have any ideas, just [open an issue](https://github.com/TarekRaafat/autoComplete.js/issues) and tell me what you think. + +- Please fork the repository and make changes as you'd like. + Pull requests are warmly welcome. + +> If you'd like to contribute: + +1. Fork it () +2. Create your feature branch (`git checkout -b feature/fooBar`) +3. Commit your changes (`git commit -am 'Add some fooBar'`) +4. Push to the branch (`git push origin feature/fooBar`) +5. Create a new Pull Request \ No newline at end of file diff --git a/docs/demo/index.html b/docs/demo/index.html index c3ae31be..82ed0732 100644 --- a/docs/demo/index.html +++ b/docs/demo/index.html @@ -72,7 +72,7 @@ + href="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@latest/dist/css/autoComplete.min.css"> @@ -151,7 +151,7 @@

mode

- + diff --git a/docs/demo/js/index.js b/docs/demo/js/index.js index 29d39859..7f4e5892 100644 --- a/docs/demo/js/index.js +++ b/docs/demo/js/index.js @@ -1,6 +1,5 @@ // The autoComplete.js Engine instance creator const autoCompleteJS = new autoComplete({ - name: "food & drinks", data: { src: async function () { // Loading placeholder text @@ -31,7 +30,16 @@ const autoCompleteJS = new autoComplete({ highlight: { render: true, }, - maxResults: 5, + resultsList: { + noResults: (list, query) => { + // No Results List Message + const message = document.createElement("li"); + message.setAttribute("class", "no_result"); + message.setAttribute("tabindex", "1"); + message.innerHTML = `Found No Results for "${query}"`; + list.appendChild(message); + }, + }, resultItem: { content: (data, element) => { // Modify Results Item Style @@ -46,16 +54,6 @@ const autoCompleteJS = new autoComplete({ `; }, }, - noResults: (dataFeedback, generateList) => { - // Generate autoComplete List - generateList(autoCompleteJS, dataFeedback, dataFeedback.results); - // No Results List Item - const result = document.createElement("li"); - result.setAttribute("class", "no_result"); - result.setAttribute("tabindex", "1"); - result.innerHTML = `Found No Results for "${dataFeedback.query}"`; - document.querySelector(`#${autoCompleteJS.resultsList.idName}`).appendChild(result); - }, onSelection: (feedback) => { document.querySelector("#autoComplete").blur(); // Prepare User's Selected Value diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 00000000..802008f3 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,9 @@ +# Getting Started + +This quick start is intended for beginner to advanced developers + +## Quick Start + +*** + +It's very easy to get started with `autoComplete.js`. All that's required is the script included in your page along with a single `` filed tag to render the chart. \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 20888e4c..7586d29e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,75 +1,205 @@ - - - autoComplete.js - Vanilla Javascript library - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - + + + autoComplete.js - Vanilla Javascript library + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..03a3c0b0 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,54 @@ +
+ + + +

Simple autocomplete pure vanilla Javascript library. :rocket: Live Demo v9.0

+ +

autoComplete.js is a simple pure vanilla Javascript library that's progressively designed for speed,
high versatility and seamless integration with a wide range of projects & systems.

+ +
+ +![GitHub top language](https://img.shields.io/github/languages/top/TarekRaafat/autoComplete.js?color=yellow) +![\[Zero Dependencies\]()](https://img.shields.io/badge/Dependencies-0-blue.svg) +![\[Size\]()](https://img.shields.io/badge/Size-10%20KB-green.svg) +![Maintained](https://img.shields.io/badge/Maintained%3F-yes-success) +[![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.svg?v=103)](https://github.com/TarekRaafat/autoComplete.js) + +autoComplete.js - Simple autocomplete pure vanilla Javascript library. | Product Hunt Embed + +
+ + + +
+ +## Features + +*** + +- Pure Vanilla Javascript +- Zero Dependencies +- Simple & Easy to use +- Extremely Lightweight +- Blazing Fast +- Versatile +- Hackable & highly customizable + + +## Author + +*** + +
Tarek Raafat + +- Email: tarek.m.raafat@gmail.com +- Website: +- Github: + +## License + +* * * + +`autoComplete.js` is released under the [Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0). + +© 2021 [Tarek Raafat](http://www.tarekraafat.com) \ No newline at end of file diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 00000000..510629fd --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,96 @@ +# Installation + +* * * + +#### Package Manager +[![npm](https://img.shields.io/npm/v/@tarekraafat/autocomplete.js)](https://badge.fury.io/js/%40tarekraafat%2Fautocomplete.js) +![npm](https://img.shields.io/npm/dm/@tarekraafat/autocomplete.js?label=downloads) + + +#### ** npm ** + + + +```shell +npm i @tarekraafat/autocomplete.js +``` + +#### ** yarn ** + + +Yarn Logo + +```shell +yarn add @tarekraafat/autocomplete.js +``` + + + +#### CDN +[![](https://data.jsdelivr.com/v1/package/npm/@tarekraafat/autocomplete.js/badge)](https://www.jsdelivr.com/package/npm/@tarekraafat/autocomplete.js) + + +#### ** JSDELIVR ** + +jsDelivr Logo + +`JS` + +```html + +``` + +`CSS` + +```html + +``` + +#### ** cdnjs ** + +cdnjs Logo + +`JS` + +```html + +``` + +`CSS` + +```html + +``` + +#### ** UNPKG ** + +unpkg Logo + +`JS` + +```html + +``` + +`CSS` + +```html + +``` + + + +#### Direct +[![GitHub package.json version](https://img.shields.io/github/package-json/v/TarekRaafat/autoComplete.js)](https://badge.fury.io/gh/tarekraafat%2FautoComplete.js) + + +#### ** Github ** + + + +1. [Download](https://github.com/TarekRaafat/autoComplete.js/releases/latest) latest release package +2. Get `javascript` file from `/dist/js` folder +3. Get `stylesheet` file from `/dist/css` folder +4. Get `search` icon from `/dist/css/images` folder + + \ No newline at end of file diff --git a/docs/playground.md b/docs/playground.md new file mode 100644 index 00000000..2e47f2ad --- /dev/null +++ b/docs/playground.md @@ -0,0 +1,20 @@ +# Playground + +Live Demo Example + +## CodePen + +*** + +```iframe +height="600" +width="100%" +scrolling="no" +title="autoComplete.js" +src="https://codepen.io/tarekraafat/embed/rQopdW?height=265&theme-id=dark&default-tab=js,result" +frameborder="no" +loading="lazy" +allowtransparency="true" +allowfullscreen="true" +textContent="See the Pen autoComplete.js by Tarek Raafat (@tarekraafat) on CodePen." +``` \ No newline at end of file diff --git a/docs/plugins.md b/docs/plugins.md new file mode 100644 index 00000000..adb977aa --- /dev/null +++ b/docs/plugins.md @@ -0,0 +1,9 @@ +# Plugins + +Add functionality and customize your autoComplete.js with plugins built by our amazing developer community + +## Third-Party Plugins + +*** + +- [Contao autoComplete.js Bundle](https://github.com/heimrichhannot/contao-autocompletejs-bundle) by [@heimrichhannot](https://github.com/heimrichhannot) \ No newline at end of file diff --git a/docs/releases.md b/docs/releases.md index ca7c69bc..62a745c6 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -1,3 +1,7 @@ +# Releases +Find release notes and guides on versioning + + ## Versioning * * * @@ -15,82 +19,118 @@ And constructed with the following guidelines: For more information on semantic versioning, please visit . -Release flags: - -- `[Experimental]`: Under testing and might be deprecated at any point -- `[Deprecated]`: Not developed / supported anymore, might be removed at any point -- `[Removed]`: Completely gone, no longer exists -- `[Changed]`: Breaking change in the API or the core library -- `[Updated]`: Non-breaking change in the API or the core library -- `[Fixed]`: Bug or Issue that was fixed and no longer exists -- `[Added]`: New feature +- Release flags: + - `[Experimental]`: Under testing and might be deprecated at any point + - `[Deprecated]`: Not developed / supported anymore, might be removed at any point + - `[Removed]`: Completely gone, no longer exists + - `[Changed]`: Breaking change in the API or the core library + - `[Updated]`: Non-breaking change in the API or the core library + - `[Fixed]`: Bug or Issue that was fixed and no longer exists + - `[Added]`: New feature * * * ## Release Notes -- v9.0.0 ✨ +#### v9.0.0 ✨ + >
This version has breaking changes, kindly check the list - πŸ”§ Fixed: `esc` button not working with `noResults` in some cases (Thanks πŸ‘ @sunshineplan) #157 - βž• Added: `selection` & `highlight` custom `className` API methods (Thanks πŸ‘ @jerrykan) #184 - βž• Added: `eventEmitter` for `resultsList` fires on list `close` event (Thanks πŸ‘ @yliharma) #188 - βž• Added: `event` parameter to `trigger.event` API method (Thanks πŸ‘ @nornes) #189 - - πŸŒ€ Changed: The name of `rendered` `eventEmitter` to `open` - - πŸŒ€ Changed: The name of `navigation` `eventEmitter` to `navigate` + - πŸŒ€ Changed: `maxResults` API moved under `resultsList` + - πŸŒ€ Changed: `noResults` API moved under `resultsList` + - πŸŒ€ Changed: `highlight` API moved under `resultItem` + - πŸŒ€ Changed: `selection` API moved under `resultItem` with the name of `selected` + - πŸŒ€ Changed: `rendered` `eventEmitter` name to `open` + - πŸŒ€ Changed: `navigation` `eventEmitter` name to `navigate` - πŸŒ€ Changed: `closeAllLists` refactored and renamed to `closeList` - πŸŒ€ Changed: `generateList` stage with some refactoring - πŸŒ€ Changed: `start` stage with some refactoring - πŸŒ€ Changed: `noResults` API method with some refactoring [details](https://tarekraafat.github.io/autoComplete.js/#/?id=api-configuration) - πŸŒ€ Changed: `highlight` API from `String` to `Object` [details](https://tarekraafat.github.io/autoComplete.js/#/?id=api-configuration) + - ❗ Removed: `sort` API + - ❗ Removed: `data.results` API + - ❗ Removed: `connect` `eventEmitter` from the `preInit` stage - πŸ” Updated: Replaced `Uglify` with `Terser` - πŸ” Updated: Development dependencies - - ❗ Removed: `connect` `eventEmitter` from the `preInit` stage + - πŸ” Updated: Code comments + - πŸ” Updated: Documentation -- v8.3.2 +*** + +#### v8.3.2 - πŸ”§ Fix: `selector` as a function breaks when `observer` is true (Thanks πŸ‘ @brunobg) #179 -- v8.3.1 +*** + +#### v8.3.1 - πŸ”§ Fix: Keyboard navigation selection reset (Thanks πŸ‘ @marsimeau) #177 -- v8.3.0 +*** + +#### v8.3.0 - βž• Added: `event` object to the `onSelection` data `feedback` (Thanks πŸ‘ @Liano) #176 -- v8.2.3 +*** + +#### v8.2.3 - πŸ”§ Fix: `resultItem` ID `setAttribute` to be `idName` instead of `className` (Thanks πŸ‘ @marsimeau) #173 -- v8.2.2 +*** + +#### v8.2.2 - πŸ”§ Fix: `diacritics` composite characters do not match (Thanks πŸ‘ @ikemo3 @Michin0suke @bravik) #169 #171 -- v8.2.1 +*** + +#### v8.2.1 - πŸ” Updated: `package.json` node engine version from `12` to `>=12` (Thanks πŸ‘ @mynameisbogdan) #164 - πŸ” Updated: `package.json` npm engine version from `6` to `>=6` -- v8.2.0 +*** + +#### v8.2.0 - βž• Added: `data.results` API to access and manipulate data feedback matching results - πŸ”§ Fixed: `resultItem.content` API `data` params to pass the entire item data (Thanks πŸ‘ @jwendel) #163 -- v8.1.1 +*** + +#### v8.1.1 - πŸ”§ Fixed: `selector` API to accept function (Thanks πŸ‘ @goaround) #160 #161 - πŸ”§ Fixed: `resultsList` destination API to accept function (Thanks πŸ‘ @goaround) #160 #162 -- v8.1.0 +*** + +#### v8.1.0 - βž• Added: `observer` Controller API [Turned off by default] #149 - βž• Added: New Light Style [autoComplete.02.css] - πŸ”§ Fixed: Main build `live reload` issue (ThanksΒ πŸ‘Β @lougroshek) #155 -- v8.0.4 +*** + +#### v8.0.4 - Fixed: Remove prior event listeners before adding new one in `init` (ThanksΒ πŸ‘Β @RobinLawinsky) #153 -- v8.0.3 +*** + +#### v8.0.3 - Fixed: Custom results list rendering destination (ThanksΒ πŸ‘Β @RobinLawinsky) #150 -- v8.0.2 +*** + +#### v8.0.2 - Updated: Input Field Assignment Order - Fixed: Trigger Event API -- v8.0.1 +*** + +#### v8.0.1 - Build Update -- v8.0.0 +*** + +#### v8.0.0 - Whole New More Modern Architecture Design - Added: High Quality Accessibility ([WAI-ARIA 1.2](https://www.w3.org/TR/wai-aria-practices-1.2/examples/combobox/combobox-autocomplete-both.html)) Support - Added: Life Cycle Events (ThanksΒ πŸ‘Β @zippy84) #89 @@ -113,24 +153,34 @@ Release flags: - Fixed: `autoComplete.js` interference with native keyboard events (ThanksΒ πŸ‘ @eballeste) #104 - Fixed: Keyboard events stops working when `onSelection` not defined (ThanksΒ πŸ‘ @AustinGrey) #130 -- v7.2.0 +*** + +#### v7.2.0 - Added support to `textarea` input field (Thanks πŸ‘ @EmilStenstrom) -- v7.1.3 +*** + +#### v7.1.3 - Enhanced mouse selection (Thanks πŸ‘ @adan-ferguson) -- v7.1.2 +*** + +#### v7.1.2 - Fixed error behavior occurs when searching (Empty, False, Null) record -- v7.1.1 +*** + +#### v7.1.1 - `resList` now is fully created in `DocumentFragment` before rendering for better performance (Thanks πŸ‘ @asafwat) - `config` parameters restructure (Thanks πŸ‘ @asafwat) - Reduced `autoComplete.js` weight -- v7.1.0 +*** + +#### v7.1.0 - New improved Navigation logic (Thanks πŸ‘ @mtomov) - `shadowRoot` API support `[Removed]` - Enhanced `resList.navigation` API data feedback @@ -139,19 +189,27 @@ Release flags: - Faster performance - Reduced `autoComplete.js` weight -- v7.0.3 +*** + +#### v7.0.3 - Duplicate values selection bug fix (Thanks πŸ‘ @plungerman) -- v7.0.2 +*** + +#### v7.0.2 - Data Promise bug fix (Thanks πŸ‘ @braco) - Remote API duplicate calls fix (Thanks πŸ‘ @srinivas025, @argebynogame) - `trigger.condition` enhancement (Thanks πŸ‘ @sakuraineed) - Code Refactor for faster performance and lighter weight -- v7.0.1 +*** + +#### v7.0.1 - `api multiple calls` issue fix (Thanks πŸ‘ @srinivas025) -- v7.0.0 +*** + +#### v7.0.0 - New API for results list navigation `resultsList.navigation` (Thanks πŸ‘ @fredluetkemeier) - New API for autoComplete.js engine `trigger.event` (Thanks πŸ‘ @fredluetkemeier) - New API for autoComplete.js engine `trigger.condition` @@ -162,10 +220,14 @@ Release flags: - `customEngine` merged with `searchEngine` API key for more convenience `[Changed]` - Code Optimizations -- v6.1.0 +*** + +#### v6.1.0 - Use Custom Search Algorithm via `customEngine` method (Thanks @hwangm) -- v6.0.0 +*** + +#### v6.0.0 - `CustomEvent` & `Closest` method IE compatibility (Thanks @g-viet) - Query interception (Thanks @barns101) - Simplified `resultsList` & `resultItem` @@ -173,24 +235,36 @@ Release flags: - `EventEmitter` now has `input` method for row user’s input - `EventEmitter` now has `query` method for intercepted user’s input -- v5.3.0 +*** + +#### v5.3.0 - Get results from `eventEmitter` without rendering list through `resultsList.render` API - EventEmitter name `type` changed to `autoComplete` `[Changed]` -- v5.2.0 +*** + +#### v5.2.0 - Added Event Emitter on `noResults` event -- v5.1.2 +*** + +#### v5.1.2 - `noResults` API unset error bug fix -- v5.1.1 +*** + +#### v5.1.1 - `UpperCase` query bug fix -- v5.1.0 +*** + +#### v5.1.0 - Added `noResults` open API for No Results (Thanks @chabri) - HTML elements `ContentEditable` Input Support (Thanks @philippejadin) -- v5.0.0 +*** + +#### v5.0.0 - Large datasets handeling (Thanks @Johann-S) - API Data fetching & Dynamic Data reloading (Thanks @Brostafa) - Debouncing API Calls diff --git a/docs/support.md b/docs/support.md new file mode 100644 index 00000000..470960e8 --- /dev/null +++ b/docs/support.md @@ -0,0 +1,26 @@ +# Support +autoComplete.js has a great community make sure to reach out to them though the right channel + +## Technical + +*** + +For technical questions and support, please post your question on Stack Overflow using the below tag + +- Stack Overflow [autoCompletejs][stackOverflow] + + + +## General + +*** + +For general questions or new ideas for `autoComplete.js` please start a discussion on Github using the below link + +- Github [discussion]. + + + +[stackOverflow]: https://stackoverflow.com/questions/tagged/autoCompletejs + +[discussion]: https://github.com/TarekRaafat/autoComplete.js/discussions \ No newline at end of file diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 00000000..954a3357 --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,241 @@ +# Usage + +autoComplete.js simple usage setup + +## Steps + +### 1. HTML + +*** + +Add an `` tag to your html page: + + +#### ** Basic ** +```html + +``` +#### ** Advanced ** +```html + +``` + +>
Tip: you can put the < input > inside < div class="autoComplete_wrapper" > to make sure results list always attached and aligned. + +### 2. Script + +**** + +1. Import `autoComplete.js` library to your project + + +#### ** HTML ** + +```html + + + +``` +#### ** Javascript ** + +```js +// CommonJS +const autoComplete = require("@tarekraafat/autocomplete.js"); + +/* OR */ + +// ES6 modules +import autoComplete from "@tarekraafat/autocomplete.js"; +``` + + +2. Create new instance of `autoComplete.js` engine after import and add needed [configuration](/configuration.md) + + +#### ** HTML ** + +```html + + + + + +``` +#### ** Javascript ** + +```js +// CommonJS +const autoComplete = require("@tarekraafat/autocomplete.js"); + +/* OR */ + +// ES6 modules +import autoComplete from "@tarekraafat/autocomplete.js"; + +const autoCompleteJS = new autoComplete({ config }); +``` + + +3. Set your `autoComplete.js` instance [configurations](/configuration.md) + + +#### ** Basic ** + +```js +// API Basic Configuration Object +{ + placeHolder: "Search for Food...", + data: { + src: ["Sauce - Thousand Island", "Wild Boar - Tenderloin", "Goat - Whole Cut"] + }, + resultItem: { + highlight: { + render: true + } + } +} +``` + +#### ** Advanced ** + +```js +// API Advanced Configuration Object +{ + selector: "#autoComplete", + placeHolder: "Search for Food...", + data: { + src: ["Sauce - Thousand Island", "Wild Boar - Tenderloin", "Goat - Whole Cut"] + }, + resultsList: { + noResults: (list, query) => { + // Create "No Results" message list element + const message = document.createElement("li"); + message.setAttribute("class", "no_result"); + // Add message text content + message.innerHTML = `Found No Results for "${query}"`; + // Add message list element to the list + list.appendChild(message); + }, + }, + resultItem: { + highlight: { + render: true + } + } +} +``` + + +> Note: [data.src](/configuration.md?id=data-required) config is **required** + + +### 3. Style + +*** + +Add the `autoComplete.js` stylesheet inside the `HEAD` tag + + +#### ** CDN ** + +```html + + + +``` + +#### ** Local ** + +```html + + + +``` + + +## Demo + +*** + +
+ +
+ +

+ +
+ Full Demo Code Snippet + +```html + + + + + + + + +
+ +
+ + + + + + +``` + +
+ + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index cb21be6b..8d0d4f8f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,15 +38,15 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.12.tgz", - "integrity": "sha512-3eJJ841uKxeV8dcN/2yGEUy+RfgQspPEgQat85umsE1rotuquQ2AbIub4S6j7c50a2d+4myc+zSlnXeIHrOnhQ==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.15.tgz", + "integrity": "sha512-ltnibHKR1VnrU4ymHyQ/CXtNXI6yZC0oJThyW78Hft8XndANwi+9H+UIklBDraIjFEJzw8wmcM427oDd9KS5wA==", "dev": true }, "node_modules/@babel/core": { - "version": "7.13.14", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.14.tgz", - "integrity": "sha512-wZso/vyF4ki0l0znlgM4inxbdrUvCb+cVz8grxDq+6C9k6qbqoIJteQOKicaKjCipU3ISV+XedCqpL2RJJVehA==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.15.tgz", + "integrity": "sha512-6GXmNYeNjS2Uz+uls5jalOemgIhnTMeaXo+yBUA72kC2uX/8VW6XyhVIo2L8/q0goKQA3EVKx0KOQpVKSeWadQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", @@ -54,9 +54,9 @@ "@babel/helper-compilation-targets": "^7.13.13", "@babel/helper-module-transforms": "^7.13.14", "@babel/helpers": "^7.13.10", - "@babel/parser": "^7.13.13", + "@babel/parser": "^7.13.15", "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.13", + "@babel/traverse": "^7.13.15", "@babel/types": "^7.13.14", "convert-source-map": "^1.7.0", "debug": "^4.1.0", @@ -148,9 +148,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.1.5.tgz", - "integrity": "sha512-nXuzCSwlJ/WKr8qxzW816gwyT6VZgiJG17zR40fou70yfAcqjoNyTLl/DQ+FExw5Hx5KNqshmN8Ldl/r2N7cTg==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.0.tgz", + "integrity": "sha512-JT8tHuFjKBo8NnaUbblz7mIu1nnvUDiHVjXXkulZULyidvo/7P6TY7+YqpV37IfF+KUFxmlK04elKtGKXaiVgw==", "dev": true, "dependencies": { "@babel/helper-compilation-targets": "^7.13.0", @@ -351,9 +351,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.13.tgz", - "integrity": "sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.15.tgz", + "integrity": "sha512-b9COtcAlVEQljy/9fbcMHpG+UIW9ReF+gpaxDHTlZd0c6/UU9ng8zdySAW9sRTzpvcdCHn6bUcbuYUgGzLAWVQ==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -377,9 +377,9 @@ } }, "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.8.tgz", - "integrity": "sha512-rPBnhj+WgoSmgq+4gQUtXx/vOcU+UYtjy1AA/aeD61Hwj410fwYyqfUcRP3lR8ucgliVJL/G7sXcNUecC75IXA==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.15.tgz", + "integrity": "sha512-VapibkWzFeoa6ubXy/NgV5U2U4MVnUlvnx6wo1XhlsaTrLYWE0UFpDQsVrmn22q5CzeloqJ8gEMHSKxuee6ZdA==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.13.0", @@ -996,9 +996,9 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.13.tgz", - "integrity": "sha512-lxb2ZAvSLyJ2PEe47hoGWPmW22v7CtSl9jW8mingV4H2sEX/JOcrAj2nPuGWi56ERUm2bUpjKzONAuT6HCn2EA==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.13.15.tgz", + "integrity": "sha512-Bk9cOLSz8DiurcMETZ8E2YtIVJbFCPGW28DJWUakmyVWtQSm6Wsf0p4B4BfEr/eL2Nkhe/CICiUiMOCi1TPhuQ==", "dev": true, "dependencies": { "regenerator-transform": "^0.14.2" @@ -1106,17 +1106,17 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.13.12.tgz", - "integrity": "sha512-JzElc6jk3Ko6zuZgBtjOd01pf9yYDEIH8BcqVuYIuOkzOwDesoa/Nz4gIo4lBG6K861KTV9TvIgmFuT6ytOaAA==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.13.15.tgz", + "integrity": "sha512-D4JAPMXcxk69PKe81jRJ21/fP/uYdcTZ3hJDF5QX2HSI9bBxxYw/dumdR6dGumhjxlprHPE4XWoPaqzZUVy2MA==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.13.12", - "@babel/helper-compilation-targets": "^7.13.10", + "@babel/compat-data": "^7.13.15", + "@babel/helper-compilation-targets": "^7.13.13", "@babel/helper-plugin-utils": "^7.13.0", "@babel/helper-validator-option": "^7.12.17", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.13.12", - "@babel/plugin-proposal-async-generator-functions": "^7.13.8", + "@babel/plugin-proposal-async-generator-functions": "^7.13.15", "@babel/plugin-proposal-class-properties": "^7.13.0", "@babel/plugin-proposal-dynamic-import": "^7.13.8", "@babel/plugin-proposal-export-namespace-from": "^7.12.13", @@ -1164,7 +1164,7 @@ "@babel/plugin-transform-object-super": "^7.12.13", "@babel/plugin-transform-parameters": "^7.13.0", "@babel/plugin-transform-property-literals": "^7.12.13", - "@babel/plugin-transform-regenerator": "^7.12.13", + "@babel/plugin-transform-regenerator": "^7.13.15", "@babel/plugin-transform-reserved-words": "^7.12.13", "@babel/plugin-transform-shorthand-properties": "^7.12.13", "@babel/plugin-transform-spread": "^7.13.0", @@ -1174,10 +1174,10 @@ "@babel/plugin-transform-unicode-escapes": "^7.12.13", "@babel/plugin-transform-unicode-regex": "^7.12.13", "@babel/preset-modules": "^0.1.4", - "@babel/types": "^7.13.12", - "babel-plugin-polyfill-corejs2": "^0.1.4", - "babel-plugin-polyfill-corejs3": "^0.1.3", - "babel-plugin-polyfill-regenerator": "^0.1.2", + "@babel/types": "^7.13.14", + "babel-plugin-polyfill-corejs2": "^0.2.0", + "babel-plugin-polyfill-corejs3": "^0.2.0", + "babel-plugin-polyfill-regenerator": "^0.2.0", "core-js-compat": "^3.9.0", "semver": "^6.3.0" }, @@ -1222,17 +1222,17 @@ } }, "node_modules/@babel/traverse": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.13.tgz", - "integrity": "sha512-CblEcwmXKR6eP43oQGG++0QMTtCjAsa3frUuzHoiIJWpaIIi8dwMyEFUJoXRLxagGqCK+jALRwIO+o3R9p/uUg==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.15.tgz", + "integrity": "sha512-/mpZMNvj6bce59Qzl09fHEs8Bt8NnpEDQYleHUPZQ3wXUMvXi+HJPLars68oAbmp839fGoOkv2pSL2z9ajCIaQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", "@babel/generator": "^7.13.9", "@babel/helper-function-name": "^7.12.13", "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.13", - "@babel/types": "^7.13.13", + "@babel/parser": "^7.13.15", + "@babel/types": "^7.13.14", "debug": "^4.1.0", "globals": "^11.1.0" } @@ -1352,9 +1352,9 @@ } }, "node_modules/anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "dependencies": { "normalize-path": "^3.0.0", @@ -1374,13 +1374,13 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.1.10.tgz", - "integrity": "sha512-DO95wD4g0A8KRaHKi0D51NdGXzvpqVLnLu5BTvDlpqUEpTmeEtypgC1xqesORaWmiUOQI14UHKlzNd9iZ2G3ZA==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.0.tgz", + "integrity": "sha512-9bNwiR0dS881c5SHnzCmmGlMkJLl0OUZvxrxHo9w/iNoRuqaPjqlvBf4HrovXtQs/au5yKkpcdgfT1cC5PAZwg==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.13.0", - "@babel/helper-define-polyfill-provider": "^0.1.5", + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.2.0", "semver": "^6.1.1" }, "peerDependencies": { @@ -1388,25 +1388,25 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.1.7.tgz", - "integrity": "sha512-u+gbS9bbPhZWEeyy1oR/YaaSpod/KDT07arZHb80aTpl8H5ZBq+uN1nN9/xtX7jQyfLdPfoqI4Rue/MQSWJquw==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.0.tgz", + "integrity": "sha512-zZyi7p3BCUyzNxLx8KV61zTINkkV65zVkDAFNZmrTCRVhjo1jAS+YLvDJ9Jgd/w2tsAviCwFHReYfxO3Iql8Yg==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.1.5", - "core-js-compat": "^3.8.1" + "@babel/helper-define-polyfill-provider": "^0.2.0", + "core-js-compat": "^3.9.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.1.6.tgz", - "integrity": "sha512-OUrYG9iKPKz8NxswXbRAdSwF0GhRdIEMTloQATJi4bDuFqrXaXcCUT/VGNrr8pBcjMh1RxZ7Xt9cytVJTJfvMg==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.0.tgz", + "integrity": "sha512-J7vKbCuD2Xi/eEHxquHN14bXAW9CXtecwuLrOIDJtcZzTaPzV1VdEfoUf9AzcRBMolKUQKM9/GVojeh0hFiqMg==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.1.5" + "@babel/helper-define-polyfill-provider": "^0.2.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -1476,9 +1476,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001205", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001205.tgz", - "integrity": "sha512-TL1GrS5V6LElbitPazidkBMD9sa448bQDDLrumDqaggmKFcuU2JW1wTOHJPukAcOMtEmLcmDJEzfRrf+GjM0Og==", + "version": "1.0.30001208", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001208.tgz", + "integrity": "sha512-OE5UE4+nBOro8Dyvv0lfx+SRtfVIOM9uhKqFmJeUbGriqhhStgp1A0OyBpgy3OUF8AhYCT+PVwPC1gMl2ZcQMA==", "dev": true }, "node_modules/chalk": { @@ -1553,9 +1553,9 @@ } }, "node_modules/core-js-compat": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.10.0.tgz", - "integrity": "sha512-9yVewub2MXNYyGvuLnMHcN1k9RkvB7/ofktpeKTIaASyB88YYqGzUnu0ywMMhJrDHOMiTjSHWGzR+i7Wb9Z1kQ==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.10.1.tgz", + "integrity": "sha512-ZHQTdTPkqvw2CeHiZC970NNJcnwzT6YIueDMASKt+p3WbZsLXOcoD392SkcWhkC0wBBHhlfhqGKKsNCQUozYtg==", "dev": true, "dependencies": { "browserslist": "^4.16.3", @@ -1605,9 +1605,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.3.704", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.704.tgz", - "integrity": "sha512-6cz0jvawlUe4h5AbfQWxPzb+8LzVyswGAWiGc32EJEmfj39HTQyNPkLXirc7+L4x5I6RgRkzua8Ryu5QZqc8cA==", + "version": "1.3.711", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.711.tgz", + "integrity": "sha512-XbklBVCDiUeho0PZQCjC25Ha6uBwqqJeyDhPLwLwfWRAo4x+FZFsmu1pPPkXT+B4MQMQoQULfyaMltDopfeiHQ==", "dev": true }, "node_modules/escalade": { @@ -2205,9 +2205,9 @@ } }, "node_modules/rollup": { - "version": "2.44.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.44.0.tgz", - "integrity": "sha512-rGSF4pLwvuaH/x4nAS+zP6UNn5YUDWf/TeEU5IoXSZKBbKRNTCI3qMnYXKZgrC0D2KzS2baiOZt1OlqhMu5rnQ==", + "version": "2.45.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.45.0.tgz", + "integrity": "sha512-JJznbtGIsHZfKH0Sa9RpCAy5JarH8SWvBzRAGuRkgzAafb8e8D7VSMJ0O1Bsix1nn91koN/Ecvl2+ZWhljcuTw==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -2531,15 +2531,15 @@ } }, "@babel/compat-data": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.12.tgz", - "integrity": "sha512-3eJJ841uKxeV8dcN/2yGEUy+RfgQspPEgQat85umsE1rotuquQ2AbIub4S6j7c50a2d+4myc+zSlnXeIHrOnhQ==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.15.tgz", + "integrity": "sha512-ltnibHKR1VnrU4ymHyQ/CXtNXI6yZC0oJThyW78Hft8XndANwi+9H+UIklBDraIjFEJzw8wmcM427oDd9KS5wA==", "dev": true }, "@babel/core": { - "version": "7.13.14", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.14.tgz", - "integrity": "sha512-wZso/vyF4ki0l0znlgM4inxbdrUvCb+cVz8grxDq+6C9k6qbqoIJteQOKicaKjCipU3ISV+XedCqpL2RJJVehA==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.15.tgz", + "integrity": "sha512-6GXmNYeNjS2Uz+uls5jalOemgIhnTMeaXo+yBUA72kC2uX/8VW6XyhVIo2L8/q0goKQA3EVKx0KOQpVKSeWadQ==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", @@ -2547,9 +2547,9 @@ "@babel/helper-compilation-targets": "^7.13.13", "@babel/helper-module-transforms": "^7.13.14", "@babel/helpers": "^7.13.10", - "@babel/parser": "^7.13.13", + "@babel/parser": "^7.13.15", "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.13", + "@babel/traverse": "^7.13.15", "@babel/types": "^7.13.14", "convert-source-map": "^1.7.0", "debug": "^4.1.0", @@ -2625,9 +2625,9 @@ } }, "@babel/helper-define-polyfill-provider": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.1.5.tgz", - "integrity": "sha512-nXuzCSwlJ/WKr8qxzW816gwyT6VZgiJG17zR40fou70yfAcqjoNyTLl/DQ+FExw5Hx5KNqshmN8Ldl/r2N7cTg==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.0.tgz", + "integrity": "sha512-JT8tHuFjKBo8NnaUbblz7mIu1nnvUDiHVjXXkulZULyidvo/7P6TY7+YqpV37IfF+KUFxmlK04elKtGKXaiVgw==", "dev": true, "requires": { "@babel/helper-compilation-targets": "^7.13.0", @@ -2825,9 +2825,9 @@ } }, "@babel/parser": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.13.tgz", - "integrity": "sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.15.tgz", + "integrity": "sha512-b9COtcAlVEQljy/9fbcMHpG+UIW9ReF+gpaxDHTlZd0c6/UU9ng8zdySAW9sRTzpvcdCHn6bUcbuYUgGzLAWVQ==", "dev": true }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { @@ -2842,9 +2842,9 @@ } }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.8.tgz", - "integrity": "sha512-rPBnhj+WgoSmgq+4gQUtXx/vOcU+UYtjy1AA/aeD61Hwj410fwYyqfUcRP3lR8ucgliVJL/G7sXcNUecC75IXA==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.15.tgz", + "integrity": "sha512-VapibkWzFeoa6ubXy/NgV5U2U4MVnUlvnx6wo1XhlsaTrLYWE0UFpDQsVrmn22q5CzeloqJ8gEMHSKxuee6ZdA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.13.0", @@ -3314,9 +3314,9 @@ } }, "@babel/plugin-transform-regenerator": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.13.tgz", - "integrity": "sha512-lxb2ZAvSLyJ2PEe47hoGWPmW22v7CtSl9jW8mingV4H2sEX/JOcrAj2nPuGWi56ERUm2bUpjKzONAuT6HCn2EA==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.13.15.tgz", + "integrity": "sha512-Bk9cOLSz8DiurcMETZ8E2YtIVJbFCPGW28DJWUakmyVWtQSm6Wsf0p4B4BfEr/eL2Nkhe/CICiUiMOCi1TPhuQ==", "dev": true, "requires": { "regenerator-transform": "^0.14.2" @@ -3397,17 +3397,17 @@ } }, "@babel/preset-env": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.13.12.tgz", - "integrity": "sha512-JzElc6jk3Ko6zuZgBtjOd01pf9yYDEIH8BcqVuYIuOkzOwDesoa/Nz4gIo4lBG6K861KTV9TvIgmFuT6ytOaAA==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.13.15.tgz", + "integrity": "sha512-D4JAPMXcxk69PKe81jRJ21/fP/uYdcTZ3hJDF5QX2HSI9bBxxYw/dumdR6dGumhjxlprHPE4XWoPaqzZUVy2MA==", "dev": true, "requires": { - "@babel/compat-data": "^7.13.12", - "@babel/helper-compilation-targets": "^7.13.10", + "@babel/compat-data": "^7.13.15", + "@babel/helper-compilation-targets": "^7.13.13", "@babel/helper-plugin-utils": "^7.13.0", "@babel/helper-validator-option": "^7.12.17", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.13.12", - "@babel/plugin-proposal-async-generator-functions": "^7.13.8", + "@babel/plugin-proposal-async-generator-functions": "^7.13.15", "@babel/plugin-proposal-class-properties": "^7.13.0", "@babel/plugin-proposal-dynamic-import": "^7.13.8", "@babel/plugin-proposal-export-namespace-from": "^7.12.13", @@ -3455,7 +3455,7 @@ "@babel/plugin-transform-object-super": "^7.12.13", "@babel/plugin-transform-parameters": "^7.13.0", "@babel/plugin-transform-property-literals": "^7.12.13", - "@babel/plugin-transform-regenerator": "^7.12.13", + "@babel/plugin-transform-regenerator": "^7.13.15", "@babel/plugin-transform-reserved-words": "^7.12.13", "@babel/plugin-transform-shorthand-properties": "^7.12.13", "@babel/plugin-transform-spread": "^7.13.0", @@ -3465,10 +3465,10 @@ "@babel/plugin-transform-unicode-escapes": "^7.12.13", "@babel/plugin-transform-unicode-regex": "^7.12.13", "@babel/preset-modules": "^0.1.4", - "@babel/types": "^7.13.12", - "babel-plugin-polyfill-corejs2": "^0.1.4", - "babel-plugin-polyfill-corejs3": "^0.1.3", - "babel-plugin-polyfill-regenerator": "^0.1.2", + "@babel/types": "^7.13.14", + "babel-plugin-polyfill-corejs2": "^0.2.0", + "babel-plugin-polyfill-corejs3": "^0.2.0", + "babel-plugin-polyfill-regenerator": "^0.2.0", "core-js-compat": "^3.9.0", "semver": "^6.3.0" } @@ -3507,17 +3507,17 @@ } }, "@babel/traverse": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.13.tgz", - "integrity": "sha512-CblEcwmXKR6eP43oQGG++0QMTtCjAsa3frUuzHoiIJWpaIIi8dwMyEFUJoXRLxagGqCK+jALRwIO+o3R9p/uUg==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.15.tgz", + "integrity": "sha512-/mpZMNvj6bce59Qzl09fHEs8Bt8NnpEDQYleHUPZQ3wXUMvXi+HJPLars68oAbmp839fGoOkv2pSL2z9ajCIaQ==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", "@babel/generator": "^7.13.9", "@babel/helper-function-name": "^7.12.13", "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.13", - "@babel/types": "^7.13.13", + "@babel/parser": "^7.13.15", + "@babel/types": "^7.13.14", "debug": "^4.1.0", "globals": "^11.1.0" } @@ -3605,9 +3605,9 @@ } }, "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -3624,33 +3624,33 @@ } }, "babel-plugin-polyfill-corejs2": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.1.10.tgz", - "integrity": "sha512-DO95wD4g0A8KRaHKi0D51NdGXzvpqVLnLu5BTvDlpqUEpTmeEtypgC1xqesORaWmiUOQI14UHKlzNd9iZ2G3ZA==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.0.tgz", + "integrity": "sha512-9bNwiR0dS881c5SHnzCmmGlMkJLl0OUZvxrxHo9w/iNoRuqaPjqlvBf4HrovXtQs/au5yKkpcdgfT1cC5PAZwg==", "dev": true, "requires": { - "@babel/compat-data": "^7.13.0", - "@babel/helper-define-polyfill-provider": "^0.1.5", + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.2.0", "semver": "^6.1.1" } }, "babel-plugin-polyfill-corejs3": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.1.7.tgz", - "integrity": "sha512-u+gbS9bbPhZWEeyy1oR/YaaSpod/KDT07arZHb80aTpl8H5ZBq+uN1nN9/xtX7jQyfLdPfoqI4Rue/MQSWJquw==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.0.tgz", + "integrity": "sha512-zZyi7p3BCUyzNxLx8KV61zTINkkV65zVkDAFNZmrTCRVhjo1jAS+YLvDJ9Jgd/w2tsAviCwFHReYfxO3Iql8Yg==", "dev": true, "requires": { - "@babel/helper-define-polyfill-provider": "^0.1.5", - "core-js-compat": "^3.8.1" + "@babel/helper-define-polyfill-provider": "^0.2.0", + "core-js-compat": "^3.9.1" } }, "babel-plugin-polyfill-regenerator": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.1.6.tgz", - "integrity": "sha512-OUrYG9iKPKz8NxswXbRAdSwF0GhRdIEMTloQATJi4bDuFqrXaXcCUT/VGNrr8pBcjMh1RxZ7Xt9cytVJTJfvMg==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.0.tgz", + "integrity": "sha512-J7vKbCuD2Xi/eEHxquHN14bXAW9CXtecwuLrOIDJtcZzTaPzV1VdEfoUf9AzcRBMolKUQKM9/GVojeh0hFiqMg==", "dev": true, "requires": { - "@babel/helper-define-polyfill-provider": "^0.1.5" + "@babel/helper-define-polyfill-provider": "^0.2.0" } }, "binary-extensions": { @@ -3698,9 +3698,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001205", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001205.tgz", - "integrity": "sha512-TL1GrS5V6LElbitPazidkBMD9sa448bQDDLrumDqaggmKFcuU2JW1wTOHJPukAcOMtEmLcmDJEzfRrf+GjM0Og==", + "version": "1.0.30001208", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001208.tgz", + "integrity": "sha512-OE5UE4+nBOro8Dyvv0lfx+SRtfVIOM9uhKqFmJeUbGriqhhStgp1A0OyBpgy3OUF8AhYCT+PVwPC1gMl2ZcQMA==", "dev": true }, "chalk": { @@ -3767,9 +3767,9 @@ } }, "core-js-compat": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.10.0.tgz", - "integrity": "sha512-9yVewub2MXNYyGvuLnMHcN1k9RkvB7/ofktpeKTIaASyB88YYqGzUnu0ywMMhJrDHOMiTjSHWGzR+i7Wb9Z1kQ==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.10.1.tgz", + "integrity": "sha512-ZHQTdTPkqvw2CeHiZC970NNJcnwzT6YIueDMASKt+p3WbZsLXOcoD392SkcWhkC0wBBHhlfhqGKKsNCQUozYtg==", "dev": true, "requires": { "browserslist": "^4.16.3", @@ -3803,9 +3803,9 @@ } }, "electron-to-chromium": { - "version": "1.3.704", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.704.tgz", - "integrity": "sha512-6cz0jvawlUe4h5AbfQWxPzb+8LzVyswGAWiGc32EJEmfj39HTQyNPkLXirc7+L4x5I6RgRkzua8Ryu5QZqc8cA==", + "version": "1.3.711", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.711.tgz", + "integrity": "sha512-XbklBVCDiUeho0PZQCjC25Ha6uBwqqJeyDhPLwLwfWRAo4x+FZFsmu1pPPkXT+B4MQMQoQULfyaMltDopfeiHQ==", "dev": true }, "escalade": { @@ -4263,9 +4263,9 @@ } }, "rollup": { - "version": "2.44.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.44.0.tgz", - "integrity": "sha512-rGSF4pLwvuaH/x4nAS+zP6UNn5YUDWf/TeEU5IoXSZKBbKRNTCI3qMnYXKZgrC0D2KzS2baiOZt1OlqhMu5rnQ==", + "version": "2.45.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.45.0.tgz", + "integrity": "sha512-JJznbtGIsHZfKH0Sa9RpCAy5JarH8SWvBzRAGuRkgzAafb8e8D7VSMJ0O1Bsix1nn91koN/Ecvl2+ZWhljcuTw==", "dev": true, "requires": { "fsevents": "~2.3.1" diff --git a/src/autoComplete.js b/src/autoComplete.js index 83729f89..723626d5 100644 --- a/src/autoComplete.js +++ b/src/autoComplete.js @@ -19,16 +19,17 @@ export default class autoComplete { constructor(config) { // Deconstructing config values const { - name = "Search", selector = "#autoComplete", + placeHolder, observer = false, data: { src, key, cache = false, store, results }, query, trigger: { event = ["input"], condition = false } = {}, - searchEngine = "strict", - diacritics = false, threshold = 1, debounce = 0, + diacritics = false, + searchEngine = "strict", + feedback, resultsList: { render: resultsListRender = true, container = false, @@ -37,35 +38,33 @@ export default class autoComplete { element: resultsListElement = "ul", idName: resultsListId = "autoComplete_list", className: resultsListClass = "autoComplete_list", + maxResults = 5, navigation = false, + noResults, } = {}, - sort = false, - placeHolder, - maxResults = 5, resultItem: { content = false, element: resultItemElement = "li", - idName: resultItemId = "autoComplete_result", + idName: resultItemId, className: resultItemClass = "autoComplete_result", + highlight: { render: highlightRender = false, className: highlightClass = "autoComplete_highlighted" } = {}, + selected: { className: selectedClass = "autoComplete_selected" } = {}, } = {}, - noResults, - selection: { className: selectionClass = "autoComplete_selected" } = {}, - highlight: { render: highlightRender = false, className: highlightClass = "autoComplete_highlighted" } = {}, - feedback, - onSelection, + onSelection, // Action function on result selection } = config; // Assigning config values to properties - this.name = name; this.selector = selector; this.observer = observer; + this.placeHolder = placeHolder; this.data = { src, key, cache, store, results }; this.query = query; this.trigger = { event, condition }; - this.searchEngine = searchEngine; - this.diacritics = diacritics; this.threshold = threshold; this.debounce = debounce; + this.diacritics = diacritics; + this.searchEngine = searchEngine; + this.feedback = feedback; this.resultsList = { render: resultsListRender, container, @@ -74,16 +73,18 @@ export default class autoComplete { element: resultsListElement, idName: resultsListId, className: resultsListClass, + maxResults: maxResults, navigation, + noResults: noResults, + }; + this.resultItem = { + content, + element: resultItemElement, + idName: resultItemId, + className: resultItemClass, + highlight: { render: highlightRender, className: highlightClass }, + selected: { className: selectedClass }, }; - this.sort = sort; - this.placeHolder = placeHolder; - this.maxResults = maxResults; - this.resultItem = { content, element: resultItemElement, idName: resultItemId, className: resultItemClass }; - this.noResults = noResults; - this.selection = { className: selectionClass }; - this.highlight = { render: highlightRender, className: highlightClass }; - this.feedback = feedback; this.onSelection = onSelection; // Assign the input field selector @@ -100,7 +101,7 @@ export default class autoComplete { ? this.data.results(listMatchingResults(this, query)) : listMatchingResults(this, query); // 2- Prepare data feedback object - const dataFeedback = { input, query, matches: results, results: results.slice(0, this.maxResults) }; + const dataFeedback = { input, query, matches: results, results: results.slice(0, this.resultsList.maxResults) }; /** * @emits {results} Emits Event on search response with results **/ @@ -118,10 +119,10 @@ export default class autoComplete { /** * @desc * Listens for all `click` events in the document - * and closes this menu if clicked outside the list and input field + * and closes list if clicked outside the list and inputField * @listens {click} Listens to all `click` events on the document **/ - document.addEventListener("click", (event) => closeList(this)); + document.addEventListener("click", (event) => closeList(this, event.target)); } async dataStore() { diff --git a/src/components/Item.js b/src/components/Item.js index accac4f2..9c3b1730 100644 --- a/src/components/Item.js +++ b/src/components/Item.js @@ -14,6 +14,7 @@ export default (item, index, config) => { result.setAttribute("class", config.resultItem.className); result.setAttribute("role", "option"); result.innerHTML = item.match; + // If custom content set pass params if (config.resultItem.content) config.resultItem.content(item, result); return result; diff --git a/src/components/List.js b/src/components/List.js index 7eaf7d28..27d9e8f8 100644 --- a/src/components/List.js +++ b/src/components/List.js @@ -9,7 +9,6 @@ export default (config) => { // Create a DIV element that will contain the results items const list = document.createElement(config.resultsList.element); list.setAttribute("id", config.resultsList.idName); - list.setAttribute("aria-label", config.name); list.setAttribute("class", config.resultsList.className); list.setAttribute("role", "listbox"); list.setAttribute("tabindex", "-1"); diff --git a/src/controllers/dataController.js b/src/controllers/dataController.js index d41a30d2..fc630e90 100644 --- a/src/controllers/dataController.js +++ b/src/controllers/dataController.js @@ -100,10 +100,8 @@ const listMatchingResults = (config, query) => { search(); } } - // Sorting / Slicing final results list - const list = config.sort ? resList.sort(config.sort) : resList; // Returns rendered list - return list; + return resList; }; export { getInputValue, prepareQueryValue, checkTriggerCondition, listMatchingResults }; diff --git a/src/controllers/listController.js b/src/controllers/listController.js index 2344119e..215fe32d 100644 --- a/src/controllers/listController.js +++ b/src/controllers/listController.js @@ -9,10 +9,10 @@ import eventEmitter from "../utils/eventEmitter"; * @param {Element} element - Current selected element * */ -const closeList = (config) => { - // Get all autoComplete lists +const closeList = (config, element) => { + // Get autoComplete list const list = document.getElementById(config.resultsList.idName); - if (list) { + if (list && element !== config.inputField) { // Remove open list list.remove(); // Remove active descendant @@ -36,6 +36,7 @@ const closeList = (config) => { * @return {Component} - The matching results list component */ const generateList = (config, data, matches) => { + // Results list element let list = document.getElementById(config.resultsList.idName); // Check if there is a rendered list @@ -78,7 +79,11 @@ const generateList = (config, data, matches) => { } else { // Check if there are NO results // Run noResults action function - config.noResults(list, data.query); + if (!config.resultsList.noResults) { + list.remove(); + } else { + config.resultsList.noResults(list, data.query); + } } }; diff --git a/src/controllers/navigationController.js b/src/controllers/navigationController.js index bc8aeb1b..9a42e64a 100644 --- a/src/controllers/navigationController.js +++ b/src/controllers/navigationController.js @@ -21,10 +21,9 @@ const navigate = (config, dataFeedback) => { * @param {Object} event - The `keydown` event Object * @param {Array } list - The array of list items * @param {Boolean} state - Of the arrow Down/Up - * @param {Object} config - autoComplete configurations * */ - const update = (event, list, state, config) => { + const update = (event, list, state) => { event.preventDefault(); if (state) { // If the arrow DOWN or TAB key is pressed @@ -60,7 +59,7 @@ const navigate = (config, dataFeedback) => { // Remove "active" class from the item list[index].removeAttribute("aria-selected"); // list[index].setAttribute("aria-selected", "false"); - if (config.selection.className) list[index].classList.remove(config.selection.className); + if (config.resultItem.selected.className) list[index].classList.remove(config.resultItem.selected.className); } }; @@ -79,7 +78,7 @@ const navigate = (config, dataFeedback) => { if (currentFocus < 0) currentFocus = list.length - 1; // Add "active" class to the item list[currentFocus].setAttribute("aria-selected", "true"); - if (config.selection.className) list[currentFocus].classList.add(config.selection.className); + if (config.resultItem.selected.className) list[currentFocus].classList.add(config.resultItem.selected.className); }; /** @@ -100,28 +99,34 @@ const navigate = (config, dataFeedback) => { list = list.getElementsByTagName(config.resultItem.element); // Check pressed key - if (event.keyCode === 27) { - // If the ESC key is pressed - // Clear Input value - config.inputField.value = ""; - // Closes open list - closeList(config); - } else if (event.keyCode === 40 || event.keyCode === 9) { - // Update list items state - update(event, list, true, config); - } else if (event.keyCode === 38 || event.keyCode === 9) { - // Update list items state - update(event, list, false, config); - } else if (event.keyCode === 13) { - // If the ENTER key is pressed - // prevent the form from its default behaviour "being submitted" - event.preventDefault(); - if (currentFocus > -1) { - // Simulate a click on the selected "active" item - list[currentFocus].click(); + switch (event.keyCode) { + case 27: + // If the ESC key is pressed + // Clear Input value + config.inputField.value = ""; // Closes open list closeList(config); - } + break; + case 9: + case 40: + // Update list items state + update(event, list, true); + break; + case 38: + // Update list items state + update(event, list, false); + break; + case 13: + // If the ENTER key is pressed + // prevent the form from its default behaviour "being submitted" + event.preventDefault(); + if (currentFocus > -1) { + // Simulate a click on the selected "active" item + list[currentFocus].click(); + // Closes open list + closeList(config); + } + break; } } }; diff --git a/src/services/search.js b/src/services/search.js index 46b1359b..7ed1c22c 100644 --- a/src/services/search.js +++ b/src/services/search.js @@ -31,8 +31,8 @@ export default (query, record, config) => { // Matching case if (searchPosition < query.length && recordLowerCase[number] === query[searchPosition]) { // Highlight matching character - recordChar = config.highlight.render - ? `${recordChar}` + recordChar = config.resultItem.highlight.render + ? `${recordChar}` : recordChar; // Increment search position searchPosition++; @@ -52,8 +52,8 @@ export default (query, record, config) => { const pattern = new RegExp(query.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"), "i"); // Search for a match Query in Record query = pattern.exec(record); - const match = config.highlight.render - ? record.replace(query, `${query}`) + const match = config.resultItem.highlight.render + ? record.replace(query, `${query}`) : record; // Returns the match return match;