Update web/templates/entry_view.html
This commit is contained in:
parent
5245352584
commit
d08107e22a
@ -65,7 +65,7 @@
|
|||||||
<!-- Main card -->
|
<!-- Main card -->
|
||||||
<div class="result-card">
|
<div class="result-card">
|
||||||
<!-- SUBJECT pills (WOL-linked) -->
|
<!-- SUBJECT pills (WOL-linked) -->
|
||||||
<div class="subject-pills">
|
<div class="subject-pills" id="subject-list">
|
||||||
{% if subject_list %}
|
{% if subject_list %}
|
||||||
{% for s in subject_list %}
|
{% for s in subject_list %}
|
||||||
<a
|
<a
|
||||||
@ -100,11 +100,11 @@
|
|||||||
<div class="meta-grid">
|
<div class="meta-grid">
|
||||||
<div class="meta-item">
|
<div class="meta-item">
|
||||||
<div class="meta-label">Source</div>
|
<div class="meta-label">Source</div>
|
||||||
<div class="meta-value">
|
<div class="meta-value" id="source-text">
|
||||||
{% if entry.source %}
|
{% if entry.source %}
|
||||||
{% with s=entry.source %}
|
{% with s=entry.source %}
|
||||||
{% with sl=s|lower %}
|
{% with sl=s|lower %}
|
||||||
{% if sl|slice:":2" == "wp" or sl|slice:":2" == "ws" or sl|slice:":2" == "yb" or sl|slice:":2" == "km" or sl|slice:":3" == "mwb" or sl|slice:":1" == "w" or sl|slice:":1" == "g" or sl|slice:":2" == "ap" or sl|slice:":3" == "apf" or sl|slice:":2" == "be" or sl|slice:":2" == "bh" or sl|slice:":2" == "br" or sl|slice:":2" == "bt" or sl|slice:":3" == "btg" or sl|slice:":2" == "cf" or sl|slice:":2" == "cl" or sl|slice:":2" == "ct" or sl|slice:":2" == "dp" or sl|slice:":2" == "fg" or sl|slice:":2" == "fy" or sl|slice:":2" == "gt" or sl|slice:":2" == "hb" or sl|slice:":2" == "im" or sl|slice:":2" == "ip" or sl|slice:":2" == "it" or sl|slice:":2" == "jv" or sl|slice:":2" == "ka" or sl|slice:":2" == "kj" or sl|slice:":2" == "kl" or sl|slice:":2" == "lf" or sl|slice:":3" == "lff" or sl|slice:":2" == "ll" or sl|slice:":2" == "ly" or sl|slice:":2" == "my" or sl|slice:":2" == "od" or sl|slice:":2" == "pe" or sl|slice:":2" == "po" or sl|slice:":2" == "pt" or sl|slice:":2" == "rr" or sl|slice:":2" == "rs" or sl|slice:":2" == "sg" or sl|slice:":2" == "sh" or sl|slice:":2" == "si" or sl|slice:":2" == "td" or sl|slice:":2" == "tp" or sl|slice:":2" == "tr" or sl|slice:":2" == "ts" or sl|slice:":2" == "un" %}
|
{% if sl|slice:":2" == "wp" or sl|slice:":2" == "ws" or sl|slice:":2" == "yb" or sl|slice:":3" == "mwb" or sl|slice:":1" == "w" or sl|slice:":1" == "g" or sl|slice:":2" == "ap" or sl|slice:":3" == "apf" or sl|slice:":2" == "be" or sl|slice:":2" == "bh" or sl|slice:":2" == "br" or sl|slice:":2" == "bt" or sl|slice:":3" == "btg" or sl|slice:":2" == "cf" or sl|slice:":2" == "cl" or sl|slice:":2" == "ct" or sl|slice:":2" == "dp" or sl|slice:":2" == "fg" or sl|slice:":2" == "fy" or sl|slice:":2" == "gt" or sl|slice:":2" == "hb" or sl|slice:":2" == "im" or sl|slice:":2" == "ip" or sl|slice:":2" == "it" or sl|slice:":2" == "jv" or sl|slice:":2" == "ka" or sl|slice:":2" == "kj" or sl|slice:":2" == "kl" or sl|slice:":2" == "lf" or sl|slice:":3" == "lff" or sl|slice:":2" == "ll" or sl|slice:":2" == "ly" or sl|slice:":2" == "my" or sl|slice:":2" == "od" or sl|slice:":2" == "pe" or sl|slice:":2" == "po" or sl|slice:":2" == "pt" or sl|slice:":2" == "rr" or sl|slice:":2" == "rs" or sl|slice:":2" == "sg" or sl|slice:":2" == "sh" or sl|slice:":2" == "si" or sl|slice:":2" == "td" or sl|slice:":2" == "tp" or sl|slice:":2" == "tr" or sl|slice:":2" == "ts" or sl|slice:":2" == "un" %}
|
||||||
<a class="chip chip-link"
|
<a class="chip chip-link"
|
||||||
href="https://wol.jw.org/en/wol/l/r1/lp-e?q={{ s|urlencode }}"
|
href="https://wol.jw.org/en/wol/l/r1/lp-e?q={{ s|urlencode }}"
|
||||||
target="_blank" rel="noopener noreferrer">{{ s }}</a>
|
target="_blank" rel="noopener noreferrer">{{ s }}</a>
|
||||||
@ -121,7 +121,7 @@
|
|||||||
|
|
||||||
<div class="meta-item">
|
<div class="meta-item">
|
||||||
<div class="meta-label">Scripture</div>
|
<div class="meta-label">Scripture</div>
|
||||||
<div class="meta-value">
|
<div class="meta-value" id="scripture-text">
|
||||||
{% if scripture_list %}
|
{% if scripture_list %}
|
||||||
{% for sc in scripture_list %}
|
{% for sc in scripture_list %}
|
||||||
<a class="chip chip-link"
|
<a class="chip chip-link"
|
||||||
@ -139,7 +139,7 @@
|
|||||||
|
|
||||||
<div class="meta-item">
|
<div class="meta-item">
|
||||||
<div class="meta-label">Talk</div>
|
<div class="meta-label">Talk</div>
|
||||||
<div class="meta-value">
|
<div class="meta-value" id="talk_title-text">
|
||||||
{% if entry.talk_title %}{{ entry.talk_title }}{% else %}—{% endif %}
|
{% if entry.talk_title %}{{ entry.talk_title }}{% else %}—{% endif %}
|
||||||
{# Talk Number pill (staff-only link) #}
|
{# Talk Number pill (staff-only link) #}
|
||||||
{% if entry.talk_number %}
|
{% if entry.talk_number %}
|
||||||
@ -179,6 +179,14 @@
|
|||||||
The Illustration was copied to the clipboard
|
The Illustration was copied to the clipboard
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Last search data for highlighter -->
|
||||||
|
<script id="last-search-data" type="application/json">
|
||||||
|
{
|
||||||
|
"q": "{{ last_search_q|escapejs }}",
|
||||||
|
"fields": {{ last_search_fields|default:"[]"|safe }}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.subject-pills{
|
.subject-pills{
|
||||||
display:flex;
|
display:flex;
|
||||||
@ -201,6 +209,13 @@
|
|||||||
background:#e2effc;
|
background:#e2effc;
|
||||||
border-color:#c9def5;
|
border-color:#c9def5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Light gray highlight for search hits */
|
||||||
|
.mark-hit {
|
||||||
|
background: #ececec;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 0 .15em;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -445,4 +460,107 @@ function showToast(message, duration = 3000) {
|
|||||||
}, duration);
|
}, duration);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
|
||||||
|
<!-- Highlighter: only runs when user pref is enabled and when a last search exists -->
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", async () => {
|
||||||
|
let enabled = true;
|
||||||
|
try {
|
||||||
|
const res = await fetch("/api/get-prefs/");
|
||||||
|
const prefs = await res.json();
|
||||||
|
if (prefs && typeof prefs.highlight_search_hits !== "undefined") {
|
||||||
|
enabled = !!prefs.highlight_search_hits;
|
||||||
|
}
|
||||||
|
} catch (e) { /* default true */ }
|
||||||
|
if (!enabled) return;
|
||||||
|
|
||||||
|
const dataEl = document.getElementById("last-search-data");
|
||||||
|
if (!dataEl) return;
|
||||||
|
|
||||||
|
let payload = {};
|
||||||
|
try { payload = JSON.parse(dataEl.textContent || "{}"); } catch (_) { return; }
|
||||||
|
|
||||||
|
const q = (payload.q || "").trim();
|
||||||
|
const fields = Array.isArray(payload.fields) ? payload.fields : [];
|
||||||
|
if (!q || !fields.length) return;
|
||||||
|
|
||||||
|
// Map search field names -> selectors on this page
|
||||||
|
const fieldToSelector = {
|
||||||
|
subject: "#subject-list",
|
||||||
|
illustration: "#illustration-text",
|
||||||
|
application: "#application-text",
|
||||||
|
scripture_raw: "#scripture-text",
|
||||||
|
source: "#source-text",
|
||||||
|
talk_title: "#talk_title-text",
|
||||||
|
talk_number: "#talk_title-text"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Tokenize similar to your search: quoted phrases kept; remove wildcard chars
|
||||||
|
const tokens = tokenize(q).map(t => t.replaceAll("*","").replaceAll("?","")).filter(Boolean);
|
||||||
|
if (!tokens.length) return;
|
||||||
|
|
||||||
|
for (const f of fields) {
|
||||||
|
const sel = fieldToSelector[f];
|
||||||
|
if (!sel) continue;
|
||||||
|
const container = document.querySelector(sel);
|
||||||
|
if (!container) continue;
|
||||||
|
|
||||||
|
for (const tok of tokens) {
|
||||||
|
highlightAll(container, tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- helpers ---
|
||||||
|
function tokenize(s) {
|
||||||
|
const out = [];
|
||||||
|
let i = 0, buf = "", inQ = false;
|
||||||
|
while (i < s.length) {
|
||||||
|
const c = s[i++];
|
||||||
|
if (c === '"') {
|
||||||
|
if (inQ) { if (buf.trim()) out.push(buf); buf = ""; inQ = false; }
|
||||||
|
else { if (buf.trim()) out.push(buf); buf = ""; inQ = true; }
|
||||||
|
} else if (!inQ && /\s/.test(c)) {
|
||||||
|
if (buf.trim()) out.push(buf); buf = "";
|
||||||
|
} else {
|
||||||
|
buf += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buf.trim()) out.push(buf);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeRegExp(str) {
|
||||||
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||||
|
}
|
||||||
|
|
||||||
|
function highlightAll(root, needle) {
|
||||||
|
if (!needle) return;
|
||||||
|
const re = new RegExp(escapeRegExp(needle), "gi");
|
||||||
|
walkTextNodes(root, (textNode) => {
|
||||||
|
const text = textNode.nodeValue;
|
||||||
|
if (!re.test(text)) return;
|
||||||
|
const frag = document.createDocumentFragment();
|
||||||
|
let lastIndex = 0;
|
||||||
|
text.replace(re, (m, idx) => {
|
||||||
|
if (idx > lastIndex) frag.appendChild(document.createTextNode(text.slice(lastIndex, idx)));
|
||||||
|
const mark = document.createElement("mark");
|
||||||
|
mark.className = "mark-hit";
|
||||||
|
mark.textContent = m;
|
||||||
|
frag.appendChild(mark);
|
||||||
|
lastIndex = idx + m.length;
|
||||||
|
return m;
|
||||||
|
});
|
||||||
|
if (lastIndex < text.length) frag.appendChild(document.createTextNode(text.slice(lastIndex)));
|
||||||
|
textNode.parentNode.replaceChild(frag, textNode);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function walkTextNodes(node, cb) {
|
||||||
|
const walker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT, null, false);
|
||||||
|
const nodes = [];
|
||||||
|
while (walker.nextNode()) nodes.push(walker.currentNode);
|
||||||
|
nodes.forEach(cb);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user