7b8b81e0a4869b24cdd8d7d31eaad33aacb87c0a
hiram
Wed Aug 21 09:03:50 2024 -0700
will now perform the request email properly and the html page can take arguments refs #32596
diff --git src/hg/js/assemblySearch.js src/hg/js/assemblySearch.js
index f555584..461353b 100644
--- src/hg/js/assemblySearch.js
+++ src/hg/js/assemblySearch.js
@@ -1,179 +1,446 @@
+// global variables:
+
+var measureTiming = false;
+var urlParams;
+var searchFor = "";
+var maxItemsOutput = 500;
+var asmIdText = null;
+var betterCommonName = null;
+var comment = null;
+var requestSubmitButton = null;
+
+// 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 queryString = window.location.search.replaceAll(";", "&");
+ urlParams = new URLSearchParams(queryString);
+ 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
+ measureTiming = true;
+ }
+ }
+
var searchForm = document.getElementById('searchForm');
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
});
searchForm.addEventListener('submit', function(event) {
event.preventDefault(); // Prevent form submission
var searchTerm = document.getElementById('searchBox').value;
- var resultCountLimit = document.getElementById('limitResultCount');
+ var resultCountLimit = document.getElementById('maxItemsOutput');
var browserExist = "mustExist";
var mustExist = document.getElementById('mustExist').checked;
var notExist = document.getElementById('notExist').checked;
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);
});
+
+ 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('searchFor')) {
+ searchFor = urlParams.get('searchFor')
+ if (searchFor.length > 0) {
+ searchInput.value = searchFor;
+ 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
+ var headerRow = '
';
+ headerRow += '
view/ request ⓘ"view" opens the genome browser for an existing assembly, "request" opens an assembly request form.
';
+ headerRow += '
English common name ⓘEnglish common name
';
+ headerRow += '
scientific name (count) ⓘbinomial scientific name
';
+ headerRow += '
NCBI Assembly ⓘLinks to NCBI resource record.
';
+ headerRow += '
genark clade ⓘclade specification as found in the GenArk system.
';
+ headerRow += '
description ⓘother meta data for this assembly.
';
+ headerRow += '
';
+ tableHead.innerHTML = headerRow;
+}
+
// 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('searchString').innerHTML = "";
- document.getElementById('matchCounts').innerHTML = "0";
- document.getElementById('availableAssemblies').innerHTML = "0";
+ 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
const genomicEntries = {};
const extraInfo = {};
for (const key in jsonData) {
if (jsonData[key].scientificName) {
genomicEntries[key] = jsonData[key];
} else {
extraInfo[key] = jsonData[key];
}
}
- // 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 = '
';
- headerRow += '
view/ request
';
- headerRow += '
English common name
';
- headerRow += '
scientific name
';
- headerRow += '
assembly
';
- headerRow += '
clade
';
- headerRow += '
description
';
- headerRow += '
';
- tableHeader.innerHTML = headerRow;
+ headerRefresh(tableHeader);
var count = 0;
for (const id in genomicEntries) {
var dataRow = '
';
var browserUrl = id;
var ncbiUrl = id;
if (genomicEntries[id].browserExists) {
if (id.startsWith("GC")) {
browserUrl = "view";
ncbiUrl = "" + id + ""
} else {
browserUrl = "view";
}
dataRow += "
" + browserUrl + "
";
} else {
- dataRow += "
request
";
+ dataRow += "
";
}
dataRow += "
" + genomicEntries[id].scientificName + "
";
dataRow += "
" + genomicEntries[id].commonName + "
";
dataRow += "
" + ncbiUrl + "
";
dataRow += "
" + genomicEntries[id].clade + "
";
dataRow += "
" + genomicEntries[id].description + "
";
dataRow += '
';
tableBody.innerHTML += dataRow;
}
var dataTable = document.getElementById('dataTable');
sorttable.makeSortable(dataTable);
- document.getElementById('searchString').innerHTML = extraInfo['genomeSearch'];
- document.getElementById('matchCounts').innerHTML = extraInfo['totalMatchCount'].toLocaleString();
- document.getElementById('availableAssemblies').innerHTML = extraInfo['availableAssemblies'].toLocaleString();
+ var itemCount = parseInt(extraInfo['itemCount'], 10);
+ var totalMatchCount = parseInt(extraInfo['totalMatchCount'], 10);
+ var availableAssemblies = parseInt(extraInfo['availableAssemblies'], 10);
+
+ var resultCounts = "results for search string: '" + extraInfo['genomeSearch'] + "', ";
+ if ( itemCount === totalMatchCount ) {
+ resultCounts += "showing " + itemCount.toLocaleString() + "match results, ";
+ } else {
+ resultCounts += "showing " + itemCount.toLocaleString() + "match results ";
+ resultCounts += "from " + totalMatchCount.toLocaleString() + "total matches, ";
+ }
+ resultCounts += "out of " + availableAssemblies.toLocaleString() + "total number of assemblies";
+ document.getElementById('resultCounts').innerHTML = resultCounts;
+ if (measureTiming) {
var etMs = extraInfo['elapsedTimeMs'];
- var elapsedTime = etMs.toLocaleString() + " milliseconds";
+ var elapsedTime = "" + etMs.toLocaleString() + "milliseconds";
if ( etMs > 1000 ) {
var etSec = etMs/1000;
- elapsedTime = etSec.toFixed(2) + " seconds";
+ elapsedTime = "" + etSec.toFixed(2) + "seconds";
}
document.getElementById('elapsedTime').innerHTML = elapsedTime.toLocaleString();
+ document.getElementById("measureTiming").style.display = "inline";
+ } else {
+ document.getElementById("measureTiming").style.display = "none";
+ }
} // function populateTableAndInfo(jsonData)
function enableButtons() {
- document.getElementById('submitButton').disabled = false;
+ document.getElementById('submitSearch').disabled = false;
document.getElementById('clearSearch').disabled = false;
}
function disableButtons() {
- document.getElementById('submitButton').disabled = true;
+ document.getElementById('submitSearch').disabled = true;
document.getElementById('clearSearch').disabled = true;
}
+function parentTable(e) {
+ while (e) {
+ e = e.parentNode;
+ if (e.tagName.toLowerCase() === 'table') {
+ return e;
+ }
+ }
+ return undefined;
+}
+
+function whichRow(e) {
+ while (e) {
+ if (e.rowIndex) {
+ return e.rowIndex;
+ }
+ e = e.parentNode;
+ }
+ return undefined;
+}
+
+function closeModal(e)
+{
+ document.getElementById("modalWrapper").className = "";
+ if (e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
+}
+
+function clickHandler(e) {
+ if(!e.target) e.target = e.srcElement;
+ if(e.target.tagName === "DIV") {
+ if(e.target.id != "modalWindow") closeModal(e);
+ }
+}
+
+function keyHandler(e) {
+ if(e.keyCode === 27) closeModal(e);
+}
+
+function modalInit() {
+ if(document.addEventListener) {
+ document.getElementById("modalClose").addEventListener("click", closeModal, false);
+ document.addEventListener("click", clickHandler, false);
+ document.addEventListener("keydown", keyHandler, false);
+ } else {
+ document.getElementById("modalClose").attachEvent("onclick", closeModal);
+ document.attachEvent("onclick", clickHandler);
+ document.attachEvent("onkeydown", keyHandler);
+ }
+}
+
+function failedRequest(url) {
+ requestSubmitButton.value = "request failed";
+ requestSubmitButton.disabled = true;
+// garStatus.innerHTML = "FAILED: '" + url + "'";
+}
+
+function sendRequest(name, email, asmId, betterName, comment) {
+ var urlComponents = encodeURIComponent(name) + "&email=" + encodeURIComponent(email) + "&asmId=" + encodeURIComponent(asmId) + "&betterName=" + encodeURIComponent(betterName) + "&comment=" + encodeURIComponent(comment);
+
+ var url = "/cgi-bin/asr?name=" + urlComponents;
+alert("request url: '" + url + "'");
+// information about escaping characters:
+// https://stackoverflow.com/questions/10772066/escaping-special-character-in-a-url/10772079
+// encodeURI() will not encode: ~!@#$&*()=:/,;?+'
+// encodeURIComponent() will not encode: ~!*()'
+
+// var encoded = encodeURIComponent(url);
+// encoded = encoded.replace("'","’");
+// var encoded = encodeURI(cleaner);
+ var xmlhttp = new XMLHttpRequest();
+ xmlhttp.onreadystatechange = function() {
+ if (4 === this.readyState && 200 === this.status) {
+ requestSubmitButton.value = "request completed";
+ } else {
+ if (4 === this.readyState && 404 === this.status) {
+ failedRequest(url);
+ }
+ }
+ };
+ xmlhttp.open("GET", url, true);
+ xmlhttp.send();
+
+} // sendRequest: function(name, email. asmId)
+
+
+function checkForm(e) {
+alert("checkForm");
+ if (requestSubmitButton.value === "request completed") {
+ if (e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
+ closeModal(e);
+ return;
+ }
+ var form = (e.target) ? e.target : e.srcElement;
+ if(form.name.value === "") {
+ alert("Please enter your Name");
+ form.name.focus();
+ if (e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
+ return;
+ }
+ if(form.email.value === "") {
+ alert("Please enter a valid Email address");
+ form.email.focus();
+ if (e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
+ return;
+ }
+// validation regex from:
+// https://www.w3resource.com/javascript/form/email-validation.php
+// another example from
+// https://www.simplilearn.com/tutorials/javascript-tutorial/email-validation-in-javascript
+// var validRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
+// another example from
+// https://ui.dev/validate-email-address-javascript/
+// return /\S+@\S+\.\S+/.test(email)
+// return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
+// var re = /^[^\s@]+@[^\s@]+$/;
+// if (re.test(email)) { OK }
+
+// var validEmail = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
+ var validEmail = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
+ if(! validEmail.test(form.email.value)) {
+ alert("You have entered an invalid email address!");
+ form.email.focus();
+ if (e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
+ return;
+ }
+ sendRequest(form.name.value, form.email.value, asmIdText.textContent, betterCommonName.value, comment.value);
+ if (e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
+} // checkForm: function(e)
+
+function asmOpenModal(e) {
+ if (e.name) {
+ var modalWindow = document.getElementById("modalWindow");
+ var pTable = parentTable(e);
+ var thisRow = whichRow(e);
+ var colGroup = document.getElementById('colDefinitions');
+ var comName = "n/a";
+ var sciName = "n/a";
+ var descr = "n/a";
+ var i = 0;
+ for (i = 0; i < colGroup.children.length; i++) {
+ if (colGroup.children[i].id === "comName") {
+ comName = pTable.rows[thisRow].cells[i].innerText;
+ } else if (colGroup.children[i].id === "sciName") {
+ sciName = pTable.rows[thisRow].cells[i].innerText;
+ } else if (colGroup.children[i].id === "description") {
+ descr = pTable.rows[thisRow].cells[i].innerText;
+ }
+ }
+ document.getElementById("commonName").textContent = comName;
+ document.getElementById("formSciName").textContent = sciName;
+ document.getElementById("formAsmId").textContent = e.name;
+ document.getElementById("comment").textContent = descr;
+ requestSubmitButton.value = "Submit request";
+ document.getElementById("modalWrapper").className = "overlay";
+ requestSubmitButton.disabled = false;
+ var overflow = modalWindow.offsetHeight - document.documentElement.clientHeight;
+ if (overflow > 0) {
+ modalWindow.style.maxHeight = (parseInt(window.getComputedStyle(modalWindow).height) - overflow) + "px";
+ }
+ modalWindow.style.marginTop = (-modalWindow.offsetHeight)/2 + "px";
+ modalWindow.style.marginLeft = (-modalWindow.offsetWidth)/2 + "px";
+ }
+ if (e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
+}
+
function makeRequest(query, browserExist, resultLimit, wordMatch) {
// Disable the submit button
disableButtons();
var queryString = query;
// for allWords, place + sign in front of each word if not already there
if (wordMatch === "allWords") {
const words = query.split(/\s+/);
if (words.length > 1) { // not needed on only one word
var queryPlus = ""; // compose new query string
words.forEach(word => {
if (word.startsWith("+")) {
queryPlus += " " + word; // space separated each word
} else {
queryPlus += " +" + word;
}
});
queryString = queryPlus.trimStart(); // remove first space character
}
}
// Show the wait spinner
document.querySelector(".submitContainer").classList.add("loading");
document.getElementById("loadingSpinner").style.display = "block";
var xhr = new XMLHttpRequest();
- var url = "/cgi-bin/hubApi/findGenome?genomeSearch=" + encodeURIComponent(queryString);
+ var urlPrefix = "/cgi-bin/hubApi"
+ var url = "/findGenome?genomeSearch=" + encodeURIComponent(queryString);
url += ";browser=" + browserExist;
url += ";maxItemsOutput=" + resultLimit;
- xhr.open('GET', url, true);
+ var apiUrl = "" + url + "";
+ document.getElementById("recentAjax").innerHTML = apiUrl;
+
+ 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();
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 = "no results found for query: '" + queryString + "'";
- document.getElementById('searchString').innerHTML = queryString;
- document.getElementById('matchCounts').innerHTML = "0";
- document.getElementById('availableAssemblies').innerHTML = "0";
+ document.getElementById('resultCounts').innerHTML = "";
document.getElementById('elapsedTime').innerHTML = "0";
}
};
xhr.onerror = function() {
alert('console.log("Request failed")');
console.log('Request failed');
};
xhr.send();
}