This commit is contained in:
Jürgen Mummert
2025-12-29 21:31:42 +01:00
parent 04f3e76c8f
commit 987441700f
@@ -4,14 +4,25 @@ Contao 5 Frontend Module Template
#} #}
<!-- indexer::stop --> <!-- indexer::stop -->
<div <div
id="topsearch"
class="meilisearch-search" class="meilisearch-search"
data-limit="{{ meiliLimit }}" data-limit="{{ meiliLimit }}"
> >
<div class="meilisearch-search-field"> <div class="headersearch">
<form id="search-form" onsubmit="return false;">
<div class="formbody">
<div class="widget widget-text">
<label for="search_input" class="invisible">
{{ 'Suchen'|trans }}
</label>
<div class="search-field">
<input <input
type="search" type="search"
id="meilisearch-input" name="keywords"
placeholder="Suche …" id="search_input"
class="text"
placeholder="Suchbegriff eingeben..."
autocomplete="off" autocomplete="off"
> >
@@ -24,8 +35,26 @@ Contao 5 Frontend Module Template
× ×
</button> </button>
</div> </div>
</div>
</div>
</form>
<div id="meilisearch-results" class="meilisearch-results"></div> <div id="search-results"></div>
<template id="search-result-template">
<div class="search-item">
<div class="siteimage"></div>
<div class="teaser">
<div class="title"></div>
<div class="extract"></div>
<div class="pfad"></div>
</div>
<a class="masterurl" href="#" title=""></a>
</div>
</template>
</div>
</div> </div>
<!-- indexer::continue --> <!-- indexer::continue -->
<script type="module"> <script type="module">
@@ -38,9 +67,15 @@ Contao 5 Frontend Module Template
return; return;
} }
const input = wrapper.querySelector('#meilisearch-input'); const input = wrapper.querySelector('#search_input');
const clear = wrapper.querySelector('.meilisearch-clear'); const clear = wrapper.querySelector('.meilisearch-clear');
const results = wrapper.querySelector('#meilisearch-results'); const results = wrapper.querySelector('#search-results');
const template = wrapper.querySelector('#search-result-template');
if (!input || !results || !template) {
console.warn('[Meilisearch] Required elements not found');
return;
}
const limit = parseInt(wrapper.dataset.limit, 10) || 50; const limit = parseInt(wrapper.dataset.limit, 10) || 50;
@@ -53,6 +88,9 @@ Contao 5 Frontend Module Template
let abortController = null; let abortController = null;
// ----------------------------
// Clear button
// ----------------------------
clear.addEventListener('click', () => { clear.addEventListener('click', () => {
input.value = ''; input.value = '';
results.innerHTML = ''; results.innerHTML = '';
@@ -60,6 +98,9 @@ Contao 5 Frontend Module Template
input.focus(); input.focus();
}); });
// ----------------------------
// Input handling
// ----------------------------
input.addEventListener('input', async () => { input.addEventListener('input', async () => {
const query = input.value.trim(); const query = input.value.trim();
@@ -97,49 +138,59 @@ Contao 5 Frontend Module Template
} catch (e) { } catch (e) {
if (e.name !== 'AbortError') { if (e.name !== 'AbortError') {
console.error('Meilisearch error:', e); console.error('[Meilisearch]', e);
} }
} }
}); });
// ----------------------------
// Render results via <template>
// ----------------------------
function renderResults(hits) { function renderResults(hits) {
results.innerHTML = ''; results.innerHTML = '';
if (!hits.length) { if (!hits || !hits.length) {
return; return;
} }
for (const hit of hits) { for (const hit of hits) {
const article = document.createElement('article'); const node = template.content.cloneNode(true);
article.className = 'meilisearch-result type-' + (hit.type || 'default');
const link = document.createElement('a'); const image = node.querySelector('.siteimage');
link.href = hit.url || '#'; const title = node.querySelector('.title');
link.className = 'meilisearch-link'; const extract = node.querySelector('.extract');
const path = node.querySelector('.pfad');
const link = node.querySelector('.masterurl');
if (hit.poster) { // Title
const img = document.createElement('img');
img.src = hit.poster;
img.alt = '';
img.loading = 'lazy';
link.appendChild(img);
}
const title = document.createElement('h3');
title.textContent = hit.title || ''; title.textContent = hit.title || '';
link.appendChild(title);
// Link
link.href = hit.url || '#';
link.title = hit.title || '';
// Extract / highlight
if (hit._formatted?.text) { if (hit._formatted?.text) {
const extract = document.createElement('p');
extract.className = 'meilisearch-extract';
extract.innerHTML = hit._formatted.text; extract.innerHTML = hit._formatted.text;
link.appendChild(extract); } else {
extract.textContent = '';
} }
article.appendChild(link); // Path (URL ohne Schema)
results.appendChild(article); if (hit.url) {
path.textContent = hit.url.replace(/^https?:\/\//, '');
}
// Image
if (hit.poster) {
image.style.backgroundImage = `url(${hit.poster})`;
} else {
image.style.backgroundImage = '';
}
results.appendChild(node);
} }
} }
}); });