110 lines
2.6 KiB
JavaScript
110 lines
2.6 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().replace(':', '')
|
|
}
|
|
|
|
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 = await this.site()
|
|
const request = await fetch('assets/templates/results.html')
|
|
const template = await request.text()
|
|
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
|
|
}
|
|
|
|
async site () {
|
|
if (!window.site) {
|
|
const data = await fetch('assets/data/site.json')
|
|
window.site = await data.json()
|
|
}
|
|
|
|
return window.site
|
|
}
|
|
}
|