sutty-base-jekyll-theme/_packs/controllers/search_controller.js

107 lines
2.5 KiB
JavaScript
Raw Permalink Normal View History

2021-11-22 17:51:50 +00:00
import { Controller } from "stimulus";
import { Liquid } from "liquidjs";
2020-11-12 16:28:24 +00:00
2021-11-22 17:51:50 +00:00
const lunr = require("lunr");
require("lunr-languages/lunr.stemmer.support")(lunr);
require("lunr-languages/lunr.es")(lunr);
2020-11-12 16:28:24 +00:00
export default class extends Controller {
2021-11-22 17:51:50 +00:00
static targets = ["q"];
2020-11-12 16:28:24 +00:00
2021-11-22 17:51:50 +00:00
get q() {
if (!this.hasQTarget) return;
if (!this.qTarget.value.trim().length === 0) return;
2020-11-12 16:28:24 +00:00
2021-11-22 17:51:50 +00:00
return this.qTarget.value.trim().replaceAll(/[:~\*\^\+\-]/gi, "");
2021-03-26 16:11:29 +00:00
}
2020-11-12 16:28:24 +00:00
2021-11-22 17:51:50 +00:00
connect() {
const q = new URLSearchParams(window.location.search).get("q")?.trim();
2020-11-12 16:28:24 +00:00
2021-03-26 16:11:29 +00:00
if (q) {
2021-11-22 17:51:50 +00:00
this.qTarget.value = q;
this.search();
2021-03-26 16:11:29 +00:00
}
2020-11-12 16:28:24 +00:00
}
2021-11-22 17:51:50 +00:00
async search(event) {
2021-03-26 16:11:29 +00:00
// Detiene el envío del formulario
if (event) {
2021-11-22 17:51:50 +00:00
event.preventDefault();
event.stopPropagation();
2021-03-26 16:11:29 +00:00
}
2021-11-22 17:51:50 +00:00
this.formDisable = true;
2021-03-26 16:11:29 +00:00
// Obtiene el término de búsqueda
2021-11-22 17:51:50 +00:00
const q = this.q;
2021-03-26 16:11:29 +00:00
// Si no hay término de búsqueda, no hay búsqueda
if (q) {
// Trae el índice de búsqueda
2021-11-22 17:51:50 +00:00
await this.fetch();
2020-11-12 16:28:24 +00:00
2021-03-26 16:11:29 +00:00
// Hasta que no haya índice no buscamos nada, esto evita que se
// aprete enter dos veces y se fallen cosas.
2021-11-22 17:51:50 +00:00
if (!window.index) return;
2021-03-26 16:11:29 +00:00
}
2020-11-12 16:28:24 +00:00
2021-11-22 17:51:50 +00:00
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;
2020-11-12 16:28:24 +00:00
}
2021-11-22 17:51:50 +00:00
async fetch() {
2021-03-26 16:11:29 +00:00
// Solo permite descargar uno a la vez
2021-11-22 17:51:50 +00:00
if (this.fetching) return;
2021-03-26 16:11:29 +00:00
2021-11-22 17:51:50 +00:00
this.fetching = true;
let response;
2020-11-12 16:28:24 +00:00
2021-03-26 16:11:29 +00:00
// Si no existe el índice, lo descarga y procesa Lunr
2020-11-12 16:28:24 +00:00
if (!window.data) {
2021-11-22 17:51:50 +00:00
response = await fetch("data.json");
window.data = await response.json();
2020-11-12 16:28:24 +00:00
}
if (!window.index) {
2021-11-22 17:51:50 +00:00
response = await fetch("idx.json");
const idx = await response.json();
window.index = lunr.Index.load(idx);
2020-11-12 16:28:24 +00:00
}
2021-03-26 16:11:29 +00:00
// Permitir volver a ejecutar
2021-11-22 17:51:50 +00:00
this.fetching = false;
2021-03-26 16:11:29 +00:00
}
2021-11-22 17:51:50 +00:00
set formDisable(disable) {
this.element.elements.forEach((x) => (x.disabled = disable));
2020-11-12 16:28:24 +00:00
}
/*
* Liquid renderer
*
* @return Liquid
*/
2021-11-22 17:51:50 +00:00
get engine() {
if (!window.liquid) window.liquid = new Liquid();
2020-11-12 16:28:24 +00:00
2021-11-22 17:51:50 +00:00
return window.liquid;
2020-11-12 16:28:24 +00:00
}
}