update lots of reader fixes
This commit is contained in:
+206
-21
@@ -85,6 +85,7 @@
|
||||
searchError: "",
|
||||
searchRequestId: 0,
|
||||
highlightedVerseId: "",
|
||||
highlightedVerseFresh: false,
|
||||
displayPreferencesBySource: {},
|
||||
showVerseHeads: readStoredBoolean(STORAGE_KEYS.showVerseHeads, true),
|
||||
showSourceOverview: readStoredBoolean(STORAGE_KEYS.showSourceOverview, true),
|
||||
@@ -125,6 +126,8 @@
|
||||
let showExtraCardEl;
|
||||
let readerFontSizeSelectEl;
|
||||
let exportButtonEl;
|
||||
let settingsBtnEl;
|
||||
let settingsPopoverEl;
|
||||
let lexiconPopupEl;
|
||||
let lexiconPopupTitleEl;
|
||||
let lexiconPopupSubtitleEl;
|
||||
@@ -132,6 +135,15 @@
|
||||
let lexiconPopupCloseEl;
|
||||
let lexiconReturnFocusEl = null;
|
||||
|
||||
let searchTimer = null;
|
||||
|
||||
function debounceRunSearch(scope) {
|
||||
clearTimeout(searchTimer);
|
||||
searchTimer = setTimeout(() => {
|
||||
void runSearch(scope);
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function normalizeId(value) {
|
||||
return String(value || "")
|
||||
.trim()
|
||||
@@ -155,6 +167,8 @@
|
||||
showExtraCardEl = document.getElementById("alpha-text-show-extra-card");
|
||||
readerFontSizeSelectEl = document.getElementById("alpha-text-font-size-select");
|
||||
exportButtonEl = document.querySelector("#alphabet-text-section .detail-export-btn");
|
||||
settingsBtnEl = document.getElementById("alpha-text-settings-btn");
|
||||
settingsPopoverEl = document.getElementById("alpha-text-settings-popover");
|
||||
translationSelectEl = document.getElementById("alpha-text-translation-select");
|
||||
translationControlEl = translationSelectEl?.closest?.(".alpha-text-control") || null;
|
||||
compareSelectEl = document.getElementById("alpha-text-compare-select");
|
||||
@@ -757,7 +771,9 @@
|
||||
input.value = "";
|
||||
}
|
||||
|
||||
state.searchQuery = "";
|
||||
const keepQuery = preserveHighlight && state.searchQuery ? state.searchQuery : "";
|
||||
|
||||
state.searchQuery = preserveHighlight ? keepQuery : "";
|
||||
state.searchResults = null;
|
||||
state.searchLoading = false;
|
||||
state.searchError = "";
|
||||
@@ -766,8 +782,6 @@
|
||||
if (!preserveHighlight) {
|
||||
state.highlightedVerseId = "";
|
||||
}
|
||||
|
||||
updateSearchControls();
|
||||
}
|
||||
|
||||
function getSourceDisplayCapabilities(source, passage) {
|
||||
@@ -1924,10 +1938,34 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
const card = createCard("Search Results");
|
||||
const payload = state.searchResults;
|
||||
const totalMatches = Number(payload?.totalMatches) || 0;
|
||||
const scopeLabel = state.activeSearchScope === "global"
|
||||
? "all texts"
|
||||
: (state.searchResults?.scope?.source?.title || getSelectedSource()?.title || "current source");
|
||||
: (payload?.scope?.source?.title || getSelectedSource()?.title || "current source");
|
||||
|
||||
const card = createCard("Search Results");
|
||||
|
||||
const diagnostic = document.createElement("div");
|
||||
diagnostic.className = "alpha-text-search-diagnostic";
|
||||
diagnostic.style.cssText = "padding:12px 16px;border:2px solid #ef4444;border-radius:8px;margin-bottom:12px;font-size:13px;line-height:1.6;color:#fca5a5;background:#1a0a0a";
|
||||
|
||||
const lines = [
|
||||
`<strong>Query:</strong> <em>"${state.searchQuery || "--"}"</em>`,
|
||||
`<strong>Scope:</strong> ${scopeLabel}`,
|
||||
state.searchLoading
|
||||
? `<strong>Status:</strong> Searching...`
|
||||
: state.searchError
|
||||
? `<strong>Status:</strong> <span style="color:#f87171">Error: ${state.searchError}</span>`
|
||||
: totalMatches > 0
|
||||
? `<strong>Status:</strong> Found <strong>${totalMatches}</strong> match${totalMatches !== 1 ? "es" : ""}${payload?.truncated ? ` (showing ${payload.resultCount})` : ""}`
|
||||
: `<strong>Status:</strong> No matches found`,
|
||||
payload ? `<strong>API Response:</strong> totalMatches=${totalMatches} resultCount=${payload.resultCount} truncated=${payload.truncated} results.length=${Array.isArray(payload.results) ? payload.results.length : "N/A"}` : "",
|
||||
``
|
||||
].filter(Boolean);
|
||||
|
||||
diagnostic.innerHTML = lines.join("<br>");
|
||||
card.appendChild(diagnostic);
|
||||
|
||||
const summary = document.createElement("p");
|
||||
summary.className = "alpha-text-search-summary";
|
||||
@@ -1957,12 +1995,19 @@
|
||||
return card;
|
||||
}
|
||||
|
||||
const payload = state.searchResults;
|
||||
const totalMatches = Number(payload?.totalMatches) || 0;
|
||||
const truncatedNote = payload?.truncated ? ` Showing the first ${payload.resultCount} results.` : "";
|
||||
summary.textContent = `${totalMatches} matches in ${scopeLabel}.${truncatedNote}`;
|
||||
summary.textContent = "";
|
||||
card.append(summary, actions);
|
||||
|
||||
if (state.searchLoading) {
|
||||
card.appendChild(createEmptyMessage("Searching..."));
|
||||
return card;
|
||||
}
|
||||
|
||||
if (state.searchError) {
|
||||
card.appendChild(createEmptyMessage(state.searchError));
|
||||
return card;
|
||||
}
|
||||
|
||||
if (!Array.isArray(payload?.results) || !payload.results.length) {
|
||||
card.appendChild(createEmptyMessage(`No matches found for \"${state.searchQuery}\".`));
|
||||
return card;
|
||||
@@ -2027,7 +2072,18 @@
|
||||
const globalSearchOnlyMode = isGlobalSearchOnlyMode();
|
||||
setGlobalSearchHeadingMode(globalSearchOnlyMode);
|
||||
|
||||
if (!source || !work || !section) {
|
||||
if (!detailBodyEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!globalSearchOnlyMode && (!source || !work || !section)) {
|
||||
if (state.searchQuery) {
|
||||
const fallbackCard = createCard("Search");
|
||||
fallbackCard.appendChild(createEmptyMessage(`Searching for "${state.searchQuery}"...`));
|
||||
detailBodyEl.replaceChildren();
|
||||
detailBodyEl.appendChild(fallbackCard);
|
||||
return;
|
||||
}
|
||||
renderPlaceholder("Text Reader", "Select a source to begin", "Choose a text source and section from the left panel.");
|
||||
renderLexiconPopup();
|
||||
return;
|
||||
@@ -2047,11 +2103,99 @@
|
||||
return;
|
||||
}
|
||||
|
||||
detailBodyEl.replaceChildren();
|
||||
if (globalSearchOnlyMode) {
|
||||
const existing = document.getElementById("alpha-text-search-overlay");
|
||||
if (existing) {
|
||||
existing.remove();
|
||||
}
|
||||
|
||||
if (!state.searchResults && !state.searchError && state.searchLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
const banner = document.createElement("div");
|
||||
banner.id = "alpha-text-search-overlay";
|
||||
banner.style.cssText = "position:fixed;inset:0;z-index:9999;background:#0c0c12;overflow:auto;padding:24px";
|
||||
const header = document.createElement("div");
|
||||
header.style.cssText = "margin-bottom:16px;display:flex;align-items:center;justify-content:space-between";
|
||||
const title = document.createElement("h2");
|
||||
title.style.cssText = "color:#e4e4e7;margin:0;font-size:20px";
|
||||
title.textContent = state.searchQuery ? `Search: "${state.searchQuery}"` : "Search Results";
|
||||
const closeBtn = document.createElement("button");
|
||||
closeBtn.type = "button";
|
||||
closeBtn.textContent = "✕ Close";
|
||||
closeBtn.style.cssText = "padding:8px 16px;border:1px solid #3f3f46;border-radius:6px;background:#18181b;color:#d4d4d8;cursor:pointer";
|
||||
closeBtn.addEventListener("click", () => {
|
||||
banner.remove();
|
||||
clearTimeout(searchTimer);
|
||||
clearSearchState();
|
||||
clearScopedSearch("global");
|
||||
clearScopedSearch("source");
|
||||
state.searchRequestId += 1;
|
||||
setGlobalSearchHeadingMode(false);
|
||||
void loadSelectedPassage();
|
||||
});
|
||||
header.append(title, closeBtn);
|
||||
|
||||
const content = document.createElement("div");
|
||||
if (state.searchLoading) {
|
||||
content.textContent = "Searching...";
|
||||
content.style.cssText = "color:#a1a1aa;padding:24px;text-align:center";
|
||||
} else if (state.searchError) {
|
||||
content.textContent = state.searchError;
|
||||
content.style.cssText = "color:#f87171;padding:24px";
|
||||
} else if (state.searchResults) {
|
||||
const p = state.searchResults;
|
||||
const summary = document.createElement("p");
|
||||
summary.style.cssText = "color:#a1a1aa;margin:0 0 16px";
|
||||
const matchCount = p.truncated ? p.resultCount : p.totalMatches;
|
||||
summary.textContent = `${matchCount}${p.truncated ? "+" : ""} match${matchCount !== 1 ? "es" : ""}`;
|
||||
content.appendChild(summary);
|
||||
if (Array.isArray(p.results)) {
|
||||
p.results.forEach((r) => {
|
||||
const btn = document.createElement("button");
|
||||
btn.type = "button";
|
||||
const isActive = normalizeId(r?.sourceId) === normalizeId(state.selectedSourceId)
|
||||
&& normalizeId(r?.workId) === normalizeId(state.selectedWorkId)
|
||||
&& normalizeId(r?.sectionId) === normalizeId(state.selectedSectionId)
|
||||
&& normalizeId(r?.verseId) === normalizeId(state.highlightedVerseId);
|
||||
btn.style.cssText = "display:block;width:100%;text-align:left;padding:10px 14px;margin-bottom:8px;border:2px solid "
|
||||
+ (isActive ? "#818cf8" : "#3f3f46")
|
||||
+ ";border-radius:8px;background:" + (isActive ? "rgba(99,102,241,0.15)" : "#18181b")
|
||||
+ ";color:#d4d4d8;cursor:pointer";
|
||||
|
||||
const refEl = document.createElement("strong");
|
||||
refEl.textContent = r.reference || "";
|
||||
btn.appendChild(refEl);
|
||||
btn.appendChild(document.createElement("br"));
|
||||
|
||||
const previewEl = document.createElement("small");
|
||||
appendHighlightedText(previewEl, (r.preview || "").slice(0, 200), state.searchQuery);
|
||||
btn.appendChild(previewEl);
|
||||
btn.addEventListener("click", () => {
|
||||
state.highlightedVerseFresh = true;
|
||||
banner.remove();
|
||||
void openSearchResult(r);
|
||||
});
|
||||
content.appendChild(btn);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
content.textContent = "No results.";
|
||||
content.style.cssText = "color:#a1a1aa;padding:24px";
|
||||
}
|
||||
|
||||
banner.append(header, content);
|
||||
document.body.appendChild(banner);
|
||||
return;
|
||||
}
|
||||
|
||||
const searchCard = createSearchCard();
|
||||
if (searchCard) {
|
||||
|
||||
if (searchCard && (globalSearchOnlyMode || state.searchLoading)) {
|
||||
detailBodyEl.replaceChildren();
|
||||
detailBodyEl.appendChild(searchCard);
|
||||
return;
|
||||
}
|
||||
|
||||
if (globalSearchOnlyMode) {
|
||||
@@ -2059,6 +2203,8 @@
|
||||
return;
|
||||
}
|
||||
|
||||
detailBodyEl.replaceChildren();
|
||||
|
||||
if (!state.currentPassage) {
|
||||
const loadingCard = createCard("Text Reader");
|
||||
loadingCard.appendChild(createEmptyMessage("Loading section…"));
|
||||
@@ -2160,7 +2306,19 @@
|
||||
|
||||
renderDetail();
|
||||
if (state.highlightedVerseId) {
|
||||
requestAnimationFrame(scrollHighlightedVerseIntoView);
|
||||
requestAnimationFrame(() => {
|
||||
scrollHighlightedVerseIntoView();
|
||||
if (state.highlightedVerseFresh) {
|
||||
const verseEl = detailBodyEl?.querySelector?.(".alpha-text-verse.is-highlighted");
|
||||
if (verseEl instanceof HTMLElement) {
|
||||
verseEl.classList.add("is-highlighted-fresh");
|
||||
setTimeout(() => {
|
||||
verseEl.classList.remove("is-highlighted-fresh");
|
||||
}, 2600);
|
||||
}
|
||||
state.highlightedVerseFresh = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2185,15 +2343,13 @@
|
||||
updateSearchControls();
|
||||
|
||||
if (!query) {
|
||||
clearSearchState();
|
||||
state.searchLoading = false;
|
||||
state.searchError = `Search query is empty (scope: ${normalizedScope}, input: ${getSearchInput(normalizedScope) ? "found" : "missing"}, stored: "${getStoredSearchQuery(normalizedScope) || "none"}")`;
|
||||
state.searchResults = null;
|
||||
renderDetail();
|
||||
return;
|
||||
}
|
||||
|
||||
if (normalizedScope === "global" || normalizedScope === "source") {
|
||||
showDetailOnlyMode();
|
||||
}
|
||||
|
||||
const requestId = state.searchRequestId + 1;
|
||||
state.searchRequestId = requestId;
|
||||
state.searchLoading = true;
|
||||
@@ -2242,7 +2398,7 @@
|
||||
showDetailOnlyMode();
|
||||
await loadSelectedPassage();
|
||||
clearActiveSearchUi({ preserveHighlight: true });
|
||||
renderDetail();
|
||||
updateSearchControls();
|
||||
}
|
||||
|
||||
function bindControls() {
|
||||
@@ -2253,7 +2409,7 @@
|
||||
if (globalSearchFormEl instanceof HTMLFormElement) {
|
||||
globalSearchFormEl.addEventListener("submit", (event) => {
|
||||
event.preventDefault();
|
||||
void runSearch("global");
|
||||
debounceRunSearch("global");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2278,7 +2434,7 @@
|
||||
if (localSearchFormEl instanceof HTMLFormElement) {
|
||||
localSearchFormEl.addEventListener("submit", (event) => {
|
||||
event.preventDefault();
|
||||
void runSearch("source");
|
||||
void debounceRunSearch("source");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2441,6 +2597,35 @@
|
||||
});
|
||||
}
|
||||
|
||||
if (settingsBtnEl instanceof HTMLButtonElement && settingsPopoverEl instanceof HTMLElement) {
|
||||
settingsBtnEl.addEventListener("click", () => {
|
||||
const isOpen = settingsPopoverEl.hidden === false;
|
||||
settingsPopoverEl.hidden = isOpen;
|
||||
settingsBtnEl.setAttribute("aria-expanded", isOpen ? "false" : "true");
|
||||
});
|
||||
|
||||
const closeBtn = settingsPopoverEl.querySelector(".alpha-text-settings-close");
|
||||
if (closeBtn instanceof HTMLButtonElement) {
|
||||
closeBtn.addEventListener("click", () => {
|
||||
settingsPopoverEl.hidden = true;
|
||||
settingsBtnEl.setAttribute("aria-expanded", "false");
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("click", (event) => {
|
||||
if (settingsPopoverEl.hidden) {
|
||||
return;
|
||||
}
|
||||
const target = event.target;
|
||||
if (target instanceof Node) {
|
||||
if (!settingsPopoverEl.contains(target) && target !== settingsBtnEl) {
|
||||
settingsPopoverEl.hidden = true;
|
||||
settingsBtnEl.setAttribute("aria-expanded", "false");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
state.initialized = true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user