Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@tarekraafat/autocomplete.js

Package Overview
Dependencies
Maintainers
1
Versions
77
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tarekraafat/autocomplete.js - npm Package Compare versions

Comparing version 4.0.0 to 5.0.0

196

dist/js/autoComplete.js

@@ -39,3 +39,3 @@ (function (global, factory) {

var createResultsList = function createResultsList(renderResults) {
var resultsList = document.createElement("ul");
var resultsList = document.createElement(renderResults.element);
if (renderResults.container) {

@@ -51,5 +51,5 @@ select.resultsList = renderResults.container(resultsList) || select.resultsList;

};
var addResultsToList = function addResultsToList(resultsList, dataSrc, dataKey, callback) {
var addResultsToList = function addResultsToList(resultsList, dataSrc, resultItem) {
dataSrc.forEach(function (event, record) {
var result = document.createElement("li");
var result = document.createElement(resultItem.element);
var resultValue = dataSrc[record].value[event.key] || dataSrc[record].value;

@@ -59,3 +59,3 @@ result.setAttribute(dataAttribute, resultValue);

result.setAttribute("tabindex", "1");
result.innerHTML = callback ? callback(event, result) : event.match || event;
result.innerHTML = resultItem.content ? resultItem.content(event, result) : event.match || event;
resultsList.appendChild(result);

@@ -133,10 +133,22 @@ });

},
key: config.data.key
key: config.data.key,
cache: typeof config.data.cache === "undefined" ? true : config.data.cache
};
this.searchEngine = config.searchEngine === "loose" ? "loose" : "strict";
this.threshold = config.threshold || 0;
this.debounce = config.debounce || 0;
this.resultsList = autoCompleteView.createResultsList({
container: config.resultsList && config.resultsList.container ? config.resultsList.container : false,
destination: config.resultsList && config.resultsList.destination ? config.resultsList.destination : autoCompleteView.getInput(this.selector),
position: config.resultsList && config.resultsList.position ? config.resultsList.position : "afterend"
container:
config.resultsList && config.resultsList.container
? config.resultsList.container
: false,
destination:
config.resultsList && config.resultsList.destination
? config.resultsList.destination
: autoCompleteView.getInput(this.selector),
position:
config.resultsList && config.resultsList.position
? config.resultsList.position
: "afterend",
element: config.resultsList && config.resultsList.element ? config.resultsList.element : "ul"
});

@@ -146,5 +158,9 @@ this.sort = config.sort || false;

this.maxResults = config.maxResults || 5;
this.resultItem = config.resultItem;
this.resultItem = {
content: config.resultItem && config.resultItem.content ? config.resultItem.content : false,
element: config.resultItem && config.resultItem.element ? config.resultItem.element : "li"
};
this.highlight = config.highlight || false;
this.onSelection = config.onSelection;
this.dataSrc;
this.init();

@@ -185,60 +201,62 @@ }

var _this = this;
var resList = [];
var inputValue = autoCompleteView.getInput(this.selector).value.toLowerCase();
data.filter(function (record, index) {
var search = function search(key) {
var match = _this.search(inputValue, record[key] || record);
if (match && key) {
resList.push({
key: key,
index: index,
match: match,
value: record
});
} else if (match && !key) {
resList.push({
index: index,
match: match,
value: record
});
}
};
if (_this.data.key) {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = _this.data.key[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var key = _step.value;
search(key);
return new Promise(function (resolve) {
var resList = [];
var inputValue = autoCompleteView.getInput(_this.selector).value.toLowerCase();
data.filter(function (record, index) {
var search = function search(key) {
var match = _this.search(inputValue, record[key] || record);
if (match && key) {
resList.push({
key: key,
index: index,
match: match,
value: record
});
} else if (match && !key) {
resList.push({
index: index,
match: match,
value: record
});
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
};
if (_this.data.key) {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
for (var _iterator = _this.data.key[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var key = _step.value;
search(key);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
if (_didIteratorError) {
throw _iteratorError;
try {
if (!_iteratorNormalCompletion && _iterator["return"] != null) {
_iterator["return"]();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
} else {
search();
}
} else {
search();
}
});
var list = _this.sort ? resList.sort(_this.sort).slice(0, _this.maxResults) : resList.slice(0, _this.maxResults);
autoCompleteView.addResultsToList(_this.resultsList, list, _this.resultItem);
autoCompleteView.navigation(_this.selector, _this.resultsList);
return resolve({
matches: resList.length,
list: list
});
});
var list = this.sort ? resList.sort(this.sort).slice(0, this.maxResults) : resList.slice(0, this.maxResults);
autoCompleteView.addResultsToList(this.resultsList, list, this.data.key, this.resultItem);
autoCompleteView.navigation(this.selector, this.resultsList);
return {
matches: resList.length,
list: list
};
}
}, {
key: "ignite",
value: function ignite(data) {
value: function ignite() {
var _this2 = this;

@@ -252,22 +270,50 @@ var selector = this.selector;

}
input.onkeyup = function (event) {
var debounce = function debounce(func, delay) {
var inDebounce;
return function () {
var context = this;
var args = arguments;
clearTimeout(inDebounce);
inDebounce = setTimeout(function () {
return func.apply(context, args);
}, delay);
};
};
var exec = function exec(event) {
var resultsList = _this2.resultsList;
var clearResults = autoCompleteView.clearResults(resultsList);
if (input.value.length > _this2.threshold && input.value.replace(/ /g, "").length) {
var list = _this2.listMatchedResults(data);
input.dispatchEvent(new CustomEvent("type", {
bubbles: true,
detail: {
event: event,
query: input.value,
matches: list.matches,
results: list.list
},
cancelable: true
}));
if (onSelection) {
autoCompleteView.getSelection(selector, resultsList, onSelection, list);
_this2.listMatchedResults(_this2.dataSrc).then(function (list) {
input.dispatchEvent(new CustomEvent("type", {
bubbles: true,
detail: {
event: event,
query: input.value,
matches: list.matches,
results: list.list
},
cancelable: true
}));
if (onSelection) {
autoCompleteView.getSelection(selector, resultsList, onSelection, list);
}
});
}
};
input.addEventListener("keyup", debounce(function (event) {
if (!_this2.data.cache) {
var data = _this2.data.src();
if (data instanceof Promise) {
data.then(function (response) {
_this2.dataSrc = response;
exec(event);
});
} else {
_this2.dataSrc = data;
exec(event);
}
} else {
exec(event);
}
};
}, this.debounce));
}

@@ -280,7 +326,9 @@ }, {

if (dataSrc instanceof Promise) {
dataSrc.then(function (data) {
return _this3.ignite(data);
dataSrc.then(function (response) {
_this3.dataSrc = response;
_this3.ignite();
});
} else {
this.ignite(dataSrc);
this.dataSrc = dataSrc;
this.ignite();
}

@@ -287,0 +335,0 @@ }

@@ -1,1 +0,1 @@

var a,b;a=this,b=function(){"use strict";function n(t,e){for(var s=0;s<e.length;s++){var i=e[s];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}var a="data-result",l={resultsList:"autoComplete_results_list",result:"autoComplete_result",highlight:"autoComplete_highlighted"},u=function(t){return"string"==typeof t?document.querySelector(t):t()},c=function(t){return t.innerHTML=""},h=u,r=function(t){var e=document.createElement("ul");return t.container&&(l.resultsList=t.container(e)||l.resultsList),e.setAttribute("id",l.resultsList),t.destination.insertAdjacentElement(t.position,e),e},f=function(t){return"<span class=".concat(l.highlight,">").concat(t,"</span>")},o=function(n,r,t,o){r.forEach(function(t,e){var s=document.createElement("li"),i=r[e].value[t.key]||r[e].value;s.setAttribute(a,i),s.setAttribute("class",l.result),s.setAttribute("tabindex","1"),s.innerHTML=o?o(t,s):t.match||t,n.appendChild(s)})},d=function(t,s){var i=u(t),n=s.firstChild;document.onkeydown=function(t){var e=document.activeElement;switch(t.keyCode){case 38:e!==n&&e!==i?e.previousSibling.focus():e===n&&i.focus();break;case 40:e===i&&0<s.childNodes.length?n.focus():e!==s.lastChild&&e.nextSibling.focus()}}},v=c,m=function(s,i,n,r){var o=i.querySelectorAll(".".concat(l.result));Object.keys(o).forEach(function(e){["mousedown","keydown"].forEach(function(t){o[e].addEventListener(t,function(e){"mousedown"!==t&&13!==e.keyCode&&39!==e.keyCode||(n({event:e,query:u(s).value,matches:r.matches,results:r.list.map(function(t){return t.value}),selection:r.list.find(function(t){return(t.value[t.key]||t.value)===e.target.closest(".".concat(l.result)).getAttribute(a)})}),c(i))})})})};return function(){function e(t){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),this.selector=t.selector||"#autoComplete",this.data={src:function(){return"function"==typeof t.data.src?t.data.src():t.data.src},key:t.data.key},this.searchEngine="loose"===t.searchEngine?"loose":"strict",this.threshold=t.threshold||0,this.resultsList=r({container:!(!t.resultsList||!t.resultsList.container)&&t.resultsList.container,destination:t.resultsList&&t.resultsList.destination?t.resultsList.destination:h(this.selector),position:t.resultsList&&t.resultsList.position?t.resultsList.position:"afterend"}),this.sort=t.sort||!1,this.placeHolder=t.placeHolder,this.maxResults=t.maxResults||5,this.resultItem=t.resultItem,this.highlight=t.highlight||!1,this.onSelection=t.onSelection,this.init()}var t,s,i;return t=e,(s=[{key:"search",value:function(t,e){var s=this.highlight,i=e.toLowerCase();if("loose"===this.searchEngine){t=t.replace(/ /g,"");for(var n=[],r=0,o=0;o<i.length;o++){var a=e[o];r<t.length&&i[o]===t[r]&&(a=s?f(a):a,r++),n.push(a)}return r===t.length&&n.join("")}if(i.includes(t))return t=new RegExp("".concat(t),"i").exec(e),s?e.replace(t,f(t)):e}},{key:"listMatchedResults",value:function(t){var l=this,u=[],c=h(this.selector).value.toLowerCase();t.filter(function(s,i){var t=function(t){var e=l.search(c,s[t]||s);e&&t?u.push({key:t,index:i,match:e,value:s}):e&&!t&&u.push({index:i,match:e,value:s})};if(l.data.key){var e=!0,n=!1,r=void 0;try{for(var o,a=l.data.key[Symbol.iterator]();!(e=(o=a.next()).done);e=!0){t(o.value)}}catch(t){n=!0,r=t}finally{try{e||null==a.return||a.return()}finally{if(n)throw r}}}else t()});var e=this.sort?u.sort(this.sort).slice(0,this.maxResults):u.slice(0,this.maxResults);return o(this.resultsList,e,this.data.key,this.resultItem),d(this.selector,this.resultsList),{matches:u.length,list:e}}},{key:"ignite",value:function(i){var n=this,r=this.selector,o=h(r),t=this.placeHolder,a=this.onSelection;t&&o.setAttribute("placeholder",t),o.onkeyup=function(t){var e=n.resultsList;v(e);if(o.value.length>n.threshold&&o.value.replace(/ /g,"").length){var s=n.listMatchedResults(i);o.dispatchEvent(new CustomEvent("type",{bubbles:!0,detail:{event:t,query:o.value,matches:s.matches,results:s.list},cancelable:!0})),a&&m(r,e,a,s)}}}},{key:"init",value:function(){var e=this,t=this.data.src();t instanceof Promise?t.then(function(t){return e.ignite(t)}):this.ignite(t)}}])&&n(t.prototype,s),i&&n(t,i),e}()},"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.autoComplete=b();
var a,b;a=this,b=function(){"use strict";function i(t,e){for(var n=0;n<e.length;n++){var s=e[n];s.enumerable=s.enumerable||!1,s.configurable=!0,"value"in s&&(s.writable=!0),Object.defineProperty(t,s.key,s)}}var o="data-result",l={resultsList:"autoComplete_results_list",result:"autoComplete_result",highlight:"autoComplete_highlighted"},u=function(t){return"string"==typeof t?document.querySelector(t):t()},c=function(t){return t.innerHTML=""},h=u,r=function(t){var e=document.createElement(t.element);return t.container&&(l.resultsList=t.container(e)||l.resultsList),e.setAttribute("id",l.resultsList),t.destination.insertAdjacentElement(t.position,e),e},d=function(t){return"<span class=".concat(l.highlight,">").concat(t,"</span>")},a=function(i,r,a){r.forEach(function(t,e){var n=document.createElement(a.element),s=r[e].value[t.key]||r[e].value;n.setAttribute(o,s),n.setAttribute("class",l.result),n.setAttribute("tabindex","1"),n.innerHTML=a.content?a.content(t,n):t.match||t,i.appendChild(n)})},f=function(t,n){var s=u(t),i=n.firstChild;document.onkeydown=function(t){var e=document.activeElement;switch(t.keyCode){case 38:e!==i&&e!==s?e.previousSibling.focus():e===i&&s.focus();break;case 40:e===s&&0<n.childNodes.length?i.focus():e!==n.lastChild&&e.nextSibling.focus()}}},m=c,v=function(n,s,i,r){var a=s.querySelectorAll(".".concat(l.result));Object.keys(a).forEach(function(e){["mousedown","keydown"].forEach(function(t){a[e].addEventListener(t,function(e){"mousedown"!==t&&13!==e.keyCode&&39!==e.keyCode||(i({event:e,query:u(n).value,matches:r.matches,results:r.list.map(function(t){return t.value}),selection:r.list.find(function(t){return(t.value[t.key]||t.value)===e.target.closest(".".concat(l.result)).getAttribute(o)})}),c(s))})})})};return function(){function e(t){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),this.selector=t.selector||"#autoComplete",this.data={src:function(){return"function"==typeof t.data.src?t.data.src():t.data.src},key:t.data.key,cache:void 0===t.data.cache||t.data.cache},this.searchEngine="loose"===t.searchEngine?"loose":"strict",this.threshold=t.threshold||0,this.debounce=t.debounce||0,this.resultsList=r({container:!(!t.resultsList||!t.resultsList.container)&&t.resultsList.container,destination:t.resultsList&&t.resultsList.destination?t.resultsList.destination:h(this.selector),position:t.resultsList&&t.resultsList.position?t.resultsList.position:"afterend",element:t.resultsList&&t.resultsList.element?t.resultsList.element:"ul"}),this.sort=t.sort||!1,this.placeHolder=t.placeHolder,this.maxResults=t.maxResults||5,this.resultItem={content:!(!t.resultItem||!t.resultItem.content)&&t.resultItem.content,element:t.resultItem&&t.resultItem.element?t.resultItem.element:"li"},this.highlight=t.highlight||!1,this.onSelection=t.onSelection,this.dataSrc,this.init()}var t,n,s;return t=e,(n=[{key:"search",value:function(t,e){var n=this.highlight,s=e.toLowerCase();if("loose"===this.searchEngine){t=t.replace(/ /g,"");for(var i=[],r=0,a=0;a<s.length;a++){var o=e[a];r<t.length&&s[a]===t[r]&&(o=n?d(o):o,r++),i.push(o)}return r===t.length&&i.join("")}if(s.includes(t))return t=new RegExp("".concat(t),"i").exec(e),n?e.replace(t,d(t)):e}},{key:"listMatchedResults",value:function(n){var c=this;return new Promise(function(t){var l=[],u=h(c.selector).value.toLowerCase();n.filter(function(n,s){var t=function(t){var e=c.search(u,n[t]||n);e&&t?l.push({key:t,index:s,match:e,value:n}):e&&!t&&l.push({index:s,match:e,value:n})};if(c.data.key){var e=!0,i=!1,r=void 0;try{for(var a,o=c.data.key[Symbol.iterator]();!(e=(a=o.next()).done);e=!0){t(a.value)}}catch(t){i=!0,r=t}finally{try{e||null==o.return||o.return()}finally{if(i)throw r}}}else t()});var e=c.sort?l.sort(c.sort).slice(0,c.maxResults):l.slice(0,c.maxResults);return a(c.resultsList,e,c.resultItem),f(c.selector,c.resultsList),t({matches:l.length,list:e})})}},{key:"ignite",value:function(){var s=this,i=this.selector,r=h(i),t=this.placeHolder,a=this.onSelection;t&&r.setAttribute("placeholder",t);var n,o,l,u=function(e){var n=s.resultsList;m(n);r.value.length>s.threshold&&r.value.replace(/ /g,"").length&&s.listMatchedResults(s.dataSrc).then(function(t){r.dispatchEvent(new CustomEvent("type",{bubbles:!0,detail:{event:e,query:r.value,matches:t.matches,results:t.list},cancelable:!0})),a&&v(i,n,a,t)})};r.addEventListener("keyup",(n=function(e){if(s.data.cache)u(e);else{var t=s.data.src();t instanceof Promise?t.then(function(t){s.dataSrc=t,u(e)}):(s.dataSrc=t,u(e))}},o=this.debounce,function(){var t=this,e=arguments;clearTimeout(l),l=setTimeout(function(){return n.apply(t,e)},o)}))}},{key:"init",value:function(){var e=this,t=this.data.src();t instanceof Promise?t.then(function(t){e.dataSrc=t,e.ignite()}):(this.dataSrc=t,this.ignite())}}])&&i(t.prototype,n),s&&i(t,s),e}()},"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.autoComplete=b();
// autoComplete.js on type event emitter
document.querySelector("#autoComplete").addEventListener("type", event => {
console.log(event);
})
console.log(event);
});
// The autoComplete.js Engine instance creator

@@ -17,3 +17,3 @@ const autoCompletejs = new autoComplete({

},
key: ["food", "cities", "animals"]
key: ["food", "cities", "animals"],
},

@@ -28,2 +28,3 @@ sort: (a, b) => {

threshold: 0,
debounce: 0,
searchEngine: "strict",

@@ -38,6 +39,10 @@ highlight: true,

destination: document.querySelector("#autoComplete"),
position: "afterend"
position: "afterend",
element: "ul",
},
resultItem: (data, source) => {
return `${data.match}`;
resultItem: {
content: (data, source) => {
return `${data.match}`;
},
element: "li",
},

@@ -54,3 +59,3 @@ onSelection: feedback => {

console.log(feedback);
}
},
});

@@ -57,0 +62,0 @@

@@ -5,3 +5,3 @@ <a href="https://tarekraafat.github.io/autoComplete.js/demo/">

> Simple autocomplete pure vanilla Javascript library. <a href="https://tarekraafat.github.io/autoComplete.js/demo/" target="\_blank">Live Demo</a> **v4.0**
> Simple autocomplete pure vanilla Javascript library. <a href="https://tarekraafat.github.io/autoComplete.js/demo/" target="\_blank">Live Demo</a> **v5.0**

@@ -8,0 +8,0 @@ autoComplete.js is a simple pure vanilla Javascript library that's progressively designed for speed,<br>high versatility and seamless integration with wide range of projects & systems.

@@ -5,2 +5,3 @@ // autoComplete.js on type event emitter

});
// The autoComplete.js Engine instance creator

@@ -12,9 +13,16 @@ const autoCompletejs = new autoComplete({

document.querySelector("#autoComplete").setAttribute("placeholder", "Loading...");
// API key token
const token = "5c2d4273b2930ee4b53f4e84a7c4440d";
// User search query
const query = document.querySelector("#autoComplete").value;
// Fetch External Data Source
const source = await fetch("./db/generic.json");
const source = await fetch(`https://www.food2fork.com/api/search?key=${token}&q=${query}`);
const data = await source.json();
// Returns Fetched data
return data;
// Post loading placeholder text
document.querySelector("#autoComplete").setAttribute("placeholder", "Food & Drinks");
// Return Fetched data
return data.recipes;
},
key: ["food", "cities", "animals"]
key: ["title"],
cache: false,
},

@@ -26,8 +34,8 @@ sort: (a, b) => {

},
placeHolder: "Food & Drinks",
selector: "#autoComplete",
threshold: 0,
threshold: 3,
debounce: 300,
searchEngine: "strict",
highlight: true,
maxResults: 10,
maxResults: Infinity,
resultsList: {

@@ -39,18 +47,25 @@ container: source => {

destination: document.querySelector("#autoComplete"),
position: "afterend"
position: "afterend",
element: "ul",
},
resultItem: (data, source) => {
return `${data.match}`;
resultItem: {
content: (data, source) => {
return `${data.match}`;
},
element: "li",
},
onSelection: feedback => {
const selection = feedback.selection.value.food;
const title = feedback.selection.value.title;
const image = feedback.selection.value.image_url;
// Render selected choice to selection div
document.querySelector(".selection").innerHTML = selection;
document.querySelector(
".selection",
).innerHTML = `<span style="display: block; font-size: 25px; width: 90vw; max-width: 400px; margin-bottom: 20px;">${title}</span><img src="${image}" style="height: 30vh; border-radius: 8px; box-shadow: 0 0 80px rgba(255, 122, 122,0.2), 0 4px 10px -3px rgba(255, 122, 122,0.4), inset 0 -10px 30px -5px rgba(255, 122, 122,0.1);"></img>`;
// Clear Input
document.querySelector("#autoComplete").value = "";
// Change placeholder with the selected value
document.querySelector("#autoComplete").setAttribute("placeholder", selection);
document.querySelector("#autoComplete").setAttribute("placeholder", title);
// Concole log autoComplete data feedback
console.log(feedback);
}
},
});

@@ -57,0 +72,0 @@

@@ -9,3 +9,3 @@ # Introduction

![\[Zero Dependencies\]()](https://img.shields.io/badge/Dependencies-0-blue.svg)
![\[Size\]()](https://img.shields.io/badge/Size-4%20KB-green.svg)
![\[Size\]()](https://img.shields.io/badge/Size-5%20KB-green.svg)
[![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.svg?v=103)](https://github.com/TarekRaafat/autoComplete.js)

@@ -18,3 +18,3 @@

> Simple autocomplete pure vanilla Javascript library. <a href="https://tarekraafat.github.io/autoComplete.js/demo/" target="\_blank">:rocket: Live Demo</a> **v4.0**
> Simple autocomplete pure vanilla Javascript library. <a href="https://tarekraafat.github.io/autoComplete.js/demo/" target="\_blank">:rocket: Live Demo</a> **v5.0**

@@ -72,3 +72,3 @@ autoComplete.js is a simple pure vanilla Javascript library that's progressively designed for speed, high versatility and seamless integration with wide range of projects & systems, made for users and developers in mind.

```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/TarekRaafat/autoComplete.js@4.0.0/dist/css/autoComplete.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/TarekRaafat/autoComplete.js@5.0.0/dist/css/autoComplete.min.css">
```

@@ -79,3 +79,3 @@

```html
<script src="https://cdn.jsdelivr.net/gh/TarekRaafat/autoComplete.js@4.0.0/dist/js/autoComplete.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/TarekRaafat/autoComplete.js@5.0.0/dist/js/autoComplete.min.js"></script>
```

@@ -122,3 +122,3 @@

OR
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/TarekRaafat/autoComplete.js@4.0.0/dist/css/autoComplete.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/TarekRaafat/autoComplete.js@5.0.0/dist/css/autoComplete.min.css">
```

@@ -138,3 +138,3 @@

OR
<script src="https://cdn.jsdelivr.net/gh/TarekRaafat/autoComplete.js@4.0.0/dist/js/autoComplete.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/TarekRaafat/autoComplete.js@5.0.0/dist/js/autoComplete.min.js"></script>
<script src="./js/index.js"></script>

@@ -149,6 +149,23 @@ ```

new autoComplete({
data: { src: data, key: "food" }, // Data src [Array, Function, Async] | (REQUIRED)
data: { // Data src [Array, Function, Async] | (REQUIRED)
src: async () => {
// 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
},
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)
threshold: 0, // Min. Chars length to start Engine | (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)

@@ -161,6 +178,10 @@ resultsList: { // Rendered results list object | (Optional)

destination: document.querySelector("#autoComplete"),
position: "afterend"
position: "afterend",
element: "ul"
},
resultItem: (data, source) => { // Rendered result item | (Optional)
return `${data.match}`;
resultItem: { // Rendered result item | (Optional)
content: (data, source) => {
return `${data.match}`;
},
element: "li"
},

@@ -170,3 +191,3 @@ highlight: true, // Highlight matching results | (Optional)

onSelection: feedback => { // Action script onSelection event | (Optional)
console.log(feedback);
console.log(feedback.selection.value.image_url);
}

@@ -176,15 +197,17 @@ });

### API Configurations:
### API Configuration:
<br>
| Features | Description | Values | Default |
| Keys | Description | Values | Default |
| -------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `data` | Data Source & Data Key | **1- src**: <br> - `Array` of `Strings` / `Objects`<br>**OR**<br> - `Function` => `Array` of `Strings` / `Objects` <br> **2- key**: <br> **Required** if `src` is `Object`, it will point to `key` in the object for the search | Data `src` **REQUIRED** any **NOT** both |
| `data` | Data Source, Data Key & Data Caching | **1- src**: <br> - `Array` of `Strings` / `Objects`<br>**OR**<br> - `Function` => `Array` of `Strings` / `Objects` <br> **2- key**: <br>- `Array` of `Strings`<br>**Required** if `src` is `Object`, for search to point to desired `keys` <br> **3- Cache**: <br> - `True` for static data `src` <br> - `False` for dynamic data `src` "API" | Data `src` **REQUIRED** |
| `sort` | Sort rendered results | `Function` | Blank / Empty **(Random Results)** |
| `placeHolder` | Place Holder text | `String` | Blank / Empty |
| `selector` | Input field selector | **-** `String` `id`/`class` <br>**OR**<br> **-** `Function` ( ) => `document.querySelector("")` | `"#autoComplete"` |
| `threshold` | Minimum characters length before engine starts rendering results | `Number` | `0` |
| `debounce` | Minimum duration after typing idle state for engine to kick in | `Number` <br> Milliseconds value <br> debounce: `300` | `0` |
| `searchEngine` | Search Engine Type/Mode | **-** `"strict"` lowerCase string<br>**OR**<br>**-** `"loose"` lowerCase string | `"strict"` |
| `resultsList` | Rendered results list destination & position | **-** `Object` with 3 methods<br> 1- Container: <br> `Function` (source) => `id`<br> 2- destination: `document.querySelector("#div")`<br> 3- position:<br> `"beforebegin"`, `"afterbegin"`, `"beforeend"`, `"afterend"` lowerCase string <br>**OR**<br>**-** `Function` ( ) => `{destination: "...", position: "..."}` | `{container: (source) => { }, destination: document.querySelector("#autoComplete"), position: "afterend"}` |
| `resultItem` | Rendered result Item | **-** `Function` (data, source) => `String` <br> **-** `data.match` has to be used for **Highlighted** result | `data.match` |
| `resultsList` | Rendered results list destination, position & element | **-** `Object` with 4 methods<br> 1- container: <br> `Function` (source) => `id`<br> 2- destination: `document.querySelector("#div")`<br> 3- position:<br> `"beforebegin"`, `"afterbegin"`, `"beforeend"`, `"afterend"` lowerCase string <br>**OR**<br>**-** `Function` ( ) => `{destination: "...", position: "..."}` <br> 4- element: <br> `"ul", "span", "div" or Custom`| `{container: (source) => { }, destination: document.querySelector("#autoComplete"), position: "afterend", element: "ul"}` |
| `resultItem` | Rendered result Item content & element | **-** `Object` with 2 methods<br> 1- content: <br>**-** `Function` (data, source) => `String` <br> **-** `data.match` has to be used for **Highlighted** result <br> 2- element: <br> `"li", "span", "div" or Custom` | `{content: (data, source) => data.match, element: "li"}` |
| `highlight` | Highlight matching results | `Boolean` | `false` |

@@ -194,3 +217,3 @@ | `maxResults` | Maximum number of displayed results | `Number` | `5` |

3. That's it, you're ready to go!
1. That's it, you're ready to go!

@@ -237,3 +260,3 @@ * * *

## 5. What's New in v4.0?
## 5. What's New in v5.0?

@@ -256,11 +279,11 @@ Check out <a href="#/releases?id=versioning">Releases</a> Information :sparkles:

- [x] Choose different results render destination & position
- [ ] Sort rendered results
- [ ] Alphabet
- [ ] Weight
- [x] Sort rendered results
- [x] Results list Keyboard `ARROW` or `TAB` Navigation
- [x] Enhance error Handling (Ongoing)
- [ ] Number of returned results value
- [ ] Results Lazy Load/Pagination for External data source
- [ ] Multiple searchable `keys` for data `src`
- [x] Number of matching results
- [x] Fetching dynamically External API data source
- [x] Multiple searchable `keys` for data `src`
- [ ] Reload data `src` on data change
- [x] Event emitter on input field events
- [x] Handling large data sets

@@ -284,3 +307,4 @@ ### Usability:

- [x] Capability for multiple instances
- [ ] Render `results` in default case
- [x] Render `results` in default case
- [x] Render `resultsList` & `resultItem` in different/custom elements

@@ -287,0 +311,0 @@ * * *

@@ -29,4 +29,13 @@ ## Versioning

- v4.0.0 :sparkles:
- v5.0.0 :sparkles:
- Large datasets handeling (Thanks @Johann-S)
- API Data fetching & Dynamic Data reloading (Thanks @Brostafa)
- Debouncing API Calls
- Custom `resultsList` & `resultItem` Elements (Thanks @Johann-S)
- Bug fixes
- Code Clean Up
- v4.0.0
- Multiple searchable `keys` for data `src` (Thanks @Johann-S)

@@ -33,0 +42,0 @@ - Rendered `results` in original case (Thanks @nickbp12)

{
"name": "@tarekraafat/autocomplete.js",
"version": "4.0.0",
"version": "5.0.0",
"description": "Simple autocomplete pure vanilla Javascript library.",

@@ -51,4 +51,4 @@ "main": "dist/js/autoComplete.js",

"devDependencies": {
"@babel/core": "^7.3.4",
"@babel/preset-env": "^7.3.4",
"@babel/core": "^7.4.4",
"@babel/preset-env": "^7.4.4",
"acorn": "^6.1.1",

@@ -59,6 +59,6 @@ "local-web-server": "^2.6.1",

"rollup-plugin-cleanup": "^3.1.0",
"rollup-plugin-eslint": "^5.0.0",
"rollup-plugin-eslint": "^5.1.0",
"rollup-plugin-gzip": "^2.2.0",
"rollup-plugin-uglify": "^6.0.0"
}
}
}

@@ -9,3 +9,3 @@ # autoComplete.js :sparkles:

![\[Zero Dependencies\]()](https://img.shields.io/badge/Dependencies-0-blue.svg)
![\[Size\]()](https://img.shields.io/badge/Size-4%20KB-green.svg)
![\[Size\]()](https://img.shields.io/badge/Size-5%20KB-green.svg)
[![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.svg?v=103)](https://github.com/TarekRaafat/autoComplete.js)

@@ -23,3 +23,3 @@

> Simple autocomplete pure vanilla Javascript library. <a href="https://tarekraafat.github.io/autoComplete.js/demo/" target="\_blank">:rocket: Live Demo</a> **v4.0**
> Simple autocomplete pure vanilla Javascript library. <a href="https://tarekraafat.github.io/autoComplete.js/demo/" target="\_blank">:rocket: Live Demo</a> **v5.0**

@@ -57,3 +57,3 @@ autoComplete.js is a simple pure vanilla Javascript library that's progressively designed for speed, high versatility and seamless integration with wide range of projects & systems, made for users and developers in mind.

```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/TarekRaafat/autoComplete.js@4.0.0/dist/css/autoComplete.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/TarekRaafat/autoComplete.js@5.0.0/dist/css/autoComplete.min.css">
```

@@ -64,3 +64,3 @@

```html
<script src="https://cdn.jsdelivr.net/gh/TarekRaafat/autoComplete.js@4.0.0/dist/js/autoComplete.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/TarekRaafat/autoComplete.js@5.0.0/dist/js/autoComplete.min.js"></script>
```

@@ -67,0 +67,0 @@

@@ -9,4 +9,8 @@ import { autoCompleteView } from "../views/autoCompleteView";

this.data = {
// Data src selection
src: () => (typeof config.data.src === "function" ? config.data.src() : config.data.src),
key: config.data.key
// Data src key selection
key: config.data.key,
// Cache Data src or NOT
cache: typeof config.data.cache === "undefined" ? true : config.data.cache,
};

@@ -17,10 +21,33 @@ // Search engine type

this.threshold = config.threshold || 0;
// Minimum duration for API calls debouncing
this.debounce = config.debounce || 0;
// Rendered results destination
this.resultsList = autoCompleteView.createResultsList({
container: config.resultsList && config.resultsList.container ? config.resultsList.container : false,
// Results List function
container:
// If resultsList and container are set
config.resultsList && config.resultsList.container
// Then set resultsList container
? config.resultsList.container
// Else set default false
: false,
// Results List selector
destination:
// If resultsList and destination are set
config.resultsList && config.resultsList.destination
// Then set resultList destination
? config.resultsList.destination
// Else set Default
: autoCompleteView.getInput(this.selector),
position: config.resultsList && config.resultsList.position ? config.resultsList.position : "afterend"
// Results List position
position:
// If resultsList and position are set
config.resultsList && config.resultsList.position
// Then resultsList position
? config.resultsList.position
// Else set default "afterend"
: "afterend",
// Results List element tag
element: config.resultsList && config.resultsList.element
? config.resultsList.element : "ul"
});

@@ -34,3 +61,10 @@ // Sorting results list

// Rendered results item
this.resultItem = config.resultItem;
this.resultItem = {
// Result Item function
content: config.resultItem && config.resultItem.content
? config.resultItem.content : false,
// Result Item element tag
element: config.resultItem && config.resultItem.element
? config.resultItem.element : "li"
};
// Highlighting matching results

@@ -40,2 +74,4 @@ this.highlight = config.highlight || false;

this.onSelection = config.onSelection;
// Data source
this.dataSrc;
// Starts the app Enigne

@@ -58,2 +94,3 @@ this.init();

const recordLowerCase = record.toLowerCase();
// Loose mode

@@ -67,2 +104,3 @@ if (this.searchEngine === "loose") {

let searchPosition = 0;
// Iterate over record characters

@@ -72,2 +110,3 @@ for (let number = 0; number < recordLowerCase.length; number++) {

let recordChar = record[number];
// Matching case

@@ -83,2 +122,3 @@ if (searchPosition < query.length && recordLowerCase[number] === query[searchPosition]) {

}
// Non-Matching case

@@ -108,49 +148,61 @@ if (searchPosition !== query.length) {

*
* @return array
* @return {*}
*/
listMatchedResults(data) {
// Final highlighted results list of array
const resList = [];
// Holds the input search value
const inputValue = autoCompleteView.getInput(this.selector).value.toLowerCase();
// Checks input has matches in data source
data.filter((record, index) => {
// Search/Matching function
const search = key => {
// Holds match value
const match = this.search(inputValue, record[key] || record);
// Push match to results list with key if set
if (match && key) {
resList.push({ key, index, match, value: record });
// Push match to results list without key if not set
} else if (match && !key) {
resList.push({ index, match, value: record });
return new Promise(resolve => {
// Final highlighted results list of array
const resList = [];
// Holds the input search value
const inputValue = autoCompleteView.getInput(this.selector).value.toLowerCase();
// Checks input has matches in data source
data.filter((record, index) => {
// Search/Matching function
const search = key => {
// Holds match value
const match = this.search(inputValue, record[key] || record);
// Push match to results list with key if set
if (match && key) {
resList.push({ key, index, match, value: record });
// Push match to results list without key if not set
} else if (match && !key) {
resList.push({ index, match, value: record });
}
};
// Checks if data key is set
if (this.data.key) {
// Iterates over all set data keys
for (const key of this.data.key) {
search(key);
}
// If no data key not set
} else {
search();
}
};
// Checks if data key is set
if(this.data.key) {
// Iterates over all set data keys
for (const key of this.data.key) {
search(key);
}
// If no data key not set
} else {
search();
}
});
// Sorting / Slicing final results list
const list = this.sort
? resList.sort(this.sort).slice(0, this.maxResults)
: resList.slice(0, this.maxResults);
// Rendering matching results to the UI list
autoCompleteView.addResultsToList(this.resultsList, list, this.resultItem);
// Keyboard Arrow Navigation
autoCompleteView.navigation(this.selector, this.resultsList);
// Returns rendered list
return resolve({
matches: resList.length,
list,
});
});
// Sorting / Slicing final results list
const list = this.sort ? resList.sort(this.sort)
.slice(0, this.maxResults) : resList.slice(0, this.maxResults);
// Rendering matching results to the UI list
autoCompleteView.addResultsToList(this.resultsList, list, this.data.key, this.resultItem);
// Keyboard Arrow Navigation
autoCompleteView.navigation(this.selector, this.resultsList);
// Returns rendered list
return {
matches: resList.length,
list
};
}
ignite(data) {
/**
* App Engine Ignition.
*
* @return void
*/
ignite() {
// Selector value holder

@@ -164,2 +216,3 @@ const selector = this.selector;

const onSelection = this.onSelection;
// Placeholder setter

@@ -169,4 +222,18 @@ if (placeHolder) {

}
// Input field handler fires an event onKeyup action
input.onkeyup = (event) => {
// Debouncer
const debounce = (func, delay) => {
let inDebounce;
return function() {
const context = this;
const args = arguments;
clearTimeout(inDebounce);
inDebounce = setTimeout(() =>
func.apply(context, args)
, delay);
};
};
// Excute autoComplete processes
const exec = (event) => {
// Get results list value

@@ -176,22 +243,25 @@ const resultsList = this.resultsList;

const clearResults = autoCompleteView.clearResults(resultsList);
// Check if input is not empty or just have space before triggering the app
if (input.value.length > this.threshold && input.value.replace(/ /g, "").length) {
// List matching results
const list = this.listMatchedResults(data);
// Event emitter on input field
input.dispatchEvent(new CustomEvent("type", {
bubbles: true,
detail: {
event,
query: input.value,
matches: list.matches,
results: list.list
},
cancelable: true
}));
// Gets user's selection
// If action configured
if (onSelection) {
autoCompleteView.getSelection(selector, resultsList, onSelection, list);
}
this.listMatchedResults(this.dataSrc).then(list => {
// Event emitter on input field
input.dispatchEvent(
new CustomEvent("type", {
bubbles: true,
detail: {
event,
query: input.value,
matches: list.matches,
results: list.list,
},
cancelable: true,
}));
// Gets user's selection
// If action configured
if (onSelection) {
autoCompleteView.getSelection(selector, resultsList, onSelection, list);
}
});
} else {

@@ -202,2 +272,27 @@ // clears all results list

};
// Input field handler fires an event onKeyup action
input.addEventListener("keyup", debounce((event) => {
// If data src NOT to be cached
// then we should invoke its function again
if (!this.data.cache) {
const data = this.data.src();
// Check if data src is a Promise
// and resolve it before setting data src
if (data instanceof Promise) {
data.then(response => {
this.dataSrc = response;
exec(event);
});
// Else if not Promise
} else {
this.dataSrc = data;
exec(event);
}
// Else if data src is local
// not external src
} else {
exec(event);
}
}, this.debounce));
}

@@ -216,9 +311,12 @@

// Return Data
dataSrc.then(data => this.ignite(data));
dataSrc.then(response => {
this.dataSrc = response;
this.ignite();
});
// Data source is Array/Function
} else {
// Return Data
this.ignite(dataSrc);
this.dataSrc = dataSrc;
this.ignite();
}
}
}
}

@@ -25,3 +25,3 @@ const dataAttribute = "data-result";

const createResultsList = renderResults => {
const resultsList = document.createElement("ul");
const resultsList = document.createElement(renderResults.element);
if (renderResults.container) {

@@ -49,10 +49,9 @@ select.resultsList = renderResults.container(resultsList) || select.resultsList;

* @param dataSrc
* @param dataKey
* @param callback
* @param resultItem
*
* @return void
*/
const addResultsToList = (resultsList, dataSrc, dataKey, callback) => {
const addResultsToList = (resultsList, dataSrc, resultItem) => {
dataSrc.forEach((event, record) => {
const result = document.createElement("li");
const result = document.createElement(resultItem.element);
const resultValue = dataSrc[record].value[event.key] || dataSrc[record].value;

@@ -62,3 +61,3 @@ result.setAttribute(dataAttribute, resultValue);

result.setAttribute("tabindex", "1");
result.innerHTML = callback ? callback(event, result) : event.match || event;
result.innerHTML = resultItem.content ? resultItem.content(event, result) : event.match || event;
resultsList.appendChild(result);

@@ -72,3 +71,2 @@ });

* @param selector
*
* @param resultsList

@@ -75,0 +73,0 @@ */

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc