c9e09744ad3e9050ff9ab8395de4a2fc1196b016
hiram
  Sun Sep 8 10:51:52 2024 -0700
correctly trim white space from before and after the query string and correctly test for words beginning with + or - refs #32596

diff --git src/hg/js/assemblySearch.js src/hg/js/assemblySearch.js
index 39c4bcb..bd01a27 100644
--- src/hg/js/assemblySearch.js
+++ src/hg/js/assemblySearch.js
@@ -123,31 +123,32 @@
     comment = document.getElementById("comment");
     requestSubmitButton = document.getElementById("submitButton");
 
     document.getElementById("modalFeedback").addEventListener("submit", checkForm, false);
     modalInit();
     var tableBody = document.getElementById('tableBody');
     tableBody.innerHTML = '<tr><td style="text-align:center;" colspan=8><b>(empty table)</b></td></tr>';
 
     clearButton.addEventListener('click', function() {
         searchInput.value = ''; // Clear the search input field
     });
 
     searchForm.addEventListener('submit', function(event) {
         event.preventDefault(); // Prevent form submission
 
-        var searchTerm = document.getElementById('searchBox').value;
+        // the trim() removes stray white space before or after the string
+        var searchTerm = document.getElementById('searchBox').value.trim();
         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";
         }
         makeRequest(searchTerm, browserExist, resultCountLimit.value);
     });
 
     advancedSearchButton.addEventListener('click', function() {
        document.getElementById('urlCopyLink').style.display = "none";
        let searchOptions = document.getElementById("advancedSearchOptions");
@@ -229,31 +230,31 @@
     });
 
     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;
     }
     if (urlParams.has('q')) {
-       query = urlParams.get('q');
+       query = urlParams.get('q').trim();
        if (query.length > 0) {
           searchInput.value = query;
           document.getElementById('submitSearch').click();
        }
     }
     document.getElementById("measureTiming").style.display = "none";
 });
 
 // refresh the thead columns in the specified table
 function headerRefresh(tableHead) {
   // clear existing content
   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
@@ -314,31 +315,31 @@
            prefix.push(noPrefix.replace(/\*$/, ''));
          }
        } else {
          wholeWord.push(noPrefix);
        }
     }
     if (wholeWord.length > 0) {
       for (let word of wholeWord) {
         for (let key in rowData) {
            if (rowData.hasOwnProperty(key)) {
               if (typeof rowData[key] === 'string') {
                  let value = rowData[key];
                  let subWords = value.match(/(\w+)|(\W+)/g);
                  let newString = "";
                  let wholeSubs = word.match(/(\w+)/g);
-                 if (wholeSubs.length > 0) {
+                 if (wholeSubs && wholeSubs.length > 0) {
                    for (let whole of wholeSubs) {
                      for (let subWord of subWords) {
                        if ( whole.toLowerCase() === subWord.toLowerCase() ) {
                           newString += "<span class='highlight'>" + subWord + "</span>";
                        } else {
                           newString += subWord;
                        }
                      }
                      newString = newString.trim();
                      if (newString !== rowData[key])
                         rowData[key] = newString;
                    }	//	for (let whole of wholeSubs)
                  }	//	if (wholeSubs.length > 0)
               }	//	if (typeof rowData[key] === 'string')
            }	//	if (rowData.hasOwnProperty(key))
@@ -387,31 +388,31 @@
     var genomicEntries = {};
     var extraInfo = {};
 
     for (var key in jsonData) {
         if (jsonData[key].scientificName) {
             genomicEntries[key] = jsonData[key];
         } else {
             extraInfo[key] = jsonData[key];
         }
     }
 
     headerRefresh(tableHeader);
 
     var count = 0;
     for (var id in genomicEntries) {
-        highlightMatch(extraInfo.q, genomicEntries[id]);
+        highlightMatch(extraInfo.q.trim(), genomicEntries[id]);
         var dataRow = '<tr>';
         var browserUrl = id;
         var asmInfoUrl = id;
         if (genomicEntries[id].browserExists) {
           if (id.startsWith("GC")) {
             browserUrl = "<a href='/h/" + id + "?position=lastDbPos' target=_blank>View</a>";
             asmInfoUrl = "<a href='https://www.ncbi.nlm.nih.gov/assembly/" + id + "' target=_blank>" + id + "</a>";
           } else {
             browserUrl = "<a href='/cgi-bin/hgTracks?db=" + id + "' target=_blank>View</a>";
             asmInfoUrl = "<a href='https://hgdownload.soe.ucsc.edu/goldenPath/" + id + "/bigZips/' target=_blank>" + id + "</a>";
           }
           dataRow += "<th>" + browserUrl + "</th>";
         } else {
           dataRow += "<th><button type=button' onclick='asmOpenModal(this)' name=" + id + "'>Request</button></th>";
         }
@@ -436,31 +437,31 @@
            hardSpace = "";
         }
         status += "</td>";
 //        status += hardSpace + "</td>";
         dataRow += status;
         dataRow += '</tr>';
         tableBody.innerHTML += dataRow;
     }
     var dataTable = document.getElementById('dataTable');
     sorttable.makeSortable(dataTable);
 
     var itemCount = parseInt(extraInfo.itemCount, 10);
     var totalMatchCount = parseInt(extraInfo.totalMatchCount, 10);
     var availableAssemblies = parseInt(extraInfo.availableAssemblies, 10);
 
-    var resultCounts = "<em>results for search string: </em><b>'" + extraInfo.q + "'</b>, ";
+    var resultCounts = "<em>results for search string: </em><b>'" + extraInfo.q.trim() + "'</b>, ";
     if ( itemCount === totalMatchCount ) {
       resultCounts += "<em>showing </em><b>" + itemCount.toLocaleString() + "</b> <em>match results</em>, ";
     } else {
       resultCounts += "<em>showing </em><b>" + itemCount.toLocaleString() + "</b> <em>match results</em> ";
       resultCounts += "<em>from </em><b>" + totalMatchCount.toLocaleString() + "</b> <em>total matches,</em> ";
     }
     resultCounts += "<em>out of </em><b>" + availableAssemblies.toLocaleString() + "</b> <em>total number of assemblies</em>";
     document.getElementById('resultCounts').innerHTML = resultCounts;
     if (measureTiming) {
       var etMs = extraInfo.elapsedTimeMs;
       var elapsedTime = "<b>" + etMs.toLocaleString() + "</b> <em>milliseconds</em>";
       if ( etMs > 1000 ) {
          var etSec = etMs/1000;
          elapsedTime = "<b>" + etSec.toFixed(2) + "</b> <em>seconds</em>";
       }
@@ -740,40 +741,40 @@
     var asmStatus = document.querySelector('input[name="asmStatus"]:checked').value;
     var refSeqCategory = document.querySelector('input[name="refSeqCategory"]:checked').value;
     var asmLevel = document.querySelector('input[name="asmLevel"]:checked').value;
 
     // start with what the user requested:
     var queryString = query;
 
     // for allWords, place + sign in front of each word if not already there
     if (wordMatch === "allWords") {
       var words = queryString.split(/\s+/);
       if (words.length > 1) {	// not needed on only one word
         var queryPlus = "";	// compose new query string
         let inQuote = false;
         words.forEach(function(word) {
           if (word.match(/^[-+]?"/)) {
-             if (word.match(/^[-+]/))
+             if (/^[-+]/.test(word))
                 queryPlus += " " + word; // do not add + to - or + already there
              else
                 queryPlus += " +" + word;
              inQuote = true;
           } else if (inQuote) {
              queryPlus += " " + word; // space separates each word
              if (word.endsWith('"'))
                 inQuote = false;
-          } else if (word.match(/[^-+]/)) {
+          } else if (/^[-+]/.test(word)) {
             queryPlus += " " + word; // do not add + to - or + already there
           } else {
             queryPlus += " +" + word;
           }
         });
         queryString = queryPlus.trim();
       }
     }
     // remove stray white space from beginning or end
     queryString = queryString.trim();
 
     // Show the wait spinner
     document.querySelector(".submitContainer").classList.add("loading");
     document.getElementById("loadingSpinner").style.display = "block";