diff --git a/dist/main.js b/dist/main.js index ebc5f8a..ff3998b 100644 --- a/dist/main.js +++ b/dist/main.js @@ -544,7 +544,7 @@ class DOM { this.result = this.build('div', [ { id: this._identifiers.results }, { class: this._classes.results } ]); this.wrapper = this.build('div', [ { id: this._identifiers.wrapper }, { class: this._classes.results } ]); - this.wrapper.setAttribute('class', `${this._input.parentElement.getAttribute('class')} ${this._classes.main} ${options.theme}`); + this.wrapper.setAttribute('class', `${this._classes.main} ${options.theme}`); this.input.parentNode.insertBefore(this.wrapper, this.input); diff --git a/dist/main.js.map b/dist/main.js.map index 13c66e5..13e9e35 100644 --- a/dist/main.js.map +++ b/dist/main.js.map @@ -1 +1 @@ -{"version":3,"file":"main.js","mappings":";;;;;;;;;;;;;;AAAA;AACA;AACA;AACO;AACP;;AAEA;AACA;AACA;AACA,aAAa,aAAa;AAC1B;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA,aAAa,aAAa;AAC1B;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA,KAAK;AACL;AACA;;;;;;;;;;;;;;;AC9CmC;;AAEnC;AACA;AACA;AACO;AACP;;AAEA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,UAAU;AACvB;AACA,cAAc,OAAO;AACrB;AACA;AACA,uBAAuB,4CAAK;AAC5B,gDAAgD,YAAY,4CAAK,EAAE,IAAI,MAAM;AAC7E;AACA,4BAA4B,eAAe;AAC3C;;AAEA;AACA;AACA;AACA,aAAa,aAAa;AAC1B,aAAa,QAAQ;AACrB,aAAa,UAAU;AACvB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA,cAAc,OAAO;AACrB;AACA,2BAA2B;AAC3B,uBAAuB,4CAAK;AAC5B,gDAAgD,YAAY,4CAAK,EAAE,IAAI,MAAM;AAC7E;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;ACrDmC;;AAEnC;AACA;AACA;AACA;AACA;AACA;AACO;;AAEP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,UAAU;AACvB;AACA,mDAAmD;AACnD,4CAA4C;AAC5C;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX,OAAO;AACP;AACA,kCAAkC,4CAAK;AACvC,OAAO;AACP;;AAEA;AACA;AACA;AACA,aAAa,QAAQ,OAAO;AAC5B;AACA,4CAA4C;AAC5C;AACA,eAAe;AACf;AACA,QAAQ,cAAc;AACtB;AACA;AACA;AACA;AACA,gDAAgD,eAAe;AAC/D,sBAAsB,OAAO,wCAAwC,SAAS;AAC9E,OAAO;AACP;AACA,kCAAkC,4CAAK;AACvC,OAAO;AACP;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA,eAAe;AACf;AACA;AACA;AACA;AACA,6CAA6C,OAAO;AACpD;AACA;AACA;AACA;AACA,MAAM;AACN,gCAAgC,4CAAK;AACrC;AACA;AACA;;;;;;;;;;;;;;;ACnGqD;;AAErD;AACA;AACA;AACO;AACP;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA,WAAW,4CAAK;;AAEhB;AACA;AACA,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;AACA,YAAY;AACZ;AACA,cAAc,uDAAgB;;AAE9B;AACA;AACA,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,8BAA8B,4CAAK;AACnC;AACA,gDAAgD,iBAAiB,IAAI,OAAO;AAC5E;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,8BAA8B,uDAAgB;AAC9C;AACA,mDAAmD,iBAAiB,IAAI,OAAO;AAC/E;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;AC5KmC;;AAE5B;AACP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uEAAuE,OAAO;AAC9E;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,yBAAyB;AACtC,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA,eAAe;AACf;AACA,8CAA8C,gBAAgB;AAC9D;;AAEA;AACA;AACA;AACA;AACA,wCAAwC,+BAA+B,IAAI,+BAA+B;;AAE1G,yCAAyC,+BAA+B,IAAI,+BAA+B;AAC3G,0CAA0C,iDAAiD,EAAE,oBAAoB,EAAE,cAAc;;AAEjI;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;;AAEL;AACA,mDAAmD,oBAAoB;AACvE;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;;AAEA;AACA;AACA;AACA,8BAA8B,YAAY,WAAW,qBAAqB;AAC1E;AACA;AACA,oCAAoC,mBAAmB,IAAI,aAAa;AACxE;AACA;AACA;AACA,2BAA2B,uBAAuB;AAClD,sCAAsC,mBAAmB,IAAI,4BAA4B;AACzF;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,MAAM;AACN,4BAA4B,qBAAqB;AACjD;;AAEA;;AAEA,8BAA8B,4CAAK;AACnC;AACA;;;;;;;;;;;;;;;;;ACxLA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA,CAAC;;;;;;;;;;;;;;;;;;;AC5C0C;AACkB;;AAE7D;AACA;AACA;AACA;AACA;AACA;AACA;AACe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,gBAAgB,gFAAgF;AAChG;AACA;AACA;AACA;AACA;AACA;;AAEA,iCAAiC,4CAAK;AACtC,iCAAiC,4CAAK;AACtC,iCAAiC,4CAAK,UAAU,oDAAS;AACzD,iCAAiC,4CAAK;AACtC,iCAAiC,4CAAK;;AAEtC;AACA;;AAEA;AACA,yDAAyD,4BAA4B;AACrF;AACA,MAAM;AACN,wCAAwC,4CAAK,iEAAiE,QAAQ;AACtH;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI,oDAAS;AACb;AACA;;AAEA;AACA;AACA;;AAEA;AACA,wDAAwD,QAAQ;AAChE,IAAI,oDAAS;AACb;AACA;;AAEA;AACA;AACA;AACA,0CAA0C,uDAAgB;AAC1D;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA,yBAAyB,YAAY;AACrC;;AAEA,mDAAmD,mBAAmB,KAAK;;AAE3E;AACA;AACA;;AAEA,6CAA6C,6CAAM;AACnD,uBAAuB,oCAAoC;AAC3D;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,qBAAqB,qCAAqC;AAC1D;AACA;AACA;AACA;AACA,WAAW;AACX,SAAS;AACT;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,aAAa,oDAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA,8CAA8C;AAC9C,uCAAuC;AACvC;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,4CAAK,aAAa,MAAM,6CAAM,oBAAoB;AACrF,SAAS;AACT,QAAQ;AACR;AACA,mCAAmC,4CAAK,aAAa,MAAM,6CAAM,uBAAuB;AACxF,SAAS;AACT,QAAQ;AACR,iCAAiC,4CAAK,aAAa,MAAM,6CAAM,+BAA+B;AAC9F;AACA,MAAM;AACN,+BAA+B,4CAAK;AACpC;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA,MAAM;AACN,+BAA+B,4CAAK;AACpC;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA,+BAA+B,4CAAK;AACpC,MAAM;AACN,+BAA+B,4CAAK;AACpC;AACA;AACA;;;;;;;;;;;;;;AC9OA;AACA;AACA;AACO;;AAEP;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,gDAAgD,kBAAkB;AAClE;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,qDAAqD,kBAAkB;AACvE;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;;;;;UCrDA;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;;;;WCtBA;WACA;WACA;WACA;WACA,yCAAyC,wCAAwC;WACjF;WACA;WACA;;;;;WCPA,8CAA8C;;;;;WCA9C;WACA;WACA;WACA,uDAAuD,iBAAiB;WACxE;WACA,gDAAgD,aAAa;WAC7D;;;;;;;;;;;;;;;;;;;;ACNqC;;AAEc;AAChB;AACY;AACF;AACd;;AAE/B;AACA;AACA;AACA,WAAW,yBAAyB;AACpC,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,UAAU;AACrB,WAAW,UAAU;AACrB,WAAW,UAAU;AACrB;AACA,aAAa;AACb;AACA,4BAA4B,kDAAkD;AAC9E;AACA;AACA,UAAU,wDAAW;AACrB,UAAU,4DAAa;AACvB,UAAU,sDAAU;AACpB;AACA;AACA;AACA,UAAU,wCAAG;AACb,gCAAgC,4CAAK;AACrC;AACA;AACA,QAAQ,oDAAQ,GAAG,gFAAgF;AACnG,IAAI;AACJ,wDAAwD,QAAQ;AAChE;AACA;;AAEA","sources":["webpack://kompletr/./src/js/animation.js","webpack://kompletr/./src/js/broadcaster.js","webpack://kompletr/./src/js/cache.js","webpack://kompletr/./src/js/configuration.js","webpack://kompletr/./src/js/dom.js","webpack://kompletr/./src/js/enums.js","webpack://kompletr/./src/js/kompletr.js","webpack://kompletr/./src/js/properties.js","webpack://kompletr/webpack/bootstrap","webpack://kompletr/webpack/runtime/define property getters","webpack://kompletr/webpack/runtime/hasOwnProperty shorthand","webpack://kompletr/webpack/runtime/make namespace object","webpack://kompletr/./src/js/index.js"],"sourcesContent":["/**\n * Represents an Animation class that provides various animation effects.\n */\nexport class Animation {\n constructor() {}\n\n /**\n * Apply a fadeIn animation effect to the target HTML element.\n * \n * @param {HTMLElement} element - The target HTML element.\n * \n * @returns {Void}\n * \n * @todo Manage duration\n */\n static fadeIn(element) {\n element.style.opacity = 0;\n element.style.display = 'block';\n (function fade(){\n let value = parseFloat(element.style.opacity);\n if (!((value += .1) > 1)) {\n element.style.opacity = value;\n requestAnimationFrame(fade);\n }\n })();\n }\n\n /**\n * Apply a fadeOut animation effect to the target HTML element.\n * \n * @param {HTMLElement} element - The target HTML element.\n * \n * @returns {Void}\n * \n * @todo Manage duration\n */\n static fadeOut(element) {\n element.style.opacity = 1;\n (function fade() {\n if ((element.style.opacity -= .1) < 0) {\n element.style.display = 'none';\n } else {\n requestAnimationFrame(fade);\n }\n })();\n }\n}","import { event } from './enums.js';\n\n/**\n * Represents a Broadcaster that allows subscribing to and triggering events.\n */\nexport class Broadcaster {\n subscribers = [];\n\n constructor() {}\n\n /**\n * Subscribes to an event.\n * \n * @param {string} type - The type of event to subscribe to.\n * @param {Function} handler - The event handler function.\n * \n * @throws {Error} If the event type is not valid.\n */\n subscribe(type, handler) {\n if (!Object.values(event).includes(type)) {\n throw new Error(`Event should be one of ${Object.keys(event)}: ${type} given.`);\n }\n this.subscribers.push({ type, handler });\n }\n\n /**\n * Listens for an event on a specified element.\n * \n * @param {HTMLElement} element - The element to listen on.\n * @param {string} type - The type of event to listen for.\n * @param {Function} handler - The event handler function.\n */\n listen(element, type, handler) {\n element.addEventListener(type, handler);\n }\n\n /**\n * Triggers an event.\n * \n * @param {string} type - The type of event to trigger.\n * @param {Object} detail - Additional details to pass to the event handler.\n * \n * @throws {Error} If the event type is not valid.\n */\n trigger(type, detail = {}) {\n if (!Object.values(event).includes(type)) {\n throw new Error(`Event should be one of ${Object.keys(event)}: ${type} given.`);\n }\n \n this.subscribers\n .filter(subscriber => subscriber.type === type)\n .forEach(subscriber => subscriber.handler(detail));\n }\n}","import { event } from './enums.js';\n\n/**\n * @description Kompletr simple caching mechanism implementation.\n * \n * @see https://developer.mozilla.org/en-US/docs/Web/API/Cache\n * @see https://web.dev/articles/cache-api-quick-guide\n */\nexport class Cache {\n\n /**\n * @description Cache name value\n */\n _name = null;\n\n /**\n * @description Cache timelife duration\n */\n _duration = null;\n \n /**\n * @description Broadcaster instance\n */\n _braodcaster = null;\n \n constructor(broadcaster, duration = 0, name = 'kompletr.cache') {\n if (!window.caches) {\n return false;\n }\n this._broadcaster = broadcaster;\n this._name = name;\n this._duration = duration;\n }\n\n /**\n * @description Retrieve the data stored in cache and dispatch event with\n * \n * @param {String} string Input value of the current request as string\n * @param {Function} done Callback function\n * \n * @emits CustomEvent 'kompltetr.request.done' { from, data }\n * @emits CustomEvent 'kompltetr.error' { error }\n * \n * @returns {Void}\n */\n get(string, done) {\n window.caches.open(this._name)\n .then(cache => {\n cache.match(string)\n .then(async (data) => {\n done(await data.json());\n });\n })\n .catch(e => {\n this._broadcaster.trigger(event.error, e);\n });\n }\n\n /**\n * @description Push data into the cache\n * \n * @param {Object} args { string, data }\n * \n * @emits CustomEvent 'kompltetr.error' { error }\n * \n * @returns {Void}\n */\n set({ string, data }) {\n window.caches.open(this._name)\n .then(cache => {\n const headers = new Headers();\n headers.set('Content-Type', 'application/json');\n headers.set('Cache-Control', `max-age=${this._duration}`);\n cache.put(`/${string}`, new Response(JSON.stringify(data), { headers }));\n })\n .catch(e => {\n this._broadcaster.trigger(event.error, e);\n });\n }\n\n /**\n * @description Check the cache validity regarding the current request and the cache timelife\n * \n * @param {String} string The current request value\n *\n * @returns {Promise}\n */\n async isValid(string) {\n try {\n const cache = await window.caches.open(this._name);\n const response = await cache.match(`/${string}`);\n if (!response) {\n return false;\n }\n return true;\n } catch(e) {\n this._broadcaster.trigger(event.error, e);\n }\n }\n}","import { searchExpression, theme } from './enums.js';\n\n/**\n * @description Represents the configuration for the Kompleter library.\n */\nexport class Configuration {\n /**\n * Indicates whether multiple selections are allowed.\n * @type {boolean}\n * @private\n */\n _multiple = false;\n \n /**\n * The theme for the kompletr options.\n * @type {string}\n */\n _theme = theme.light;\n\n /**\n * Array containing the fields to be displayed.\n * @type {Array}\n * @private\n */\n _fieldsToDisplay = [];\n\n /**\n * The maximum number of results to display.\n * @type {number}\n */\n _maxResults = 10;\n\n /**\n * The character index from which querying should start.\n * @type {number}\n */\n _startQueryingFromChar = 2;\n\n /**\n * Represents the value of a property to be mapped.\n * @type {string}\n * @private\n */\n _propToMapAsValue = '';\n\n /**\n * The filter option used for filtering data.\n * Possible values are 'prefix', 'expression'.\n * @type {string}\n */\n _filterOn = searchExpression.prefix;\n\n /**\n * Represents the cache value.\n * @type {number}\n * @private\n */\n _cache = 0;\n\n /**\n * @description Enable / disable multiple choices\n */\n get multiple() {\n return this._multiple;\n }\n\n set multiple(value) {\n this._multiple = value;\n }\n\n /**\n * @description Display theme between light | dark\n */\n get theme() {\n return this._theme;\n }\n\n set theme(value) {\n const valid = Object.keys(theme);\n if (!valid.includes(value)) {\n throw new Error(`theme should be one of ${valid.toString()}, ${value} given`);\n }\n this._theme = value;\n }\n\n /**\n * @description Fields to display in each suggestion item\n */\n get fieldsToDisplay() {\n return this._fieldsToDisplay;\n }\n\n set fieldsToDisplay(value) {\n this._fieldsToDisplay = value;\n }\n \n /**\n * @description Maximum number of results to display as suggestions (can be different thant the number of results availables)\n */\n get maxResults() {\n return this._maxResults;\n }\n\n set maxResults(value) {\n this._maxResults = value;\n }\n\n /**\n * @description Input minimal value length before to fire research\n */\n get startQueryingFromChar() {\n return this._startQueryingFromChar;\n }\n\n set startQueryingFromChar(value) {\n this._startQueryingFromChar = value;\n }\n\n /**\n * @description Property to map as value\n */\n get propToMapAsValue() {\n return this._propToMapAsValue;\n }\n\n set propToMapAsValue(value) {\n this._propToMapAsValue = value;\n }\n\n /**\n * @description Apply filtering from the beginning of the word (prefix) or on the entire expression (expression)\n */\n get filterOn() {\n return this._filterOn;\n }\n\n set filterOn(value) {\n const valid = Object.keys(searchExpression);\n if (!valid.includes(value)) {\n throw new Error(`filterOn should be one of ${valid.toString()}, ${value} given`);\n }\n this._filterOn = value;\n }\n\n /**\n * @description Time life of the cache when data is retrieved from an API call\n */\n get cache() {\n return this._cache;\n }\n\n set cache(value) {\n if (isNaN(parseInt(value, 10))) {\n throw new Error('cache should be an integer');\n }\n this._cache = value;\n }\n\n constructor(options) {\n if (options === undefined) return;\n if (typeof options !== 'object') {\n throw new Error('options should be an object');\n }\n this.theme = options?.theme || this._theme;\n this.multiple = options?.multiple || this._multiple;\n this.fieldsToDisplay = options?.fieldsToDisplay || this._fieldsToDisplay;\n this.maxResults = options?.maxResults || this._maxResults;\n this.startQueryingFromChar = options?.startQueryingFromChar || this._startQueryingFromChar;\n this.propToMapAsValue = options?.propToMapAsValue || this._propToMapAsValue;\n this.filterOn = options?.filterOn || this._filterOn;\n this.cache = options?.cache || this._cache;\n }\n}","import { event } from './enums.js';\n\nexport class DOM {\n /**\n * @description Identifiers for the DOM elements\n */\n _identifiers = {\n wrapper: 'kompletr-wrapper',\n results: 'kompletr-results',\n };\n\n /**\n * @description Classes for the DOM elements\n */\n _classes = {\n main: 'kompletr',\n results: 'container--search-results',\n result: 'item--row',\n data: 'item--property',\n focus: 'focus',\n };\n\n /**\n * @description Body tag\n */\n _body = null;\n\n get body() {\n return this._body;\n }\n\n set body(value) {\n this._body = value;\n }\n\n /**\n * @description Main input text\n */\n _input = null;\n\n get input() {\n return this._input;\n }\n\n set input(value) {\n if (value instanceof HTMLInputElement === false) {\n throw new Error(`input should be an HTMLInputElement instance: ${value} given.`);\n }\n this._input = value;\n }\n\n /**\n * @description HTMLElement in suggestions who's have the focus\n */\n _focused = null;\n\n get focused() {\n return this._focused;\n }\n\n set focused(value) {\n this._focused = value;\n }\n\n /**\n * @description HTMLElement results container\n */\n _result = null;\n\n get result() {\n return this._result;\n }\n\n set result(value) {\n this._result = value;\n }\n \n /**\n * @description Broadcaster instance\n */\n _broadcaster = null;\n\n /**\n * Represents a Kompletr DOM container.\n * \n * @param {string|HTMLInputElement} input - The input element or its ID.\n * @param {object} broadcaster - The broadcaster object.\n * @param {object} [options] - The options for the DOM object.\n * @param {string} [options.theme='light'] - The theme for the DOM object.\n * \n * @returns {void}\n */\n constructor(input, broadcaster, options = { theme: 'light' }) {\n this._broadcaster = broadcaster;\n\n this.body = document.getElementsByTagName('body')[0];\n \n this.input = input instanceof HTMLInputElement ? input : document.getElementById(input); \n \n this.result = this.build('div', [ { id: this._identifiers.results }, { class: this._classes.results } ]);\n\n this.wrapper = this.build('div', [ { id: this._identifiers.wrapper }, { class: this._classes.results } ]);\n this.wrapper.setAttribute('class', `${this._input.parentElement.getAttribute('class')} ${this._classes.main} ${options.theme}`);\n\n this.input.parentNode.insertBefore(this.wrapper, this.input);\n\n this.wrapper.appendChild(this.input);\n this.wrapper.appendChild(this.result);\n }\n\n /**\n * @description Build an HTML element and set his attributes\n * \n * @param {String} element HTML tag to build\n * @param {Object[]} attributes Key / values pairs\n * \n * @returns {HTMLElement}\n */\n build(element, attributes = []) {\n const htmlElement = document.createElement(element);\n attributes.forEach(attribute => {\n htmlElement.setAttribute(Object.keys(attribute)[0], Object.values(attribute)[0]);\n });\n return htmlElement;\n }\n\n /**\n * @description Add / remove the focus on a HTMLElement\n * \n * @param {String} action add|remove\n *\n * @returns {Void}\n */\n focus(pointer) {\n if (isNaN(parseInt(pointer, 10)) || pointer < 0 || pointer > this.result.children.length - 1) {\n throw new Error('pointer should be a valid integer in the result lenght range: ' + pointer + ' given.');\n }\n\n this.focused = null;\n Array.from(this.result.children).forEach(result => {\n ((result) => {\n result.className = this._classes.result;\n })(result);\n });\n\n this.focused = this.result.children[pointer];\n this.result.children[pointer].className += ` ${this._classes.focus}`;\n }\n\n /**\n * @description Display results according to the current input value / setup\n * \n * @returns {Void}\n */\n buildResults(data, fieldsToDisplay) {\n let html = '';\n\n if(data && data.length) {\n html = data\n .reduce((html, current) => {\n html += `
`;\n switch (typeof current.data) {\n case 'string':\n html += `${current.data}`;\n break;\n case 'object': {\n let properties = Array.isArray(fieldsToDisplay) && fieldsToDisplay.length ? fieldsToDisplay: Object.keys(current.data);\n for(let j = 0; j < properties.length; j++) {\n html += `${current.data[properties[j]]}`;\n }\n break;\n }}\n html += '
';\n return html;\n }, '');\n \n } else {\n html = `
Not found
`;\n }\n\n this.result.innerHTML = html;\n\n this._broadcaster.trigger(event.domDone, this.result);\n }\n}","/**\n * Enum representing different custom events.\n * \n * @enum {string}\n * @readonly\n */\nconst event = Object.freeze({\n error: 'kompletr.error',\n domDone: 'kompletr.dom.done',\n dataDone: 'kompletr.data.done',\n selectDone: 'kompletr.select.done'\n});\n\n/**\n * Enum representing the origin of a value.\n * \n * @enum {string}\n * @readonly\n */\nconst origin = Object.freeze({\n cache: 'cache',\n callback: 'callback',\n local: 'local',\n});\n\n/**\n * Enum representing the search expression options.\n * \n * @enum {string}\n * @readonly\n */\nconst searchExpression = Object.freeze({\n prefix: 'prefix',\n expression: 'expression',\n});\n\n/**\n * Enum representing the theme options.\n *\n * @enum {string}\n * @readonly\n */\nconst theme = Object.freeze({\n light: 'light',\n dark: 'dark',\n});\n\nexport { event, origin, searchExpression, theme };","\nimport { Animation } from './animation.js';\nimport { event, origin, searchExpression } from './enums.js';\n\n/**\n * @summary Kømpletr.js is a library providing features dedicated to autocomplete fields.\n * \n * @author Steve Lebleu \n * \n * @see https://github.com/steve-lebleu/kompletr\n */\nexport default class Kompletr {\n /**\n * \n */\n broadcaster = null;\n\n /**\n * \n */\n cache = null;\n\n /**\n * \n */\n callbacks = {};\n\n /**\n * \n */\n configuration = null;\n\n /**\n * \n */\n dom = null;\n\n /**\n * \n */\n props = null;\n\n constructor({ configuration, properties, dom, cache, broadcaster, onKeyup, onSelect, onError }) {\n try {\n this.configuration = configuration;\n this.broadcaster = broadcaster;\n this.props = properties;\n this.dom = dom;\n this.cache = cache;\n\n this.broadcaster.subscribe(event.error, this.error);\n this.broadcaster.subscribe(event.dataDone, this.showResults);\n this.broadcaster.subscribe(event.domDone, Animation.fadeIn.bind(null, this.dom.result));\n this.broadcaster.subscribe(event.domDone, this.bindResults);\n this.broadcaster.subscribe(event.selectDone, this.closeTheShop);\n\n this.broadcaster.listen(this.dom.input, 'keyup', this.suggest);\n this.broadcaster.listen(this.dom.body, 'click', this.closeTheShop);\n\n if(onKeyup || onSelect || onError) {\n this.callbacks = Object.assign(this.callbacks, { onKeyup, onSelect, onError });\n }\n } catch(e) {\n broadcaster ? broadcaster.trigger(event.error, e) : console.error(`[kompletr] An error has occured -> ${e.stack}`);\n }\n }\n\n closeTheShop = (e) => {\n if (e.srcElement === this.dom.input) {\n return true;\n }\n Animation.fadeOut(this.dom.result);\n this.resetPointer();\n };\n\n resetPointer = () => {\n this.props.pointer = -1;\n };\n\n error = (e) => {\n console.error(`[kompletr] An error has occured -> ${e.stack}`);\n Animation.fadeOut(this.dom.result);\n this.callbacks.onError && this.callbacks.onError(e);\n };\n\n filter = (data, pattern) => {\n return data.filter((record) => {\n const value = typeof record.data === 'string' ? record.data : record.data[this.configuration.propToMapAsValue];\n if (this.configuration.filterOn === searchExpression.prefix) {\n return value.toLowerCase().lastIndexOf(pattern.toLowerCase(), 0) === 0;\n }\n return value.toLowerCase().lastIndexOf(pattern.toLowerCase()) !== -1;\n });\n };\n\n /**\n * @description CustomEvent 'this.request.done' listener\n * \n * @todo Check something else to determine if we filter or not -> currently just the presence of onKeyup callback\n */\n showResults = async ({ from, data }) => {\n this.props.data = data;\n\n data = this.props.data.map((record, idx) => ({ idx, data: record }) ); // TODO: Check to avoid this\n\n if (!this.callbacks.onKeyup) {\n data = this.filter(data, this.dom.input.value);\n }\n\n if (this.configuration.cache && from !== origin.cache) {\n this.cache.set({ string: this.dom.input.value, data });\n }\n\n this.dom.buildResults(data.slice(0, this.configuration.maxResults), this.configuration.fieldsToDisplay);\n };\n\n /**\n * @description CustomEvent 'kompletr.dom.done' listener\n */\n bindResults = () => { \n if(this.dom.result?.children?.length) {\n for(let i = 0; i < this.dom.result.children.length; i++) {\n ((i) => {\n return this.broadcaster.listen(this.dom.result.children[i], 'click', () => {\n this.dom.focused = this.dom.result.children[i];\n this.select(this.dom.focused.id);\n });\n })(i);\n }\n }\n };\n\n /**\n * @description 'input.keyup' listener\n */\n suggest = (e) => {\n if (this.dom.input.value.length < this.configuration.startQueryingFromChar) {\n return Animation.fadeOut(this.dom.result);\n }\n \n switch (e.keyCode) {\n case 13: // Enter\n this.select(this.dom.focused.id);\n break;\n case 38: // Up\n case 40: // Down\n this.navigate(e.keyCode);\n break;\n default:\n if (this.dom.input.value !== this.props.previousValue) {\n this.hydrate(this.dom.input.value);\n }\n this.resetPointer();\n break;\n }\n };\n\n /**\n * @description Manage the data hydration according to the current setup (cache, request or local data)\n * \n * @param {String} value Current input value\n * \n * @emits CustomEvent 'this.request.done' { from, data }\n * @emits CustomEvent 'this.error' { error }\n * \n * @returns {Void}\n * \n * @todo options.data could returns Promise, and same for the onKeyup callback\n */\n hydrate = async (value) => {\n try {\n if (this.configuration.cache && await this.cache.isValid(value)) {\n this.cache.get(value, (data) => {\n this.broadcaster.trigger(event.dataDone, { from: origin.cache, data: data }); \n });\n } else if (this.callbacks.onKeyup) {\n this.callbacks.onKeyup(value, (data) => {\n this.broadcaster.trigger(event.dataDone, { from: origin.callback, data: data });\n });\n } else {\n this.broadcaster.trigger(event.dataDone, { from: origin.local, data: this.props.data });\n }\n } catch(e) {\n this.broadcaster.trigger(event.error, e);\n }\n };\n\n /**\n * @description Apply visual navigation into the suggestions set\n * \n * @param {Number} keyCode The current keyCode value\n * \n * @returns {Void}\n */\n navigate = (keyCode) => {\n try {\n if (keyCode != 38 && keyCode != 40) {\n return false;\n }\n \n if(this.props.pointer < -1 || this.props.pointer > this.dom.result.children.length - 1) {\n return false;\n }\n \n if ((keyCode === 38 && this.props.pointer === 0) || (keyCode === 40 && this.props.pointer === this.dom.result.children.length - 1)) {\n return false;\n }\n\n if (keyCode === 38 && this.props.pointer >= -1) {\n this.props.pointer--;\n } else if (keyCode === 40 && this.props.pointer < this.dom.result.children.length - 1) {\n this.props.pointer++;\n } \n \n this.dom.focus(this.props.pointer);\n } catch(e) {\n this.broadcaster.trigger(event.error, e);\n }\n };\n\n /**\n * @description Select a suggested item as user choice\n * \n * @param {Number} idx The index of the selected suggestion\n * \n * @emits CustomEvent 'this.select.done'\n * \n * @returns {Void}\n */\n select = (idx = 0) => {\n try {\n this.dom.input.value = typeof this.props.data[idx] === 'object' ? this.props.data[idx][this.configuration.propToMapAsValue] : this.props.data[idx];\n this.callbacks.onSelect && this.callbacks.onSelect(this.props.data[idx]);\n this.broadcaster.trigger(event.selectDone);\n } catch(e) {\n this.broadcaster.trigger(event.error, e);\n }\n };\n}","/**\n * @description Dynamic properties of current Kompltr instance.\n */\nexport class Properties {\n\n /**\n * @description Data storage\n */\n _data = null;\n\n get data() {\n return this._data;\n }\n\n set data(value) {\n if (!Array.isArray(value)) {\n throw new Error(`data must be an array (${value.toString()} given)`);\n }\n this._data = value;\n }\n\n /**\n * @description Position of the pointer inside the suggestions\n */\n _pointer = null;\n\n get pointer() {\n return this._pointer;\n }\n\n set pointer(value) {\n if (isNaN(parseInt(value, 10))) {\n throw new Error(`pointer must be an integer (${value.toString()} given)`);\n }\n this._pointer = value;\n }\n\n /**\n * @description Previous input value\n */\n _previousValue = null;\n\n get previousValue() {\n return this._previousValue;\n }\n\n set previousValue(value) {\n this._previousValue = value;\n }\n\n constructor(data = []) {\n this._data = data;\n }\n}","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","// define __esModule on exports\n__webpack_require__.r = function(exports) {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import Kompletr from './kompletr.js';\n\nimport { Configuration } from './configuration.js';\nimport { Cache } from './cache.js';\nimport { Broadcaster } from './broadcaster.js';\nimport { Properties } from './properties.js';\nimport { DOM } from './dom.js';\n\n/**\n * Initializes the module with the provided data and options.\n *\n * @param {string|HTMLInputElement} input - The target input as selector or instance.\n * @param {Object} data - The data used by the application.\n * @param {Object} options - The configuration options for the application.\n * @param {Function} onKeyup - The callback function to be executed on keyup event.\n * @param {Function} onSelect - The callback function to be executed on select event.\n * @param {Function} onError - The callback function to be executed on error event.\n * \n * @returns {void}\n */\nconst kompletr = function({ input, data, options, onKeyup, onSelect, onError }) {\n try {\n const [broadcaster, configuration, properties] = [\n new Broadcaster(),\n new Configuration(options),\n new Properties(data),\n ];\n \n const [dom, cache] = [\n new DOM(input, broadcaster, configuration),\n configuration.cache ? new Cache(broadcaster, configuration.cache) : null,\n ];\n \n new Kompletr({ configuration, properties, dom, cache, broadcaster, onKeyup, onSelect, onError });\n } catch(e) {\n console.error(`[kompletr] An error has occured -> ${e.stack}`);\n }\n};\n\nwindow.kompletr = kompletr;\n\nexport { kompletr };"],"names":[],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"main.js","mappings":";;;;;;;;;;;;;;AAAA;AACA;AACA;AACO;AACP;;AAEA;AACA;AACA;AACA,aAAa,aAAa;AAC1B;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA,aAAa,aAAa;AAC1B;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA,KAAK;AACL;AACA;;;;;;;;;;;;;;;AC9CmC;;AAEnC;AACA;AACA;AACO;AACP;;AAEA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,UAAU;AACvB;AACA,cAAc,OAAO;AACrB;AACA;AACA,uBAAuB,4CAAK;AAC5B,gDAAgD,YAAY,4CAAK,EAAE,IAAI,MAAM;AAC7E;AACA,4BAA4B,eAAe;AAC3C;;AAEA;AACA;AACA;AACA,aAAa,aAAa;AAC1B,aAAa,QAAQ;AACrB,aAAa,UAAU;AACvB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA,cAAc,OAAO;AACrB;AACA,2BAA2B;AAC3B,uBAAuB,4CAAK;AAC5B,gDAAgD,YAAY,4CAAK,EAAE,IAAI,MAAM;AAC7E;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;ACrDmC;;AAEnC;AACA;AACA;AACA;AACA;AACA;AACO;;AAEP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,UAAU;AACvB;AACA,mDAAmD;AACnD,4CAA4C;AAC5C;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX,OAAO;AACP;AACA,kCAAkC,4CAAK;AACvC,OAAO;AACP;;AAEA;AACA;AACA;AACA,aAAa,QAAQ,OAAO;AAC5B;AACA,4CAA4C;AAC5C;AACA,eAAe;AACf;AACA,QAAQ,cAAc;AACtB;AACA;AACA;AACA;AACA,gDAAgD,eAAe;AAC/D,sBAAsB,OAAO,wCAAwC,SAAS;AAC9E,OAAO;AACP;AACA,kCAAkC,4CAAK;AACvC,OAAO;AACP;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA,eAAe;AACf;AACA;AACA;AACA;AACA,6CAA6C,OAAO;AACpD;AACA;AACA;AACA;AACA,MAAM;AACN,gCAAgC,4CAAK;AACrC;AACA;AACA;;;;;;;;;;;;;;;ACnGqD;;AAErD;AACA;AACA;AACO;AACP;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA,WAAW,4CAAK;;AAEhB;AACA;AACA,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;AACA,YAAY;AACZ;AACA,cAAc,uDAAgB;;AAE9B;AACA;AACA,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,8BAA8B,4CAAK;AACnC;AACA,gDAAgD,iBAAiB,IAAI,OAAO;AAC5E;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,8BAA8B,uDAAgB;AAC9C;AACA,mDAAmD,iBAAiB,IAAI,OAAO;AAC/E;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;AC5KmC;;AAE5B;AACP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uEAAuE,OAAO;AAC9E;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,yBAAyB;AACtC,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA,eAAe;AACf;AACA,8CAA8C,gBAAgB;AAC9D;;AAEA;AACA;AACA;AACA;AACA,wCAAwC,+BAA+B,IAAI,+BAA+B;;AAE1G,yCAAyC,+BAA+B,IAAI,+BAA+B;AAC3G,0CAA0C,oBAAoB,EAAE,cAAc;;AAE9E;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;;AAEL;AACA,mDAAmD,oBAAoB;AACvE;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;;AAEA;AACA;AACA;AACA,8BAA8B,YAAY,WAAW,qBAAqB;AAC1E;AACA;AACA,oCAAoC,mBAAmB,IAAI,aAAa;AACxE;AACA;AACA;AACA,2BAA2B,uBAAuB;AAClD,sCAAsC,mBAAmB,IAAI,4BAA4B;AACzF;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,MAAM;AACN,4BAA4B,qBAAqB;AACjD;;AAEA;;AAEA,8BAA8B,4CAAK;AACnC;AACA;;;;;;;;;;;;;;;;;ACxLA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA,CAAC;;;;;;;;;;;;;;;;;;;AC5C0C;AACkB;;AAE7D;AACA;AACA;AACA;AACA;AACA;AACA;AACe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,gBAAgB,gFAAgF;AAChG;AACA;AACA;AACA;AACA;AACA;;AAEA,iCAAiC,4CAAK;AACtC,iCAAiC,4CAAK;AACtC,iCAAiC,4CAAK,UAAU,oDAAS;AACzD,iCAAiC,4CAAK;AACtC,iCAAiC,4CAAK;;AAEtC;AACA;;AAEA;AACA,yDAAyD,4BAA4B;AACrF;AACA,MAAM;AACN,wCAAwC,4CAAK,iEAAiE,QAAQ;AACtH;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI,oDAAS;AACb;AACA;;AAEA;AACA;AACA;;AAEA;AACA,wDAAwD,QAAQ;AAChE,IAAI,oDAAS;AACb;AACA;;AAEA;AACA;AACA;AACA,0CAA0C,uDAAgB;AAC1D;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA,yBAAyB,YAAY;AACrC;;AAEA,mDAAmD,mBAAmB,KAAK;;AAE3E;AACA;AACA;;AAEA,6CAA6C,6CAAM;AACnD,uBAAuB,oCAAoC;AAC3D;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,qBAAqB,qCAAqC;AAC1D;AACA;AACA;AACA;AACA,WAAW;AACX,SAAS;AACT;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,aAAa,oDAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA,8CAA8C;AAC9C,uCAAuC;AACvC;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,4CAAK,aAAa,MAAM,6CAAM,oBAAoB;AACrF,SAAS;AACT,QAAQ;AACR;AACA,mCAAmC,4CAAK,aAAa,MAAM,6CAAM,uBAAuB;AACxF,SAAS;AACT,QAAQ;AACR,iCAAiC,4CAAK,aAAa,MAAM,6CAAM,+BAA+B;AAC9F;AACA,MAAM;AACN,+BAA+B,4CAAK;AACpC;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA,MAAM;AACN,+BAA+B,4CAAK;AACpC;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA,+BAA+B,4CAAK;AACpC,MAAM;AACN,+BAA+B,4CAAK;AACpC;AACA;AACA;;;;;;;;;;;;;;AC9OA;AACA;AACA;AACO;;AAEP;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,gDAAgD,kBAAkB;AAClE;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,qDAAqD,kBAAkB;AACvE;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;;;;;UCrDA;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;;;;WCtBA;WACA;WACA;WACA;WACA,yCAAyC,wCAAwC;WACjF;WACA;WACA;;;;;WCPA,8CAA8C;;;;;WCA9C;WACA;WACA;WACA,uDAAuD,iBAAiB;WACxE;WACA,gDAAgD,aAAa;WAC7D;;;;;;;;;;;;;;;;;;;;ACNqC;;AAEc;AAChB;AACY;AACF;AACd;;AAE/B;AACA;AACA;AACA,WAAW,yBAAyB;AACpC,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,UAAU;AACrB,WAAW,UAAU;AACrB,WAAW,UAAU;AACrB;AACA,aAAa;AACb;AACA,4BAA4B,kDAAkD;AAC9E;AACA;AACA,UAAU,wDAAW;AACrB,UAAU,4DAAa;AACvB,UAAU,sDAAU;AACpB;AACA;AACA;AACA,UAAU,wCAAG;AACb,gCAAgC,4CAAK;AACrC;AACA;AACA,QAAQ,oDAAQ,GAAG,gFAAgF;AACnG,IAAI;AACJ,wDAAwD,QAAQ;AAChE;AACA;;AAEA","sources":["webpack://kompletr/./src/js/animation.js","webpack://kompletr/./src/js/broadcaster.js","webpack://kompletr/./src/js/cache.js","webpack://kompletr/./src/js/configuration.js","webpack://kompletr/./src/js/dom.js","webpack://kompletr/./src/js/enums.js","webpack://kompletr/./src/js/kompletr.js","webpack://kompletr/./src/js/properties.js","webpack://kompletr/webpack/bootstrap","webpack://kompletr/webpack/runtime/define property getters","webpack://kompletr/webpack/runtime/hasOwnProperty shorthand","webpack://kompletr/webpack/runtime/make namespace object","webpack://kompletr/./src/js/index.js"],"sourcesContent":["/**\n * Represents an Animation class that provides various animation effects.\n */\nexport class Animation {\n constructor() {}\n\n /**\n * Apply a fadeIn animation effect to the target HTML element.\n * \n * @param {HTMLElement} element - The target HTML element.\n * \n * @returns {Void}\n * \n * @todo Manage duration\n */\n static fadeIn(element) {\n element.style.opacity = 0;\n element.style.display = 'block';\n (function fade(){\n let value = parseFloat(element.style.opacity);\n if (!((value += .1) > 1)) {\n element.style.opacity = value;\n requestAnimationFrame(fade);\n }\n })();\n }\n\n /**\n * Apply a fadeOut animation effect to the target HTML element.\n * \n * @param {HTMLElement} element - The target HTML element.\n * \n * @returns {Void}\n * \n * @todo Manage duration\n */\n static fadeOut(element) {\n element.style.opacity = 1;\n (function fade() {\n if ((element.style.opacity -= .1) < 0) {\n element.style.display = 'none';\n } else {\n requestAnimationFrame(fade);\n }\n })();\n }\n}","import { event } from './enums.js';\n\n/**\n * Represents a Broadcaster that allows subscribing to and triggering events.\n */\nexport class Broadcaster {\n subscribers = [];\n\n constructor() {}\n\n /**\n * Subscribes to an event.\n * \n * @param {string} type - The type of event to subscribe to.\n * @param {Function} handler - The event handler function.\n * \n * @throws {Error} If the event type is not valid.\n */\n subscribe(type, handler) {\n if (!Object.values(event).includes(type)) {\n throw new Error(`Event should be one of ${Object.keys(event)}: ${type} given.`);\n }\n this.subscribers.push({ type, handler });\n }\n\n /**\n * Listens for an event on a specified element.\n * \n * @param {HTMLElement} element - The element to listen on.\n * @param {string} type - The type of event to listen for.\n * @param {Function} handler - The event handler function.\n */\n listen(element, type, handler) {\n element.addEventListener(type, handler);\n }\n\n /**\n * Triggers an event.\n * \n * @param {string} type - The type of event to trigger.\n * @param {Object} detail - Additional details to pass to the event handler.\n * \n * @throws {Error} If the event type is not valid.\n */\n trigger(type, detail = {}) {\n if (!Object.values(event).includes(type)) {\n throw new Error(`Event should be one of ${Object.keys(event)}: ${type} given.`);\n }\n \n this.subscribers\n .filter(subscriber => subscriber.type === type)\n .forEach(subscriber => subscriber.handler(detail));\n }\n}","import { event } from './enums.js';\n\n/**\n * @description Kompletr simple caching mechanism implementation.\n * \n * @see https://developer.mozilla.org/en-US/docs/Web/API/Cache\n * @see https://web.dev/articles/cache-api-quick-guide\n */\nexport class Cache {\n\n /**\n * @description Cache name value\n */\n _name = null;\n\n /**\n * @description Cache timelife duration\n */\n _duration = null;\n \n /**\n * @description Broadcaster instance\n */\n _braodcaster = null;\n \n constructor(broadcaster, duration = 0, name = 'kompletr.cache') {\n if (!window.caches) {\n return false;\n }\n this._broadcaster = broadcaster;\n this._name = name;\n this._duration = duration;\n }\n\n /**\n * @description Retrieve the data stored in cache and dispatch event with\n * \n * @param {String} string Input value of the current request as string\n * @param {Function} done Callback function\n * \n * @emits CustomEvent 'kompltetr.request.done' { from, data }\n * @emits CustomEvent 'kompltetr.error' { error }\n * \n * @returns {Void}\n */\n get(string, done) {\n window.caches.open(this._name)\n .then(cache => {\n cache.match(string)\n .then(async (data) => {\n done(await data.json());\n });\n })\n .catch(e => {\n this._broadcaster.trigger(event.error, e);\n });\n }\n\n /**\n * @description Push data into the cache\n * \n * @param {Object} args { string, data }\n * \n * @emits CustomEvent 'kompltetr.error' { error }\n * \n * @returns {Void}\n */\n set({ string, data }) {\n window.caches.open(this._name)\n .then(cache => {\n const headers = new Headers();\n headers.set('Content-Type', 'application/json');\n headers.set('Cache-Control', `max-age=${this._duration}`);\n cache.put(`/${string}`, new Response(JSON.stringify(data), { headers }));\n })\n .catch(e => {\n this._broadcaster.trigger(event.error, e);\n });\n }\n\n /**\n * @description Check the cache validity regarding the current request and the cache timelife\n * \n * @param {String} string The current request value\n *\n * @returns {Promise}\n */\n async isValid(string) {\n try {\n const cache = await window.caches.open(this._name);\n const response = await cache.match(`/${string}`);\n if (!response) {\n return false;\n }\n return true;\n } catch(e) {\n this._broadcaster.trigger(event.error, e);\n }\n }\n}","import { searchExpression, theme } from './enums.js';\n\n/**\n * @description Represents the configuration for the Kompleter library.\n */\nexport class Configuration {\n /**\n * Indicates whether multiple selections are allowed.\n * @type {boolean}\n * @private\n */\n _multiple = false;\n \n /**\n * The theme for the kompletr options.\n * @type {string}\n */\n _theme = theme.light;\n\n /**\n * Array containing the fields to be displayed.\n * @type {Array}\n * @private\n */\n _fieldsToDisplay = [];\n\n /**\n * The maximum number of results to display.\n * @type {number}\n */\n _maxResults = 10;\n\n /**\n * The character index from which querying should start.\n * @type {number}\n */\n _startQueryingFromChar = 2;\n\n /**\n * Represents the value of a property to be mapped.\n * @type {string}\n * @private\n */\n _propToMapAsValue = '';\n\n /**\n * The filter option used for filtering data.\n * Possible values are 'prefix', 'expression'.\n * @type {string}\n */\n _filterOn = searchExpression.prefix;\n\n /**\n * Represents the cache value.\n * @type {number}\n * @private\n */\n _cache = 0;\n\n /**\n * @description Enable / disable multiple choices\n */\n get multiple() {\n return this._multiple;\n }\n\n set multiple(value) {\n this._multiple = value;\n }\n\n /**\n * @description Display theme between light | dark\n */\n get theme() {\n return this._theme;\n }\n\n set theme(value) {\n const valid = Object.keys(theme);\n if (!valid.includes(value)) {\n throw new Error(`theme should be one of ${valid.toString()}, ${value} given`);\n }\n this._theme = value;\n }\n\n /**\n * @description Fields to display in each suggestion item\n */\n get fieldsToDisplay() {\n return this._fieldsToDisplay;\n }\n\n set fieldsToDisplay(value) {\n this._fieldsToDisplay = value;\n }\n \n /**\n * @description Maximum number of results to display as suggestions (can be different thant the number of results availables)\n */\n get maxResults() {\n return this._maxResults;\n }\n\n set maxResults(value) {\n this._maxResults = value;\n }\n\n /**\n * @description Input minimal value length before to fire research\n */\n get startQueryingFromChar() {\n return this._startQueryingFromChar;\n }\n\n set startQueryingFromChar(value) {\n this._startQueryingFromChar = value;\n }\n\n /**\n * @description Property to map as value\n */\n get propToMapAsValue() {\n return this._propToMapAsValue;\n }\n\n set propToMapAsValue(value) {\n this._propToMapAsValue = value;\n }\n\n /**\n * @description Apply filtering from the beginning of the word (prefix) or on the entire expression (expression)\n */\n get filterOn() {\n return this._filterOn;\n }\n\n set filterOn(value) {\n const valid = Object.keys(searchExpression);\n if (!valid.includes(value)) {\n throw new Error(`filterOn should be one of ${valid.toString()}, ${value} given`);\n }\n this._filterOn = value;\n }\n\n /**\n * @description Time life of the cache when data is retrieved from an API call\n */\n get cache() {\n return this._cache;\n }\n\n set cache(value) {\n if (isNaN(parseInt(value, 10))) {\n throw new Error('cache should be an integer');\n }\n this._cache = value;\n }\n\n constructor(options) {\n if (options === undefined) return;\n if (typeof options !== 'object') {\n throw new Error('options should be an object');\n }\n this.theme = options?.theme || this._theme;\n this.multiple = options?.multiple || this._multiple;\n this.fieldsToDisplay = options?.fieldsToDisplay || this._fieldsToDisplay;\n this.maxResults = options?.maxResults || this._maxResults;\n this.startQueryingFromChar = options?.startQueryingFromChar || this._startQueryingFromChar;\n this.propToMapAsValue = options?.propToMapAsValue || this._propToMapAsValue;\n this.filterOn = options?.filterOn || this._filterOn;\n this.cache = options?.cache || this._cache;\n }\n}","import { event } from './enums.js';\n\nexport class DOM {\n /**\n * @description Identifiers for the DOM elements\n */\n _identifiers = {\n wrapper: 'kompletr-wrapper',\n results: 'kompletr-results',\n };\n\n /**\n * @description Classes for the DOM elements\n */\n _classes = {\n main: 'kompletr',\n results: 'container--search-results',\n result: 'item--row',\n data: 'item--property',\n focus: 'focus',\n };\n\n /**\n * @description Body tag\n */\n _body = null;\n\n get body() {\n return this._body;\n }\n\n set body(value) {\n this._body = value;\n }\n\n /**\n * @description Main input text\n */\n _input = null;\n\n get input() {\n return this._input;\n }\n\n set input(value) {\n if (value instanceof HTMLInputElement === false) {\n throw new Error(`input should be an HTMLInputElement instance: ${value} given.`);\n }\n this._input = value;\n }\n\n /**\n * @description HTMLElement in suggestions who's have the focus\n */\n _focused = null;\n\n get focused() {\n return this._focused;\n }\n\n set focused(value) {\n this._focused = value;\n }\n\n /**\n * @description HTMLElement results container\n */\n _result = null;\n\n get result() {\n return this._result;\n }\n\n set result(value) {\n this._result = value;\n }\n \n /**\n * @description Broadcaster instance\n */\n _broadcaster = null;\n\n /**\n * Represents a Kompletr DOM container.\n * \n * @param {string|HTMLInputElement} input - The input element or its ID.\n * @param {object} broadcaster - The broadcaster object.\n * @param {object} [options] - The options for the DOM object.\n * @param {string} [options.theme='light'] - The theme for the DOM object.\n * \n * @returns {void}\n */\n constructor(input, broadcaster, options = { theme: 'light' }) {\n this._broadcaster = broadcaster;\n\n this.body = document.getElementsByTagName('body')[0];\n \n this.input = input instanceof HTMLInputElement ? input : document.getElementById(input); \n \n this.result = this.build('div', [ { id: this._identifiers.results }, { class: this._classes.results } ]);\n\n this.wrapper = this.build('div', [ { id: this._identifiers.wrapper }, { class: this._classes.results } ]);\n this.wrapper.setAttribute('class', `${this._classes.main} ${options.theme}`);\n\n this.input.parentNode.insertBefore(this.wrapper, this.input);\n\n this.wrapper.appendChild(this.input);\n this.wrapper.appendChild(this.result);\n }\n\n /**\n * @description Build an HTML element and set his attributes\n * \n * @param {String} element HTML tag to build\n * @param {Object[]} attributes Key / values pairs\n * \n * @returns {HTMLElement}\n */\n build(element, attributes = []) {\n const htmlElement = document.createElement(element);\n attributes.forEach(attribute => {\n htmlElement.setAttribute(Object.keys(attribute)[0], Object.values(attribute)[0]);\n });\n return htmlElement;\n }\n\n /**\n * @description Add / remove the focus on a HTMLElement\n * \n * @param {String} action add|remove\n *\n * @returns {Void}\n */\n focus(pointer) {\n if (isNaN(parseInt(pointer, 10)) || pointer < 0 || pointer > this.result.children.length - 1) {\n throw new Error('pointer should be a valid integer in the result lenght range: ' + pointer + ' given.');\n }\n\n this.focused = null;\n Array.from(this.result.children).forEach(result => {\n ((result) => {\n result.className = this._classes.result;\n })(result);\n });\n\n this.focused = this.result.children[pointer];\n this.result.children[pointer].className += ` ${this._classes.focus}`;\n }\n\n /**\n * @description Display results according to the current input value / setup\n * \n * @returns {Void}\n */\n buildResults(data, fieldsToDisplay) {\n let html = '';\n\n if(data && data.length) {\n html = data\n .reduce((html, current) => {\n html += `
`;\n switch (typeof current.data) {\n case 'string':\n html += `${current.data}`;\n break;\n case 'object': {\n let properties = Array.isArray(fieldsToDisplay) && fieldsToDisplay.length ? fieldsToDisplay: Object.keys(current.data);\n for(let j = 0; j < properties.length; j++) {\n html += `${current.data[properties[j]]}`;\n }\n break;\n }}\n html += '
';\n return html;\n }, '');\n \n } else {\n html = `
Not found
`;\n }\n\n this.result.innerHTML = html;\n\n this._broadcaster.trigger(event.domDone, this.result);\n }\n}","/**\n * Enum representing different custom events.\n * \n * @enum {string}\n * @readonly\n */\nconst event = Object.freeze({\n error: 'kompletr.error',\n domDone: 'kompletr.dom.done',\n dataDone: 'kompletr.data.done',\n selectDone: 'kompletr.select.done'\n});\n\n/**\n * Enum representing the origin of a value.\n * \n * @enum {string}\n * @readonly\n */\nconst origin = Object.freeze({\n cache: 'cache',\n callback: 'callback',\n local: 'local',\n});\n\n/**\n * Enum representing the search expression options.\n * \n * @enum {string}\n * @readonly\n */\nconst searchExpression = Object.freeze({\n prefix: 'prefix',\n expression: 'expression',\n});\n\n/**\n * Enum representing the theme options.\n *\n * @enum {string}\n * @readonly\n */\nconst theme = Object.freeze({\n light: 'light',\n dark: 'dark',\n});\n\nexport { event, origin, searchExpression, theme };","\nimport { Animation } from './animation.js';\nimport { event, origin, searchExpression } from './enums.js';\n\n/**\n * @summary Kømpletr.js is a library providing features dedicated to autocomplete fields.\n * \n * @author Steve Lebleu \n * \n * @see https://github.com/steve-lebleu/kompletr\n */\nexport default class Kompletr {\n /**\n * \n */\n broadcaster = null;\n\n /**\n * \n */\n cache = null;\n\n /**\n * \n */\n callbacks = {};\n\n /**\n * \n */\n configuration = null;\n\n /**\n * \n */\n dom = null;\n\n /**\n * \n */\n props = null;\n\n constructor({ configuration, properties, dom, cache, broadcaster, onKeyup, onSelect, onError }) {\n try {\n this.configuration = configuration;\n this.broadcaster = broadcaster;\n this.props = properties;\n this.dom = dom;\n this.cache = cache;\n\n this.broadcaster.subscribe(event.error, this.error);\n this.broadcaster.subscribe(event.dataDone, this.showResults);\n this.broadcaster.subscribe(event.domDone, Animation.fadeIn.bind(null, this.dom.result));\n this.broadcaster.subscribe(event.domDone, this.bindResults);\n this.broadcaster.subscribe(event.selectDone, this.closeTheShop);\n\n this.broadcaster.listen(this.dom.input, 'keyup', this.suggest);\n this.broadcaster.listen(this.dom.body, 'click', this.closeTheShop);\n\n if(onKeyup || onSelect || onError) {\n this.callbacks = Object.assign(this.callbacks, { onKeyup, onSelect, onError });\n }\n } catch(e) {\n broadcaster ? broadcaster.trigger(event.error, e) : console.error(`[kompletr] An error has occured -> ${e.stack}`);\n }\n }\n\n closeTheShop = (e) => {\n if (e.srcElement === this.dom.input) {\n return true;\n }\n Animation.fadeOut(this.dom.result);\n this.resetPointer();\n };\n\n resetPointer = () => {\n this.props.pointer = -1;\n };\n\n error = (e) => {\n console.error(`[kompletr] An error has occured -> ${e.stack}`);\n Animation.fadeOut(this.dom.result);\n this.callbacks.onError && this.callbacks.onError(e);\n };\n\n filter = (data, pattern) => {\n return data.filter((record) => {\n const value = typeof record.data === 'string' ? record.data : record.data[this.configuration.propToMapAsValue];\n if (this.configuration.filterOn === searchExpression.prefix) {\n return value.toLowerCase().lastIndexOf(pattern.toLowerCase(), 0) === 0;\n }\n return value.toLowerCase().lastIndexOf(pattern.toLowerCase()) !== -1;\n });\n };\n\n /**\n * @description CustomEvent 'this.request.done' listener\n * \n * @todo Check something else to determine if we filter or not -> currently just the presence of onKeyup callback\n */\n showResults = async ({ from, data }) => {\n this.props.data = data;\n\n data = this.props.data.map((record, idx) => ({ idx, data: record }) ); // TODO: Check to avoid this\n\n if (!this.callbacks.onKeyup) {\n data = this.filter(data, this.dom.input.value);\n }\n\n if (this.configuration.cache && from !== origin.cache) {\n this.cache.set({ string: this.dom.input.value, data });\n }\n\n this.dom.buildResults(data.slice(0, this.configuration.maxResults), this.configuration.fieldsToDisplay);\n };\n\n /**\n * @description CustomEvent 'kompletr.dom.done' listener\n */\n bindResults = () => { \n if(this.dom.result?.children?.length) {\n for(let i = 0; i < this.dom.result.children.length; i++) {\n ((i) => {\n return this.broadcaster.listen(this.dom.result.children[i], 'click', () => {\n this.dom.focused = this.dom.result.children[i];\n this.select(this.dom.focused.id);\n });\n })(i);\n }\n }\n };\n\n /**\n * @description 'input.keyup' listener\n */\n suggest = (e) => {\n if (this.dom.input.value.length < this.configuration.startQueryingFromChar) {\n return Animation.fadeOut(this.dom.result);\n }\n \n switch (e.keyCode) {\n case 13: // Enter\n this.select(this.dom.focused.id);\n break;\n case 38: // Up\n case 40: // Down\n this.navigate(e.keyCode);\n break;\n default:\n if (this.dom.input.value !== this.props.previousValue) {\n this.hydrate(this.dom.input.value);\n }\n this.resetPointer();\n break;\n }\n };\n\n /**\n * @description Manage the data hydration according to the current setup (cache, request or local data)\n * \n * @param {String} value Current input value\n * \n * @emits CustomEvent 'this.request.done' { from, data }\n * @emits CustomEvent 'this.error' { error }\n * \n * @returns {Void}\n * \n * @todo options.data could returns Promise, and same for the onKeyup callback\n */\n hydrate = async (value) => {\n try {\n if (this.configuration.cache && await this.cache.isValid(value)) {\n this.cache.get(value, (data) => {\n this.broadcaster.trigger(event.dataDone, { from: origin.cache, data: data }); \n });\n } else if (this.callbacks.onKeyup) {\n this.callbacks.onKeyup(value, (data) => {\n this.broadcaster.trigger(event.dataDone, { from: origin.callback, data: data });\n });\n } else {\n this.broadcaster.trigger(event.dataDone, { from: origin.local, data: this.props.data });\n }\n } catch(e) {\n this.broadcaster.trigger(event.error, e);\n }\n };\n\n /**\n * @description Apply visual navigation into the suggestions set\n * \n * @param {Number} keyCode The current keyCode value\n * \n * @returns {Void}\n */\n navigate = (keyCode) => {\n try {\n if (keyCode != 38 && keyCode != 40) {\n return false;\n }\n \n if(this.props.pointer < -1 || this.props.pointer > this.dom.result.children.length - 1) {\n return false;\n }\n \n if ((keyCode === 38 && this.props.pointer === 0) || (keyCode === 40 && this.props.pointer === this.dom.result.children.length - 1)) {\n return false;\n }\n\n if (keyCode === 38 && this.props.pointer >= -1) {\n this.props.pointer--;\n } else if (keyCode === 40 && this.props.pointer < this.dom.result.children.length - 1) {\n this.props.pointer++;\n } \n \n this.dom.focus(this.props.pointer);\n } catch(e) {\n this.broadcaster.trigger(event.error, e);\n }\n };\n\n /**\n * @description Select a suggested item as user choice\n * \n * @param {Number} idx The index of the selected suggestion\n * \n * @emits CustomEvent 'this.select.done'\n * \n * @returns {Void}\n */\n select = (idx = 0) => {\n try {\n this.dom.input.value = typeof this.props.data[idx] === 'object' ? this.props.data[idx][this.configuration.propToMapAsValue] : this.props.data[idx];\n this.callbacks.onSelect && this.callbacks.onSelect(this.props.data[idx]);\n this.broadcaster.trigger(event.selectDone);\n } catch(e) {\n this.broadcaster.trigger(event.error, e);\n }\n };\n}","/**\n * @description Dynamic properties of current Kompltr instance.\n */\nexport class Properties {\n\n /**\n * @description Data storage\n */\n _data = null;\n\n get data() {\n return this._data;\n }\n\n set data(value) {\n if (!Array.isArray(value)) {\n throw new Error(`data must be an array (${value.toString()} given)`);\n }\n this._data = value;\n }\n\n /**\n * @description Position of the pointer inside the suggestions\n */\n _pointer = null;\n\n get pointer() {\n return this._pointer;\n }\n\n set pointer(value) {\n if (isNaN(parseInt(value, 10))) {\n throw new Error(`pointer must be an integer (${value.toString()} given)`);\n }\n this._pointer = value;\n }\n\n /**\n * @description Previous input value\n */\n _previousValue = null;\n\n get previousValue() {\n return this._previousValue;\n }\n\n set previousValue(value) {\n this._previousValue = value;\n }\n\n constructor(data = []) {\n this._data = data;\n }\n}","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","// define __esModule on exports\n__webpack_require__.r = function(exports) {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import Kompletr from './kompletr.js';\n\nimport { Configuration } from './configuration.js';\nimport { Cache } from './cache.js';\nimport { Broadcaster } from './broadcaster.js';\nimport { Properties } from './properties.js';\nimport { DOM } from './dom.js';\n\n/**\n * Initializes the module with the provided data and options.\n *\n * @param {string|HTMLInputElement} input - The target input as selector or instance.\n * @param {Object} data - The data used by the application.\n * @param {Object} options - The configuration options for the application.\n * @param {Function} onKeyup - The callback function to be executed on keyup event.\n * @param {Function} onSelect - The callback function to be executed on select event.\n * @param {Function} onError - The callback function to be executed on error event.\n * \n * @returns {void}\n */\nconst kompletr = function({ input, data, options, onKeyup, onSelect, onError }) {\n try {\n const [broadcaster, configuration, properties] = [\n new Broadcaster(),\n new Configuration(options),\n new Properties(data),\n ];\n \n const [dom, cache] = [\n new DOM(input, broadcaster, configuration),\n configuration.cache ? new Cache(broadcaster, configuration.cache) : null,\n ];\n \n new Kompletr({ configuration, properties, dom, cache, broadcaster, onKeyup, onSelect, onError });\n } catch(e) {\n console.error(`[kompletr] An error has occured -> ${e.stack}`);\n }\n};\n\nwindow.kompletr = kompletr;\n\nexport { kompletr };"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/src/index.html b/src/index.html index 15505df..8e240d8 100644 --- a/src/index.html +++ b/src/index.html @@ -45,6 +45,17 @@ value="" /> + +