diff --git a/public/index.html b/public/index.html index 42b46e7..7e0376a 100644 --- a/public/index.html +++ b/public/index.html @@ -123,13 +123,23 @@ badge.textContent = val + '+'; badge.style.background = getAgeColor(val); } - async function search() { + let lastQuery = ''; + let lastResults = []; + + async function search(force = false) { const query = document.getElementById('q').value.trim(); if (!query) return; const maxAge = parseInt(document.getElementById('maxAge').value, 10); window.history.replaceState({}, '', '?q=' + encodeURIComponent(query) + (maxAge < 21 ? `&maxAge=${maxAge}` : '')); const filmsDiv = document.getElementById('films'); filmsDiv.innerHTML = '

Searching...

'; + + // Si on a déjà cherché ce terme, et pas force, on ne refait pas le fetch + if (!force && lastQuery === query && lastResults.length) { + renderFilms(filterFilmsByMaxAge(lastResults, maxAge)); + return; + } + try { const base = window.location.origin; const response = await fetch(`${base}/search?q=${encodeURIComponent(query)}`); @@ -138,16 +148,8 @@ return; } let films = await response.json(); - if (!Array.isArray(films) || !films.length) { - filmsDiv.innerHTML = '

No results. Try another query.

'; - return; - } - // Filtres sources inutiles (pas de description et/ou pas d'âge) films = films.map(film => { film.results = film.results.filter(r => { - // On considère valide si : - // - summary ou parentsNeedToKnow ou details.summary >= 8 chars - // - ET un âge existe (age, normalizedMarks, marks, details.ageLegal, etc) let hasDescription = (r.summary && r.summary.length >= 8) || (r.parentsNeedToKnow && r.parentsNeedToKnow.length >= 8) || @@ -159,118 +161,133 @@ return film; }).filter(film => film.results.length > 0); - if (isFinite(maxAge)) { - films = films.filter(film => { - const uniqueResults = []; - const seenSources = new Set(); - film.results.forEach(r => { - if (!seenSources.has(r.source)) { - uniqueResults.push(r); - seenSources.add(r.source); - } - }); - const ages = getAllAges(uniqueResults); - if (ages.length === 0) return true; - return Math.max(...ages) <= maxAge; - }); - } - if (!films.length) { - filmsDiv.innerHTML = '

No results for this max age.

'; - return; - } - let html = ` - - - - - - - - `; - films.forEach(film => { - const allImgs = film.results.map(r => r.img).filter(Boolean); - const mainImg = allImgs.length ? allImgs[0] : null; - html += ` - - - `; - }); - html += '
TitleYearInformation sources
-
-
${film.title || 'Unknown title'}
- ${mainImg ? `Poster for ${film.title}` : ''} -
-
${film.year || 'N/A'}`; - const uniqueResults = []; - const seenSources = new Set(); - film.results.forEach(r => { - if (!seenSources.has(r.source)) { - uniqueResults.push(r); - seenSources.add(r.source); - } - }); - uniqueResults.forEach(r => { - html += `
`; - html += `

${r.source.charAt(0).toUpperCase() + r.source.slice(1)}

`; - if (r.link) { - html += `

View details

`; - } - if (r.source === 'commonsense') { - html += `

Recommended age: ${ageBadge(r.age)}

`; - html += `

Summary (CSM): ${shortSummary(r.summary || r.parentsNeedToKnow)}

`; - if (r.details && r.details.length) { - html += `

Details (CSM):

    `; - r.details.forEach(d => { - html += `
  • ${d.type}: ${d.score}/5 - ${shortSummary(d.description, 80)}
  • `; - }); - html += `
`; - } - } - else if (r.source === 'cinecheck') { - let numericAges = Array.isArray(r.normalizedMarks) && r.normalizedMarks.length - ? r.normalizedMarks - : (r.marks || []).map(x => { - let n = parseInt((x + '').replace(/\d+/, ''), 10); - return isNaN(n) ? null : n; - }).filter(n => n !== null && !isNaN(n)); - let minAge = numericAges.length ? Math.min(...numericAges) : ''; - html += `

Age(s) (Cinecheck): ${minAge ? ageBadge(minAge) : ''}${r.marks && r.marks.length ? r.marks.join(', ') : '-'}

`; - html += `

Summary (Cinecheck): ${shortSummary(r.summary)}

`; - if (r.details && r.details.length) { - html += `

Pictograms (Cinecheck): ${r.details.map(d => d.type).join(', ') || '-'}

`; - } - } - else if (r.source === 'filmages') { - html += `

Original title (Filmages): ${r.details.titleOriginalPage || r.details.titleOriginal || '-'}

`; - html += `

Legal age (Filmages): ${ageBadge(r.details.ageLegal)}

`; - html += `

Suggested age (Filmages): ${ageBadge(r.details.ageSuggested)}

`; - html += `

Summary (Filmages): ${shortSummary(r.details.summary)}

`; - html += `

Synthesis (Filmages): ${shortSummary(r.details.synthesis, 100)}

`; - if (r.details.indications && r.details.indications.length) { - html += `

Indications: ${shortSummary(r.details.indications.join(', '), 100)}

`; - } - if (r.details.counterIndications && r.details.counterIndications.length) { - html += `

Contra-indications: ${shortSummary(r.details.counterIndications.join(', '), 100)}

`; - } - } - else { - html += `

Summary: ${shortSummary(r.summary)}

`; - html += `

Age: ${ageBadge(r.age)}

`; - } - html += `
`; - }); - html += `
'; - filmsDiv.innerHTML = html; + lastQuery = query; + lastResults = films; + renderFilms(filterFilmsByMaxAge(films, maxAge)); } catch (error) { console.error('Search function error:', error); filmsDiv.innerHTML = `

Search failed. Check the console.

`; } } + function filterFilmsByMaxAge(films, maxAge) { + if (!isFinite(maxAge)) return films; + return films.filter(film => { + const uniqueResults = []; + const seenSources = new Set(); + film.results.forEach(r => { + if (!seenSources.has(r.source)) { + uniqueResults.push(r); + seenSources.add(r.source); + } + }); + const ages = getAllAges(uniqueResults); + if (ages.length === 0) return true; + return Math.max(...ages) <= maxAge; + }); + } + + // Extraction de la partie rendering pour pouvoir la réutiliser + function renderFilms(films) { + const filmsDiv = document.getElementById('films'); + if (!films.length) { + filmsDiv.innerHTML = '

No results for this max age.

'; + return; + } + let html = ` + + + + + + + + `; + films.forEach(film => { + const allImgs = film.results.map(r => r.img).filter(Boolean); + const mainImg = allImgs.length ? allImgs[0] : null; + html += ` + + + `; + }); + html += '
TitleYearInformation sources
+
+
${film.title || 'Unknown title'}
+ ${mainImg ? `Poster for ${film.title}` : ''} +
+
${film.year || 'N/A'}`; + const uniqueResults = []; + const seenSources = new Set(); + film.results.forEach(r => { + if (!seenSources.has(r.source)) { + uniqueResults.push(r); + seenSources.add(r.source); + } + }); + uniqueResults.forEach(r => { + html += `
`; + html += `

${r.source.charAt(0).toUpperCase() + r.source.slice(1)}

`; + if (r.link) { + html += `

View details

`; + } + if (r.source === 'commonsense') { + html += `

Recommended age: ${ageBadge(r.age)}

`; + html += `

Summary (CSM): ${shortSummary(r.summary || r.parentsNeedToKnow)}

`; + if (r.details && r.details.length) { + html += `

Details (CSM):

    `; + r.details.forEach(d => { + html += `
  • ${d.type}: ${d.score}/5 - ${shortSummary(d.description, 80)}
  • `; + }); + html += `
`; + } + } + else if (r.source === 'cinecheck') { + let numericAges = Array.isArray(r.normalizedMarks) && r.normalizedMarks.length + ? r.normalizedMarks + : (r.marks || []).map(x => { + let n = parseInt((x + '').replace(/\d+/, ''), 10); + return isNaN(n) ? null : n; + }).filter(n => n !== null && !isNaN(n)); + let minAge = numericAges.length ? Math.min(...numericAges) : ''; + html += `

Age(s) (Cinecheck): ${minAge ? ageBadge(minAge) : ''}${r.marks && r.marks.length ? r.marks.join(', ') : '-'}

`; + html += `

Summary (Cinecheck): ${shortSummary(r.summary)}

`; + if (r.details && r.details.length) { + html += `

Pictograms (Cinecheck): ${r.details.map(d => d.type).join(', ') || '-'}

`; + } + } + else if (r.source === 'filmages') { + html += `

Original title (Filmages): ${r.details.titleOriginalPage || r.details.titleOriginal || '-'}

`; + html += `

Legal age (Filmages): ${ageBadge(r.details.ageLegal)}

`; + html += `

Suggested age (Filmages): ${ageBadge(r.details.ageSuggested)}

`; + html += `

Summary (Filmages): ${shortSummary(r.details.summary)}

`; + html += `

Synthesis (Filmages): ${shortSummary(r.details.synthesis, 100)}

`; + if (r.details.indications && r.details.indications.length) { + html += `

Indications: ${shortSummary(r.details.indications.join(', '), 100)}

`; + } + if (r.details.counterIndications && r.details.counterIndications.length) { + html += `

Contra-indications: ${shortSummary(r.details.counterIndications.join(', '), 100)}

`; + } + } + else { + html += `

Summary: ${shortSummary(r.summary)}

`; + html += `

Age: ${ageBadge(r.age)}

`; + } + html += `
`; + }); + html += `
'; + filmsDiv.innerHTML = html; + } + document.getElementById('maxAge').addEventListener('input', function() { updateMaxAgeDisplay(); - search(); + // Pas de fetch, juste filtre en front + const query = document.getElementById('q').value.trim(); + if (!query || !lastResults.length) return; + const maxAge = parseInt(document.getElementById('maxAge').value, 10); + renderFilms(filterFilmsByMaxAge(lastResults, maxAge)); }); + window.addEventListener('DOMContentLoaded', () => { const params = new URLSearchParams(window.location.search); const q = params.get('q'); @@ -281,10 +298,11 @@ } if (q) { document.getElementById('q').value = q; - search(); + search(true); // force fetch initiale } }); - document.getElementById('q').addEventListener('keydown', e => { if (e.key === 'Enter') search(); }); + document.getElementById('q').addEventListener('keydown', e => { if (e.key === 'Enter') search(true); }); +