f7f79df1b3d0ebea41b0fa0436f0fe65160131ca
hiram
  Mon Aug 26 13:12:08 2024 -0700
now honoring the back button and restoring the state from the saved state object refs #32596

diff --git src/hg/js/assemblySearch.js src/hg/js/assemblySearch.js
index f31b48e..3e71f2b 100644
--- src/hg/js/assemblySearch.js
+++ src/hg/js/assemblySearch.js
@@ -1,27 +1,28 @@
 // global variables:
 
 var debug = false;
 var measureTiming = false;
 var urlParams;
 var query = "";
 var maxItemsOutput = 500;
 var asmIdText = null;
 // adjust default here and in assemblySearch.html
 var browserExist = "mayExist";
 var betterCommonName = null;
 var comment = null;
+var stateObject = {};	// maintain page state
 var requestSubmitButton = null;
 var completedAsmId = new Map();	// keep track of requests completed
 				// so they won't be repeated
 
 // This function is called on DOMContentLoaded as the initialization
 //  procedure for first time page draw
 document.addEventListener('DOMContentLoaded', function() {
     // allow semi colon separators as well as ampersand
     var urlArgList = window.location.search.replaceAll(";", "&");
     urlParams = new URLSearchParams(urlArgList);
     if (urlParams.has('measureTiming')) { // accepts no value or other string
        var measureValue = urlParams.get('measureTiming');
        if ("0" === measureValue | "off" === measureValue) {
          measureTiming = false;
        } else {			// any other string turns it on
@@ -55,30 +56,32 @@
        } else {			// any other string turns it on
          debug = true;
        }
     }
 
     // add extra element to the help text bullet list for API example
     if (debug) {
       var searchTipList = document.getElementById("searchTipList");
       // Create a new list item
       var li = document.createElement("li");
       li.innerHTML = "example API call: <span id=\"recentAjax\">n/a</span>";
       // Append the new list item to the ordered list
       searchTipList.appendChild(li);
     }
 
+    // default starts as hidden
+    stateObject.advancedSearchVisible = false;
     var searchForm = document.getElementById('searchForm');
     var advancedSearchButton = document.getElementById('advancedSearchButton');
     var searchInput = document.getElementById('searchBox');
     var clearButton = document.getElementById('clearSearch');
     asmIdText = document.getElementById("formAsmId");
     betterCommonName = document.getElementById("betterCommonName");
     comment = document.getElementById("comment");
     requestSubmitButton = document.getElementById("submitButton");
 
     document.getElementById("modalFeedback").addEventListener("submit", checkForm, false);
     modalInit();
 
     clearButton.addEventListener('click', function() {
         searchInput.value = ''; // Clear the search input field
     });
@@ -89,39 +92,72 @@
         var searchTerm = document.getElementById('searchBox').value;
         var resultCountLimit = document.getElementById('maxItemsOutput');
         var mustExist = document.getElementById('mustExist').checked;
         var notExist = document.getElementById('notExist').checked;
         browserExist = "mustExist";
         if (mustExist && notExist) {
            browserExist = "mayExist";
         } else if (notExist) {
            browserExist = "notExist";
         }
         var wordMatch = document.querySelector('input[name="wordMatch"]:checked').value;
         makeRequest(searchTerm, browserExist, resultCountLimit.value, wordMatch);
     });
 
     advancedSearchButton.addEventListener('click', function() {
-       var advancedSearchOptions = document.getElementById("advancedSearchOptions");
+       var searchOptions = document.getElementById("advancedSearchOptions");
        // I don't know why it is false the first time ?
-       if (! advancedSearchOptions.style.display ||
-             advancedSearchOptions.style.display === "none") {
-          advancedSearchOptions.style.display = "flex";
-          this.textContent = "hide advanced search options"; // Change button text
+       if (! searchOptions.style.display
+             || searchOptions.style.display === "none") {
+          advancedSearchVisible(true);
        } else {
-          advancedSearchOptions.style.display = "none";
-          this.textContent = "show advanced search options"; // Change button text
+          advancedSearchVisible(false);
+       }
+    });
+
+    // restore history on back button
+    window.addEventListener('popstate', function(e) {
+       const state = event.state;
+       if (state) {
+          stateObject.queryString = state.queryString;
+          stateObject.maxItemsOutput = state.maxItemsOutput;
+          stateObject.browser = state.browser;
+          stateObject.debug = state.debug;
+          stateObject.measureTiming = state.measureTiming;
+          stateObject.wordMatch = state.wordMatch;
+          stateObject.jsonData = state.jsonData;
+          document.getElementById('mustExist').checked = false;
+          document.getElementById('notExist').checked = false;
+          if (stateObject.browser === "mustExist") {
+             document.getElementById('mustExist').checked = true;
+          }
+          if (stateObject.browser === "notExist") {
+             document.getElementById('notExist').checked = true;
+          }
+          if (stateObject.browser === "mayExist") {
+             document.getElementById('mustExist').checked = true;
+             document.getElementById('notExist').checked = true;
+          }
+          advancedSearchVisible(stateObject.advancedSearchVisible);
+          if (stateObject.wordMatch === "allWords") {
+             document.getElementById("allWords").checked = true;
+          } else {
+             document.getElementById("anyWord").checked = true;
+          }
+          document.getElementById('searchBox').value = stateObject.queryString;
+	  populateTableAndInfo(JSON.parse(stateObject.jsonData));
+//          alert("state: '" + JSON.stringify(stateObject) + "'");
        }
     });
 
     var tableHeader = document.getElementById('tableHeader');
     headerRefresh(tableHeader);
 
     if (urlParams.has('maxItemsOutput')) {
        maxItemsOutput = parseInt(urlParams.get('maxItemsOutput'), 10);
        if (maxItemsOutput < 1) {
          maxItemsOutput = 1;
        } else if (maxItemsOutput > 1000) {
          maxItemsOutput = 1000;
        }
        document.getElementById('maxItemsOutput').value = maxItemsOutput;
     }
@@ -141,30 +177,45 @@
   tableHead.innerHTML = '';
   // re-populate header row - the sortable system added a class to
   //  the last sorted column, need to rebuild the headerRow to get the
   //  header back to pristine condition for the next sort
   var headerRow = '<tr>';
   headerRow += '<th><div class=tooltip>view/<br>request &#9432;<span onclick="event.stopPropagation()" class="tooltiptext"><em>"view"</em> opens the genome browser for an existing assembly, <em>"request"</em> opens an assembly request form.</span></div></th>';
   headerRow += '<th><div class="tooltip">English common name &#9432;<span onclick="event.stopPropagation()" class="tooltiptext">English common name</span></div></th>';
   headerRow += '<th><div class="tooltip">scientific name &#9432;<span onclick="event.stopPropagation()" class="tooltiptext">scientific name</span></div></th>';
   headerRow += '<th><div class="tooltip">NCBI Assembly &#9432;<span onclick="event.stopPropagation()" class="tooltiptext">Links to NCBI resource record<br>or UCSC downloads for local UCSC assemblies</span></div></th>';
   headerRow += '<th><div class="tooltip"><em>genark</em> clade &#9432;<span onclick="event.stopPropagation()" class="tooltiptextright">clade specification as found in the GenArk system.</span></div></th>';
   headerRow += '<th><div class="tooltip">description &#9432;<span onclick="event.stopPropagation()" class="tooltiptextright">other meta data for this assembly.</span></div></th>';
   headerRow += '</tr>';
   tableHead.innerHTML = headerRow;
 }
 
+// call with visible true to make visible, false to hide
+function advancedSearchVisible(visible) {
+  var advancedSearchButton = document.getElementById("advancedSearchButton");
+  var searchOptions = document.getElementById("advancedSearchOptions");
+  if (visible) {
+    searchOptions.style.display = "flex";
+    advancedSearchButton.textContent = "hide advanced search options";
+    stateObject.advancedSearchVisible = true;
+  } else {
+    searchOptions.style.display = "none";
+    advancedSearchButton.textContent = "show advanced search options";
+    stateObject.advancedSearchVisible = false;
+  }
+}
+
 // Function to generate the table and extra information
 function populateTableAndInfo(jsonData) {
     var tableHeader = document.getElementById('tableHeader');
     var tableBody = document.getElementById('tableBody');
     var metaData = document.getElementById('metaData');
     document.getElementById('resultCounts').innerHTML = "";
     document.getElementById('elapsedTime').innerHTML = "0";
 
     // Clear existing table content
     tableHeader.innerHTML = '';
     tableBody.innerHTML = '';
     metaData.innerHTML = '';
 
     // Extract the genomic entries and the extra info
     var genomicEntries = {};
@@ -480,45 +531,54 @@
     document.getElementById("loadingSpinner").style.display = "block";
 
     var xhr = new XMLHttpRequest();
     var urlPrefix = "/cgi-bin/hubApi";
     var url = "/findGenome?q=" + encodeURIComponent(queryString);
     url += ";browser=" + browserExist;
     url += ";maxItemsOutput=" + resultLimit;
 
     var historyUrl = "?q=" + encodeURIComponent(queryString) + ";browser=" + browserExist + ";maxItemsOutput=" + resultLimit;
     if (debug) {
        historyUrl += ";debug=1";
     }
     if (measureTiming) {
        historyUrl += ";measureTiming=1";
     }
-    history.pushState(null, '', historyUrl);
 
     if (debug) {
       var apiUrl = "<a href='" + urlPrefix + url + "' target=_blank>" + url + "</a>";
       document.getElementById("recentAjax").innerHTML = apiUrl;
     }
+    stateObject.queryString = queryString;
+    stateObject.maxItemsOutput = maxItemsOutput;
+    stateObject.browser = browserExist;
+    stateObject.debug = debug;
+    stateObject.measureTiming = measureTiming;
+    stateObject.wordMatch = wordMatch;
 
     xhr.open('GET', urlPrefix + url, true);
 
     xhr.onload = function() {
         if (xhr.status === 200) {
             // Hide the wait spinner once the AJAX request is complete
             document.querySelector(".submitContainer").classList.remove("loading");
             document.getElementById("loadingSpinner").style.display = "none";
             enableButtons();
+
+            stateObject.jsonData = xhr.responseText;
+            history.pushState(stateObject, '', historyUrl);
+
             var data = JSON.parse(xhr.responseText);
 	    populateTableAndInfo(data);
         } else {
             // Hide the wait spinner once the AJAX request is complete
             document.querySelector(".submitContainer").classList.remove("loading");
             document.getElementById("loadingSpinner").style.display = "none";
             enableButtons();
 	    var tableBody = document.getElementById('tableBody');
             var metaData = document.getElementById('metaData');
             tableBody.innerHTML = '';
             metaData.innerHTML = '';
             metaData.innerHTML = "<b>no results found for query: '" + queryString + "'</b>";
             document.getElementById('resultCounts').innerHTML = "";
             document.getElementById('elapsedTime').innerHTML = "0";
         }