106 lines
2.5 KiB
JavaScript
106 lines
2.5 KiB
JavaScript
import { Controller } from "stimulus";
|
|
import { Liquid } from "liquidjs";
|
|
|
|
const lunr = require("lunr");
|
|
require("lunr-languages/lunr.stemmer.support")(lunr);
|
|
require("lunr-languages/lunr.es")(lunr);
|
|
|
|
export default class extends Controller {
|
|
static targets = ["q"];
|
|
|
|
get q() {
|
|
if (!this.hasQTarget) return;
|
|
if (!this.qTarget.value.trim().length === 0) return;
|
|
|
|
return this.qTarget.value.trim().replaceAll(/[:~\*\^\+\-]/gi, "");
|
|
}
|
|
|
|
connect() {
|
|
const q = new URLSearchParams(window.location.search).get("q")?.trim();
|
|
|
|
if (q) {
|
|
this.qTarget.value = q;
|
|
this.search();
|
|
}
|
|
}
|
|
|
|
async search(event) {
|
|
// Detiene el envío del formulario
|
|
if (event) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
}
|
|
|
|
this.formDisable = true;
|
|
|
|
// Obtiene el término de búsqueda
|
|
const q = this.q;
|
|
// Si no hay término de búsqueda, no hay búsqueda
|
|
if (q) {
|
|
// Trae el índice de búsqueda
|
|
await this.fetch();
|
|
|
|
// Hasta que no haya índice no buscamos nada, esto evita que se
|
|
// aprete enter dos veces y se fallen cosas.
|
|
if (!window.index) return;
|
|
}
|
|
|
|
const main = document.querySelector("main");
|
|
const results = window.index
|
|
.search(q)
|
|
.map((r) => window.data.find((a) => a.id == r.ref));
|
|
const site = window.site;
|
|
const template = window.templates.results;
|
|
const html = await this.engine.parseAndRender(template, {
|
|
q,
|
|
site,
|
|
results,
|
|
});
|
|
const title = `${site.i18n.search.title} - ${q}`;
|
|
const query = new URLSearchParams({ q });
|
|
|
|
window.history.pushState({ q }, title, `?${query.toString()}`);
|
|
document.title = title;
|
|
|
|
main.innerHTML = html;
|
|
this.formDisable = false;
|
|
}
|
|
|
|
async fetch() {
|
|
// Solo permite descargar uno a la vez
|
|
if (this.fetching) return;
|
|
|
|
this.fetching = true;
|
|
let response;
|
|
|
|
// Si no existe el índice, lo descarga y procesa Lunr
|
|
if (!window.data) {
|
|
response = await fetch("data.json");
|
|
window.data = await response.json();
|
|
}
|
|
|
|
if (!window.index) {
|
|
response = await fetch("idx.json");
|
|
const idx = await response.json();
|
|
window.index = lunr.Index.load(idx);
|
|
}
|
|
|
|
// Permitir volver a ejecutar
|
|
this.fetching = false;
|
|
}
|
|
|
|
set formDisable(disable) {
|
|
this.element.elements.forEach((x) => (x.disabled = disable));
|
|
}
|
|
|
|
/*
|
|
* Liquid renderer
|
|
*
|
|
* @return Liquid
|
|
*/
|
|
get engine() {
|
|
if (!window.liquid) window.liquid = new Liquid();
|
|
|
|
return window.liquid;
|
|
}
|
|
}
|