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>
|
<li><strong>Wildcard search</strong> — use <code>*</code>.<br>
|
||||||
<em>Example:</em> <code>lov*</code></li>
|
<em>Example:</em> <code>lov*</code></li>
|
||||||
<li><strong>Scripture search</strong> — type a Bible book.<br>
|
<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>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -84,12 +84,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- ===== Illustration of the Day ===== -->
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<form method="get" class="search-form">
|
<form method="get" class="search-form">
|
||||||
<h1 class="page-title">Illustration of the Day</h1>
|
<h1 class="page-title">Illustration of the Day</h1>
|
||||||
<!-- insert illustration of the day here -->
|
<!-- insert illustration of the day here -->
|
||||||
</div>
|
<div id="iotd-card" class="card" style="padding:16px; margin:12px 0;">
|
||||||
</form>
|
<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>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -192,7 +202,7 @@
|
|||||||
}
|
}
|
||||||
refetchRecent();
|
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');
|
const searchForm = document.querySelector('form.search-form');
|
||||||
if (searchForm){
|
if (searchForm){
|
||||||
searchForm.addEventListener('submit', ()=>{
|
searchForm.addEventListener('submit', ()=>{
|
||||||
@ -200,7 +210,6 @@
|
|||||||
const fd = new FormData(searchForm);
|
const fd = new FormData(searchForm);
|
||||||
const data = new URLSearchParams();
|
const data = new URLSearchParams();
|
||||||
data.append('q', (fd.get('q') || '').trim());
|
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']
|
['subject','illustration','application','scripture_raw','source','talk_title','talk_number','entry_code']
|
||||||
.forEach(k=>{
|
.forEach(k=>{
|
||||||
if (fd.get(k)) data.append(`sel[${k}]`, 'on');
|
if (fd.get(k)) data.append(`sel[${k}]`, 'on');
|
||||||
@ -237,6 +246,109 @@
|
|||||||
if (!clickedInside) panel.classList.remove('open');
|
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>
|
</script>
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user