Update web/templates/search.html
This commit is contained in:
parent
fc82767666
commit
0ffecb9100
@ -23,9 +23,7 @@
|
|||||||
|
|
||||||
<!-- Mobile dropdown filters -->
|
<!-- Mobile dropdown filters -->
|
||||||
<div class="filter-row mobile-filters">
|
<div class="filter-row mobile-filters">
|
||||||
<button type="button" id="filterDropdownBtn" class="btn btn-secondary dropdown-toggle" aria-expanded="false">
|
<button type="button" id="filterDropdownBtn" class="btn btn-secondary" aria-expanded="false">Filters ▾</button>
|
||||||
Filters ▾
|
|
||||||
</button>
|
|
||||||
<div id="filterDropdownPanel" class="dropdown-panel">
|
<div id="filterDropdownPanel" class="dropdown-panel">
|
||||||
{% for f in field_options %}
|
{% for f in field_options %}
|
||||||
<label class="check-pill" style="display:block; margin:6px 0;">
|
<label class="check-pill" style="display:block; margin:6px 0;">
|
||||||
@ -125,7 +123,7 @@
|
|||||||
return url + sep + 't=' + Date.now();
|
return url + sep + 't=' + Date.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search history
|
// Search history (keeps selected-fields subtitle)
|
||||||
function renderHistory(items){
|
function renderHistory(items){
|
||||||
const list = document.getElementById('searchHistoryList');
|
const list = document.getElementById('searchHistoryList');
|
||||||
const empty = document.getElementById('searchHistoryEmpty');
|
const empty = document.getElementById('searchHistoryEmpty');
|
||||||
@ -213,7 +211,7 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Dropdown toggle for mobile filters
|
// Mobile filter dropdown toggle
|
||||||
(function(){
|
(function(){
|
||||||
const btn = document.getElementById('filterDropdownBtn');
|
const btn = document.getElementById('filterDropdownBtn');
|
||||||
const panel = document.getElementById('filterDropdownPanel');
|
const panel = document.getElementById('filterDropdownPanel');
|
||||||
@ -248,6 +246,99 @@
|
|||||||
el.textContent = pick;
|
el.textContent = pick;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
/* ===============================
|
||||||
|
Illustration of the Day (client-only, deterministic)
|
||||||
|
=============================== */
|
||||||
|
(function illustrationOfTheDay(){
|
||||||
|
const total = {{ total|default:0 }};
|
||||||
|
const iotdTextEl = document.getElementById('iotd-text');
|
||||||
|
const iotdOpenEl = document.getElementById('iotd-open');
|
||||||
|
if (!iotdTextEl || !iotdOpenEl) return;
|
||||||
|
|
||||||
|
if (!total || total < 1){
|
||||||
|
iotdTextEl.textContent = 'No illustrations available yet.';
|
||||||
|
iotdOpenEl.style.display = 'none';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seed from local date (YYYYMMDD) so it’s the same for everyone that day
|
||||||
|
const today = new Date();
|
||||||
|
const ymd = today.getFullYear()*10000 + (today.getMonth()+1)*100 + today.getDate();
|
||||||
|
|
||||||
|
// 32-bit xorshift PRNG for a good daily seed
|
||||||
|
function xorshift32(seed){
|
||||||
|
let x = seed | 0;
|
||||||
|
x ^= x << 13; x ^= x >>> 17; x ^= x << 5;
|
||||||
|
return (x >>> 0);
|
||||||
|
}
|
||||||
|
const seed = xorshift32(ymd ^ 0x9E3779B9);
|
||||||
|
|
||||||
|
const maxGuess = Math.max(100, Math.floor(total * 4));
|
||||||
|
const maxAttempts = Math.min(600, maxGuess);
|
||||||
|
|
||||||
|
function idAt(i){
|
||||||
|
const v = (Math.imul(i + 1, 1103515245) + 12345 + seed) >>> 0;
|
||||||
|
return 1 + (v % maxGuess);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchEntryHtml(id){
|
||||||
|
const url = entryUrlFor(id);
|
||||||
|
try{
|
||||||
|
const r = await fetch(url, { credentials: 'same-origin' });
|
||||||
|
if (r.ok) return await r.text();
|
||||||
|
}catch(_){}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensurePunct(str){
|
||||||
|
const s = (str || '').trim();
|
||||||
|
if (!s) return '';
|
||||||
|
return /[.!?…]$/.test(s) ? s : (s + '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractSectionText(doc, label){
|
||||||
|
const labels = doc.querySelectorAll('.section-label, .meta-label, h3, h4, strong');
|
||||||
|
for (const el of labels){
|
||||||
|
const t = (el.textContent || '').trim().toLowerCase();
|
||||||
|
if (t === label){
|
||||||
|
const section = el.closest('.section') || el.parentElement;
|
||||||
|
if (section){
|
||||||
|
const body = section.querySelector('.lead-text') ||
|
||||||
|
section.querySelector('.section-body') ||
|
||||||
|
section.querySelector('p');
|
||||||
|
if (body) return (body.textContent || '').trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const alt = doc.querySelector('.lead-text, .section-body');
|
||||||
|
return alt ? (alt.textContent || '').trim() : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderIotd(id, html){
|
||||||
|
const dom = new DOMParser().parseFromString(html, 'text/html');
|
||||||
|
const illustration = extractSectionText(dom, 'illustration');
|
||||||
|
const application = extractSectionText(dom, 'application');
|
||||||
|
const merged = (ensurePunct(illustration) + (application ? ' ' + application : '')).trim();
|
||||||
|
|
||||||
|
iotdTextEl.textContent = merged || 'Open to view today’s illustration.';
|
||||||
|
iotdOpenEl.href = entryUrlFor(id);
|
||||||
|
iotdOpenEl.style.display = 'inline-block';
|
||||||
|
}
|
||||||
|
|
||||||
|
(async function findAndRender(){
|
||||||
|
for (let i = 0; i < maxAttempts; i++){
|
||||||
|
const id = idAt(i);
|
||||||
|
const html = await fetchEntryHtml(id);
|
||||||
|
if (html){
|
||||||
|
renderIotd(id, html);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iotdTextEl.textContent = 'Unable to load today’s illustration.';
|
||||||
|
iotdOpenEl.style.display = 'none';
|
||||||
|
})();
|
||||||
|
})();
|
||||||
|
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -289,12 +380,34 @@
|
|||||||
margin-top:6px;
|
margin-top:6px;
|
||||||
padding:10px;
|
padding:10px;
|
||||||
}
|
}
|
||||||
#filterDropdownBtn {
|
#filterDropdownBtn { width:100%; text-align:left; }
|
||||||
width:100%;
|
|
||||||
text-align:left;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<!-- Save q + selected fields exactly as submitted -->
|
||||||
|
<script>
|
||||||
|
(function(){
|
||||||
|
const form = document.querySelector('form.search-form') || document.querySelector('form[method="get"]');
|
||||||
|
if (!form) return;
|
||||||
|
const qInput = form.querySelector('input[name="q"]');
|
||||||
|
|
||||||
|
form.addEventListener('submit', () => {
|
||||||
|
const fd = new FormData(form);
|
||||||
|
const fields = [];
|
||||||
|
for (const [k, v] of fd.entries()) {
|
||||||
|
if (k.startsWith('sel[') && k.endsWith(']') && (v === 'on' || v === 'true' || v === '1')) {
|
||||||
|
fields.push(k.slice(4, -1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const q = (qInput && qInput.value || '').trim();
|
||||||
|
|
||||||
|
try {
|
||||||
|
localStorage.setItem('lastSearchQ', q);
|
||||||
|
localStorage.setItem('lastSearchFields', JSON.stringify(fields));
|
||||||
|
} catch (_) {}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
{% include "partials/announcement_modal.html" %}
|
{% include "partials/announcement_modal.html" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Loading…
Reference in New Issue
Block a user