Skip to content

Commit

Permalink
chore: clean up status for next developments
Browse files Browse the repository at this point in the history
  • Loading branch information
steve-lebleu committed Feb 25, 2024
1 parent b2973ef commit 2e338cd
Showing 1 changed file with 134 additions and 78 deletions.
212 changes: 134 additions & 78 deletions src/js/vanilla/kompleter.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,19 @@
throw new Error('window.kompleter already exists !');
}

/**
* @summary Kompleter.js is a library providing features dedicated to autocomplete fields.
* @author Steve Lebleu <[email protected]>
*/
const kompleter = {

/**
* @descrption Animations functions
*/
animations: {
fadeIn: function(element, display) {
fadeIn: function(element, display = 'block', duration = 500) {
element.style.opacity = 0;
element.style.display = display || 'block';
element.style.display = display;
(function fade(){
let value = parseFloat(element.style.opacity);
if (!((value += .1) > 1)) {
Expand All @@ -16,7 +24,7 @@
}
})()
},
fadeOut: function(element) {
fadeOut: function(element, duration = 500) {
element.style.opacity = 1;
(function fade() {
if ((element.style.opacity -= .1) < 0) {
Expand All @@ -26,33 +34,87 @@
}
})();
},
slideUp: function() {

slideUp: function(element, duration = 500) {
element.style.transitionProperty = 'height, margin, padding';
element.style.transitionDuration = duration + 'ms';
element.style.boxSizing = 'border-box';
element.style.height = element.offsetHeight + 'px';
element.offsetHeight;
element.style.overflow = 'hidden';
element.style.height = 0;
element.style.paddingTop = 0;
element.style.paddingBottom = 0;
element.style.marginTop = 0;
element.style.marginBottom = 0;
window.setTimeout( () => {
element.style.display = 'none';
element.style.removeProperty('height');
element.style.removeProperty('padding-top');
element.style.removeProperty('padding-bottom');
element.style.removeProperty('margin-top');
element.style.removeProperty('margin-bottom');
element.style.removeProperty('overflow');
element.style.removeProperty('transition-duration');
element.style.removeProperty('transition-property');
}, duration);
},
slideDown: function() {

slideDown: function(element, duration = 500) {
element.style.removeProperty('display');
let display = window.getComputedStyle(element).display;
if (display === 'none') display = 'block';
element.style.display = display;
let height = element.offsetHeight;
element.style.overflow = 'hidden';
element.style.height = 0;
element.style.paddingTop = 0;
element.style.paddingBottom = 0;
element.style.marginTop = 0;
element.style.marginBottom = 0;
element.offsetHeight;
element.style.boxSizing = 'border-box';
element.style.transitionProperty = "height, margin, padding";
element.style.transitionDuration = duration + 'ms';
element.style.height = height + 'px';
element.style.removeProperty('padding-top');
element.style.removeProperty('padding-bottom');
element.style.removeProperty('margin-top');
element.style.removeProperty('margin-bottom');
window.setTimeout( () => {
element.style.removeProperty('height');
element.style.removeProperty('overflow');
element.style.removeProperty('transition-duration');
element.style.removeProperty('transition-property');
}, duration);
}
},

/**
* @description Custom events
*/
events: {
'kompleter.render.result.done': new CustomEvent('kompleter.render.result.done', {
detail: {},
error: (detail = {}) => new CustomEvent('kompleter.error', {
detail,
bubble: true,
cancelable: false,
composed: false,
}),
'kompleter.request.done': new CustomEvent('kompleter.request.done', {
detail: {},
rendrResultDone: (detail = {}) => new CustomEvent('kompleter.render.result.done', {
detail,
bubble: true,
cancelable: false,
composed: false,
}),
'kompleter.result.show': new CustomEvent('kompleter.result.show', {
detail: {},
requestDone: (detail = {}) => new CustomEvent('kompleter.request.done', {
detail,
bubble: true,
cancelable: false,
composed: false,
})
}),
},

/**
* @description Handlers of all religions
*/
handlers: {
build: function (element, attributes = []) {
const htmlElement = document.createElement(element);
Expand Down Expand Up @@ -120,12 +182,10 @@
.then(result => result.json())
.then(result => {
kompleter.props.response = this.filter(result);
document.dispatchEvent(kompleter.events['kompleter.request.done']);
document.dispatchEvent(kompleter.events.requestDone());
})
.catch(e => {
console.error(e.message);
kompleter.htmlElements.result.innerHTML = '<div class="item--result">Error</div>';
kompleter.animations.fadeIn(kompleter.htmlElements.result);
document.dispatchEvent(kompleter.events.error({ message: e.message, stack: e?.stack, instance: e }));
});
},
select: function () {
Expand All @@ -136,16 +196,24 @@
kompleter.htmlElements.result.style.display = 'none';
},
validate: function(options) {
// Ne valider que ce qui est donné ou requis
// Le reste doit fallback sur des valeurs par défaut quand c'est possible
// Valid only what's required OR provided
// The rest should fallback on default values when it's feasible
}
},

/**
* @description HTMLElements container
*/
htmlElements: {
focused: null,
input: null,
result: null,
suggestions: [],
},

/**
* @description Events listeners
*/
listeners: {
onHide: () => {
const body = document.getElementsByTagName('body')[0];
Expand All @@ -171,18 +239,11 @@
},
onRequestDone: () => {
document.addEventListener('kompleter.request.done', (e) => {
kompleter.renders.results(e)
kompleter.render.results(e)
});
},
onRenderDone: () => {
document.addEventListener('kompleter.render.result.done', (e) => {
console.log('kompleter.render.result.done', e)
kompleter.animations.fadeIn(kompleter.htmlElements.result);
kompleter.listeners.onSelect('item--result');
});
},
onShow: () => {
document.addEventListener('kompleter.result.show', (e) => {
kompleter.animations.fadeIn(kompleter.htmlElements.result);
kompleter.listeners.onSelect('item--result');
});
Expand All @@ -200,9 +261,13 @@
});
},
},

/**
* @description Public options
*/
options: {
id: null,
dataSource: null,
dataSource: null, // Can be ommited if data is provided directly. In this case we don't fetch. Allow credentials or API key on fetch ?
store: {
type: 'memory', // memory | indexedDB | localStorage
timelife: 50000,
Expand All @@ -211,6 +276,9 @@
type: 'fadeIn',
duration: 500
},
notification: {
// TODO
},
begin: true,
startOnChar: 2,
maxResults: 10,
Expand All @@ -223,14 +291,26 @@
beforeSelectItem: (e, dataset, current) => {},
afterSelectItem: (e, dataset, current) => {},
},

/**
* @description Internal properties
*/
props: {
response: {}, // Clarify / refactor the usage of response vs suggestions
pointer: -1,
previousValue: null,
},
renders: {

/**
* @description Rendering methods
*/
render: {
error: function(e) {
// TODO Do better on the error display / logging / notifications
kompleter.htmlElements.result.innerHTML = '<div class="item--result">Error</div>';
kompleter.animations.fadeIn(kompleter.htmlElements.result);
},
results: function(e) {
console.log('render.results', e)
let html = '';
if(kompleter.props.response && kompleter.props.response.length) {
const properties = kompleter.options.fieldsToDisplay.length; // TODO should be validated as 3 or 4 max + flexbox design
Expand All @@ -247,19 +327,16 @@
html = '<div class="item--result">Not found</div>';
}
kompleter.htmlElements.result.innerHTML = html;
console.log('kompleter.htmlElements.result', kompleter.htmlElements.result)
document.dispatchEvent(kompleter.events['kompleter.render.result.done'])
document.dispatchEvent(kompleter.events.rendrResultDone());
}
},
init: function(options) {

// Préfixer sur les valeurs

// ---------- Gérer les callbacks opts

// ---------- Gérer le store
// Gérer le fetch mutliple en cas de store
// Gérer la durée de validité du store en cas de store
/**
* @description Kompleter entry point
*
* @param {*} options
*/
init: function(options) {

// ---------- Gérer les animations

Expand All @@ -274,34 +351,23 @@

// ---------- Gérer les paramètres opts

// Aller chercher sur data- et options, faire un merge, c'est options qui gagne si conflit
// Valider le résultat
// id unique, obligé

// Valider le résultat -> pas de lib externe
// id unique, obligé
// L'assigner si c'est ok

// /!\ Si tu bouges aux options ici, tu vas devoir adapter le jQuery aussi

// --- Currently managed as data-attributes

const dataSource = kompleter.htmlElements.input.dataset['url'];
const filterOn = kompleter.htmlElements.input.dataset['filter-on'];
const fieldsToDisplay = kompleter.htmlElements.input.dataset['fields-to-display'];

console.log('v', dataSource)
console.log('v', filterOn)
console.log('v', fieldsToDisplay)

// --- Other ones

/**
id
store: false, // Todo
animation: '', // Todo
animationSpeed: '', // Todo
store: false,
animation: '',
animationSpeed: '',
begin: true,
startOnChar: 2,
maxResults: 10,
notification: an instance of notifier, console by default
beforeDisplayResults: (e, dataset) => {},
afterDisplayResults: (e, dataset) => {},
beforeFocusOnItem: (e, dataset, current) => {},
Expand All @@ -310,29 +376,19 @@
afterSelectItem: (e, dataset, current) => {},
*/

// --- Playable as data-
// --- Special case: the id -> ? Pass the input by id reference or HTMLElement ?

/**
store: false, // Todo
animation: '', // Todo
animationSpeed: '', // Todo
begin: true,
startOnChar: 2,
maxResults: 10,
*/

// --- Required as options
// Préfixer sur les valeurs

/**
beforeDisplayResults: (e, dataset) => {},
afterDisplayResults: (e, dataset) => {},
beforeFocusOnItem: (e, dataset, current) => {},
afterFocusOnItem: (e, dataset, current) => {},
beforeSelectItem: (e, dataset, current) => {},
afterSelectItem: (e, dataset, current) => {},
*/
// ---------- Gérer les callbacks opts

// --- Special case: the id -> ? Pass the input by id reference or HTMLElement ?
// ---------- Gérer le store
// Gérer le fetch mutliple en cas de store
// Gérer la durée de validité du store en cas de store

// ---------- Errorrs management
// Try catches
// Display

kompleter.listeners.onHide();
kompleter.listeners.onShow();
Expand Down

0 comments on commit 2e338cd

Please sign in to comment.