Zalgorithm

Approaches to saving search state

History state with a fallback query

const apiUrl =
  window.location.hostname === "localhost"
    ? "http://localhost:8000/query"
    : "https://api.zalgorithm.com/query";

function loadKaTexCSS() {
  if (document.getElementById("katex-css")) return;

  const link = document.createElement("link");
  link.id = "katex-css";
  link.rel = "stylesheet";
  link.href = "https://cdn.jsdelivr.net/npm/katex@0.16.25/dist/katex.min.css";
  link.integrity =
    "sha384-WcoG4HRXMzYzfCgiyfrySxx90XSl2rxY5mnVY5TwtWE6KLrArNKn0T/mOgNL0Mmi";
  link.crossOrigin = "anonymous";
  document.head.appendChild(link);
}

function loadSearchResults() {
  const urlParams = new URLSearchParams(window.location.search);
  const query = urlParams.get("q");

  if (query) {
    document.getElementById("semantic-search").value = query;

    // conditionally load katex-css
    // TODO: confirm this and conditional loading in fetch call below
    if (history.state && history.state.results) {
      if (history.state.results.includes('class="katex"')) {
        loadKaTexCSS();
      }
      document.getElementById("search-results").innerHTML =
        history.state.results;
    } else {
      const formData = new FormData();
      formData.append("query", query);

      fetch(apiUrl, {
        method: "POST",
        body: formData,
      })
        .then((response) => response.text())
        .then((html) => {
          if (html.includes('class="katex"')) {
            loadKaTexCSS();
          }
          document.getElementById("search-results").innerHTML = html;

          history.replaceState(
            { query: query, results: html },
            "",
            window.location.href,
          );
        });
    }
  }
}

document.addEventListener("DOMContentLoaded", loadSearchResults);
// handle back/forward navigation
window.addEventListener("popstate", loadSearchResults);

document.body.addEventListener("htmx:afterRequest", function (evt) {
  const form = evt.detail.elt;
  if (form.querySelector("#semantic-search")) {
    const query = form.querySelector("#semantic-search").value;
    if (query && evt.detail.successful) {
      const results = document.getElementById("search-results").innerHTML;
      history.pushState(
        { query: query, results: results },
        "",
        "?q=" + encodeURIComponent(query),
      );
    }
  }
});

Session Storage

document.body.addEventListener("htmx:afterRequest", function (evt) {
  const form = evt.detail.elt;
  if (form.querySelector("#semantic-search")) {
    const query = form.querySelector("#semantic-search").value;
    if (query && evt.detail.successful) {
      const results = document.getElementById("search-results").innerHTML;

      // Store in sessionStorage
      sessionStorage.setItem(`search_${query}`, results);

      // Only store query in history
      history.pushState(
        { query: query },
        "",
        "?q=" + encodeURIComponent(query),
      );
    }
  }
});

function loadSearchResults() {
  const urlParams = new URLSearchParams(window.location.search);
  const query = urlParams.get("q");

  if (query) {
    document.getElementById("semantic-search").value = query;

    // Try sessionStorage first
    const cached = sessionStorage.getItem(`search_${query}`);
    if (cached) {
      document.getElementById("search-results").innerHTML = cached;
      if (cached.includes('class="katex"')) loadKaTexCSS();
    } else {
      // Fetch fresh...
    }
  }
}