Code du thème Base
Le thème de référence, version 1.1.0. Tout télécharger (.zip)
assets/theme.js
/* Thème Base : suggestions de la barre de recherche (produits et catégories pendant la frappe). */
(function () {
'use strict';
var form = document.querySelector('form[data-suggest]');
if (!form || !window.fetch) return;
var input = form.querySelector('input[name="q"]');
var url = form.getAttribute('data-suggest');
var box = document.createElement('div');
box.className = 'suggest';
box.id = 'suggestions';
box.setAttribute('role', 'listbox');
box.hidden = true;
form.appendChild(box);
var timer, last = '', active = -1;
function esc(s) { return String(s).replace(/[&<>"']/g, function (c) { return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]; }); }
function close() { box.hidden = true; input.setAttribute('aria-expanded', 'false'); active = -1; }
function items() { return box.querySelectorAll('a'); }
function render(d) {
if (!d.products.length && !d.categories.length) {
box.innerHTML = '<p class="suggest-empty">Aucun résultat pour « ' + esc(input.value) + ' »</p>';
} else {
box.innerHTML = (d.categories.length ? '<p class="suggest-title">Rayons</p>' + d.categories.map(function (c) {
return '<a role="option" href="' + esc(c.url) + '">' + esc(c.name) + '</a>';
}).join('') : '') + (d.products.length ? '<p class="suggest-title">Produits</p>' + d.products.map(function (p) {
return '<a role="option" class="suggest-product" href="' + esc(p.url) + '">' + (p.image ? '<img src="' + esc(p.image) + '" alt="">' : '<i></i>')
+ '<span>' + esc(p.name) + '</span><b>' + esc(p.price) + '</b></a>';
}).join('') : '') + '<a role="option" class="suggest-all" href="' + esc(d.all_url) + '">Voir tous les résultats →</a>';
}
box.hidden = false;
input.setAttribute('aria-expanded', 'true');
active = -1;
}
input.addEventListener('input', function () {
clearTimeout(timer);
var q = input.value.trim();
if (q.length < 2) { close(); return; }
timer = setTimeout(function () {
if (q === last && !box.hidden) return;
last = q;
fetch(url + (url.indexOf('?') < 0 ? '?' : '&') + 'q=' + encodeURIComponent(q), { headers: { Accept: 'application/json' } })
.then(function (r) { return r.json(); })
.then(function (d) { if (input.value.trim() === q) render(d); })
.catch(close);
}, 180);
});
input.addEventListener('keydown', function (e) {
var list = items();
if (box.hidden || !list.length) return;
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
e.preventDefault();
active = (active + (e.key === 'ArrowDown' ? 1 : -1) + list.length) % list.length;
list.forEach(function (a, i) { a.classList.toggle('on', i === active); a.setAttribute('aria-selected', i === active ? 'true' : 'false'); });
} else if (e.key === 'Enter' && active >= 0) {
e.preventDefault();
location.href = list[active].href;
} else if (e.key === 'Escape') {
close();
}
});
document.addEventListener('click', function (e) { if (!form.contains(e.target)) close(); });
})();