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 { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[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(); });
})();