Update web/templates/search.html
This commit is contained in:
parent
69943c2717
commit
1311bd25fd
@ -35,7 +35,7 @@
|
||||
<li><strong>Wildcard search</strong> — use <code>*</code>.<br>
|
||||
<em>Example:</em> <code>lov*</code></li>
|
||||
<li><strong>Scripture search</strong> — type a Bible book.<br>
|
||||
<em>Example:</em> <code>John 3:16</code></li>
|
||||
<em>Example:</em> <code>John 3:16</code></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@ -84,12 +84,22 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===== Illustration of the Day ===== -->
|
||||
<div class="container">
|
||||
<form method="get" class="search-form">
|
||||
<h1 class="page-title">Illustration of the Day</h1>
|
||||
<!-- insert illustration of the day here -->
|
||||
</div>
|
||||
</form>
|
||||
<form method="get" class="search-form">
|
||||
<h1 class="page-title">Illustration of the Day</h1>
|
||||
<!-- insert illustration of the day here -->
|
||||
<div id="iotd-card" class="card" style="padding:16px; margin:12px 0;">
|
||||
<div id="iotd-text" class="lead-text" style="white-space:pre-wrap; margin-bottom:12px;">
|
||||
Loading…
|
||||
</div>
|
||||
<div id="iotd-actions">
|
||||
<a id="iotd-open" href="#" class="btn btn-primary">Open Illustration</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
@ -192,7 +202,7 @@
|
||||
}
|
||||
refetchRecent();
|
||||
|
||||
// ✅ Log searches with Beacon on submit (this is what was missing)
|
||||
// ✅ Log searches with Beacon on submit
|
||||
const searchForm = document.querySelector('form.search-form');
|
||||
if (searchForm){
|
||||
searchForm.addEventListener('submit', ()=>{
|
||||
@ -200,7 +210,6 @@
|
||||
const fd = new FormData(searchForm);
|
||||
const data = new URLSearchParams();
|
||||
data.append('q', (fd.get('q') || '').trim());
|
||||
// selected checkboxes (match your field names)
|
||||
['subject','illustration','application','scripture_raw','source','talk_title','talk_number','entry_code']
|
||||
.forEach(k=>{
|
||||
if (fd.get(k)) data.append(`sel[${k}]`, 'on');
|
||||
@ -237,6 +246,109 @@
|
||||
if (!clickedInside) panel.classList.remove('open');
|
||||
}
|
||||
});
|
||||
|
||||
/* ===============================
|
||||
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();
|
||||
|
||||
// Simple string hash -> 32-bit -> xorshift for decent spread
|
||||
function xorshift32(seed){
|
||||
let x = seed | 0;
|
||||
x ^= x << 13; x ^= x >>> 17; x ^= x << 5;
|
||||
return (x >>> 0);
|
||||
}
|
||||
function pickIndex(max, seed){
|
||||
// (0..max-1)
|
||||
return xorshift32(seed) % max;
|
||||
}
|
||||
|
||||
// We don’t know if IDs are contiguous, so:
|
||||
// 1) choose a *candidate* ID in [1..maxIdGuess]
|
||||
// 2) try up to N nearby IDs until one 200s
|
||||
// Best guess for max id is "total * 1.5" (cheap heuristic).
|
||||
const maxIdGuess = Math.max(total, Math.floor(total * 1.5));
|
||||
let candidate = 1 + pickIndex(maxIdGuess, ymd ^ 0x9E3779B9);
|
||||
|
||||
async function tryFetch(id){
|
||||
const url = entryUrlFor(id);
|
||||
try{
|
||||
const r = await fetch(url, { credentials:'same-origin' });
|
||||
if (r.ok) {
|
||||
const html = await r.text();
|
||||
return { ok:true, id, html };
|
||||
}
|
||||
}catch(_){}
|
||||
return { ok:false };
|
||||
}
|
||||
|
||||
function ensurePunct(str){
|
||||
const s = (str || '').trim();
|
||||
if (!s) return '';
|
||||
// If ends with punctuation, keep; else add period.
|
||||
return /[.!?…]$/.test(s) ? s : (s + '.');
|
||||
}
|
||||
|
||||
function extractSectionText(doc, label){
|
||||
// Look for a section with a label like "Illustration" / "Application"
|
||||
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){
|
||||
// usual structure: label inside a .section; body nearby
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fallback: first .lead-text / .section-body on page if label search failed
|
||||
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);
|
||||
}
|
||||
|
||||
(async function findAndRender(){
|
||||
// Try candidate, then probe up to +/- 10 around it
|
||||
const offsets = [0,1,-1,2,-2,3,-3,4,-4,5,-5,6,-6,7,-7,8,-8,9,-9,10,-10];
|
||||
for (const off of offsets){
|
||||
const id = Math.max(1, candidate + off);
|
||||
const res = await tryFetch(id);
|
||||
if (res.ok) { renderIotd(id, res.html); return; }
|
||||
}
|
||||
// Give up—show a graceful fallback
|
||||
iotdTextEl.textContent = 'Unable to load today’s illustration.';
|
||||
iotdOpenEl.style.display = 'none';
|
||||
})();
|
||||
})();
|
||||
|
||||
})();
|
||||
</script>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user