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 ⓘ<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 ⓘ<span onclick="event.stopPropagation()" class="tooltiptext">English common name</span></div></th>'; headerRow += '<th><div class="tooltip">scientific name ⓘ<span onclick="event.stopPropagation()" class="tooltiptext">scientific name</span></div></th>'; headerRow += '<th><div class="tooltip">NCBI Assembly ⓘ<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 ⓘ<span onclick="event.stopPropagation()" class="tooltiptextright">clade specification as found in the GenArk system.</span></div></th>'; headerRow += '<th><div class="tooltip">description ⓘ<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"; }