Update web/templates/search.html
This commit is contained in:
parent
fc82767666
commit
0ffecb9100
@ -23,9 +23,7 @@
|
||||
|
||||
<!-- Mobile dropdown filters -->
|
||||
<div class="filter-row mobile-filters">
|
||||
<button type="button" id="filterDropdownBtn" class="btn btn-secondary dropdown-toggle" aria-expanded="false">
|
||||
Filters ▾
|
||||
</button>
|
||||
<button type="button" id="filterDropdownBtn" class="btn btn-secondary" aria-expanded="false">Filters ▾</button>
|
||||
<div id="filterDropdownPanel" class="dropdown-panel">
|
||||
{% for f in field_options %}
|
||||
<label class="check-pill" style="display:block; margin:6px 0;">
|
||||
@ -125,7 +123,7 @@
|
||||
return url + sep + 't=' + Date.now();
|
||||
}
|
||||
|
||||
// Search history
|
||||
// Search history (keeps selected-fields subtitle)
|
||||
function renderHistory(items){
|
||||
const list = document.getElementById('searchHistoryList');
|
||||
const empty = document.getElementById('searchHistoryEmpty');
|
||||
@ -213,7 +211,7 @@
|
||||
});
|
||||
});
|
||||
|
||||
// Dropdown toggle for mobile filters
|
||||
// Mobile filter dropdown toggle
|
||||
(function(){
|
||||
const btn = document.getElementById('filterDropdownBtn');
|
||||
const panel = document.getElementById('filterDropdownPanel');
|
||||
@ -248,6 +246,99 @@
|
||||
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>
|
||||
|
||||
@ -289,12 +380,34 @@
|
||||
margin-top:6px;
|
||||
padding:10px;
|
||||
}
|
||||
#filterDropdownBtn {
|
||||
width:100%;
|
||||
text-align:left;
|
||||
}
|
||||
#filterDropdownBtn { width:100%; text-align:left; }
|
||||
}
|
||||
</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" %}
|
||||
{% endblock %}
|
||||
Loading…
Reference in New Issue
Block a user