Persist search settings locally
Some checks failed
docker-build / build (push) Has been cancelled

This commit is contained in:
knight 2025-11-19 10:20:00 -05:00
parent c88d1886c9
commit 7f74aaced8

View File

@ -56,13 +56,28 @@
const graphModalClose = document.getElementById("graphModalClose");
const channelMap = new Map();
const transcriptCache = new Map();
const SETTINGS_KEY = "tlc-search-settings";
const DEFAULT_SETTINGS = {
channel: "",
year: "",
sort: "relevant",
size: "10",
exact: true,
fuzzy: true,
phrase: true,
external: false,
queryString: false,
};
let settings = loadSettings();
let lastFocusBeforeModal = null;
let pendingChannelSelection = "";
let channelsReady = false;
let previousToggleState = { exact: true, fuzzy: true, phrase: true };
let currentPage =
parseInt(qs.get("page") || "0", 10) ||
0;
let previousToggleState = {
exact: settings.exact,
fuzzy: settings.fuzzy,
phrase: settings.phrase,
};
let currentPage = 0;
function toggleAboutPanel(show) {
if (!aboutPanel) return;
@ -73,13 +88,6 @@
}
}
function parseBoolParam(name, defaultValue) {
const raw = qs.get(name);
if (raw === null) return defaultValue;
const lowered = raw.toLowerCase();
return !["0", "false", "no"].includes(lowered);
}
function parseChannelParam(params) {
if (!params) return "";
const seen = new Set();
@ -102,6 +110,69 @@
return first || "";
}
function loadSettings() {
try {
const raw = localStorage.getItem(SETTINGS_KEY);
if (!raw) return { ...DEFAULT_SETTINGS };
const parsed = JSON.parse(raw);
return { ...DEFAULT_SETTINGS, ...parsed };
} catch (err) {
console.warn("Failed to load settings", err);
return { ...DEFAULT_SETTINGS };
}
}
function persistSettings() {
try {
localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings));
} catch (err) {
console.warn("Failed to persist settings", err);
}
}
function applyStoredSettings() {
yearSel.value = settings.year || "";
sortSel.value = settings.sort || "relevant";
sizeSel.value = settings.size || "10";
exactToggle.checked = settings.exact;
fuzzyToggle.checked = settings.fuzzy;
phraseToggle.checked = settings.phrase;
if (externalToggle) {
externalToggle.checked = settings.external;
}
if (queryToggle) {
queryToggle.checked = settings.queryString;
}
}
function currentTogglePreferences() {
if (queryToggle && queryToggle.checked) {
return { ...previousToggleState };
}
return {
exact: !!exactToggle.checked,
fuzzy: !!fuzzyToggle.checked,
phrase: !!phraseToggle.checked,
};
}
function syncSettingsFromControls() {
const togglePrefs = currentTogglePreferences();
const next = {
...settings,
channel: channelSelect ? channelSelect.value || "" : "",
year: yearSel.value || "",
sort: sortSel.value || "relevant",
size: sizeSel.value || "10",
external: externalToggle ? !!externalToggle.checked : false,
queryString: queryToggle ? !!queryToggle.checked : false,
...togglePrefs,
};
settings = next;
persistSettings();
return settings;
}
function getSelectedChannels() {
if (!channelSelect) return [];
const value = channelSelect.value;
@ -130,20 +201,18 @@
function setFromQuery() {
qInput.value = qs.get("q") || "";
yearSel.value = qs.get("year") || "";
sortSel.value = qs.get("sort") || "relevant";
sizeSel.value = qs.get("size") || "10";
pendingChannelSelection = parseChannelParam(qs);
const urlChannel = parseChannelParam(qs);
if (urlChannel) {
pendingChannelSelection = urlChannel;
settings.channel = urlChannel;
persistSettings();
} else {
pendingChannelSelection = settings.channel || "";
}
applyStoredSettings();
if (channelSelect) {
channelSelect.value = pendingChannelSelection || "";
}
exactToggle.checked = parseBoolParam("exact", true);
fuzzyToggle.checked = parseBoolParam("fuzzy", true);
phraseToggle.checked = parseBoolParam("phrase", true);
if (externalToggle) {
externalToggle.checked = parseBoolParam("external", false);
}
queryToggle.checked = parseBoolParam("query_string", false);
applyQueryMode();
rememberToggleState();
}
@ -157,6 +226,8 @@
fuzzy: fuzzyToggle.checked,
phrase: phraseToggle.checked,
};
settings = { ...settings, ...previousToggleState };
persistSettings();
}
exactToggle.checked = false;
fuzzyToggle.checked = false;
@ -172,6 +243,8 @@
fuzzyToggle.checked = previousToggleState.fuzzy;
phraseToggle.checked = previousToggleState.phrase;
}
settings.queryString = !!(queryToggle && queryToggle.checked);
persistSettings();
}
function rememberToggleState() {
@ -181,6 +254,8 @@
fuzzy: !!fuzzyToggle.checked,
phrase: !!phraseToggle.checked,
};
settings = { ...settings, ...previousToggleState };
persistSettings();
}
}
@ -313,6 +388,8 @@
} else {
channelSelect.value = "";
}
settings.channel = channelSelect.value || "";
persistSettings();
channelsReady = true;
} catch (err) {
@ -322,25 +399,24 @@
}
}
function updateUrl(q, sort, channels, year, page, size, exact, fuzzy, phrase, queryMode, includeExternal) {
function updateUrl(q) {
const next = new URL(window.location.href);
next.searchParams.set("q", q);
next.searchParams.set("sort", sort);
if (q) {
next.searchParams.set("q", q);
} else {
next.searchParams.delete("q");
}
next.searchParams.delete("page");
next.searchParams.delete("sort");
next.searchParams.delete("channel_id");
next.searchParams.delete("channel");
channels.forEach((id) => next.searchParams.append("channel_id", id));
if (year) {
next.searchParams.set("year", year);
} else {
next.searchParams.delete("year");
}
next.searchParams.set("page", page);
next.searchParams.set("size", size);
next.searchParams.set("exact", exact ? "1" : "0");
next.searchParams.set("fuzzy", fuzzy ? "1" : "0");
next.searchParams.set("phrase", phrase ? "1" : "0");
next.searchParams.set("query_string", queryMode ? "1" : "0");
next.searchParams.set("external", includeExternal ? "1" : "0");
next.searchParams.delete("year");
next.searchParams.delete("size");
next.searchParams.delete("exact");
next.searchParams.delete("fuzzy");
next.searchParams.delete("phrase");
next.searchParams.delete("query_string");
next.searchParams.delete("external");
history.pushState({}, "", next.toString());
}
@ -1542,24 +1618,14 @@ async function updateFrequencyChart(term, channels, year, queryMode, toggles = {
fuzzy,
phrase,
};
settings = { ...settings, ...previousToggleState };
persistSettings();
}
const page = pageOverride != null ? pageOverride : currentPage;
currentPage = page;
if (pushState) {
updateUrl(
q,
sort,
channels,
year,
page,
size,
exact,
fuzzy,
phrase,
queryMode,
includeExternal
);
updateUrl(q);
}
const params = new URLSearchParams();
@ -1575,6 +1641,8 @@ async function updateFrequencyChart(term, channels, year, queryMode, toggles = {
channels.forEach((id) => params.append("channel_id", id));
if (year) params.set("year", year);
syncSettingsFromControls();
const res = await fetch(`/api/search?${params.toString()}`);
const payload = await res.json();
renderResults(payload, page);
@ -1598,31 +1666,39 @@ async function updateFrequencyChart(term, channels, year, queryMode, toggles = {
if (channelSelect) {
channelSelect.addEventListener("change", () => {
pendingChannelSelection = channelSelect.value || "";
settings.channel = pendingChannelSelection;
persistSettings();
if (channelsReady) {
runSearch(0);
}
});
}
yearSel.addEventListener("change", () => runSearch(0));
sortSel.addEventListener("change", () => runSearch(0));
sizeSel.addEventListener("change", () => runSearch(0));
exactToggle.addEventListener("change", () => { rememberToggleState(); runSearch(0); });
fuzzyToggle.addEventListener("change", () => { rememberToggleState(); runSearch(0); });
phraseToggle.addEventListener("change", () => { rememberToggleState(); runSearch(0); });
yearSel.addEventListener("change", () => { syncSettingsFromControls(); runSearch(0); });
sortSel.addEventListener("change", () => { syncSettingsFromControls(); runSearch(0); });
sizeSel.addEventListener("change", () => { syncSettingsFromControls(); runSearch(0); });
exactToggle.addEventListener("change", () => { rememberToggleState(); syncSettingsFromControls(); runSearch(0); });
fuzzyToggle.addEventListener("change", () => { rememberToggleState(); syncSettingsFromControls(); runSearch(0); });
phraseToggle.addEventListener("change", () => { rememberToggleState(); syncSettingsFromControls(); runSearch(0); });
if (externalToggle) {
externalToggle.addEventListener("change", () => {
pendingChannelSelection = "";
settings.external = !!externalToggle.checked;
persistSettings();
loadChannels().then(() => runSearch(0));
});
}
if (queryToggle) {
queryToggle.addEventListener("change", () => { applyQueryMode(); runSearch(0); });
queryToggle.addEventListener("change", () => {
applyQueryMode();
syncSettingsFromControls();
runSearch(0);
});
}
window.addEventListener("popstate", () => {
qs = new URLSearchParams(window.location.search);
setFromQuery();
currentPage = parseInt(qs.get("page") || "0", 10) || 0;
currentPage = 0;
runSearch(currentPage, false);
});