160d10a30597d7435c30409878e2ba11c3e7c660 mspeir Wed Sep 9 14:19:40 2026 -0700 trackDb docs: stop the shared script from aborting on the pages without a search box, refs #38062 Two JavaScript faults on the trackDb doc pages, both of which trackDbHub.v3.html had already avoided while the other pages drifted. trackDbDoc.html, changes.html and trackDbHub.v0/v1/v2.html load /js/utils.js in their head, and the hgMenubar include further down brings in the same file by a different path, so it ran twice. utils.js declares mouseoverContainer with let at top level, so the second run threw a redeclaration error. v3 does not load utils.js in the head, and the menubar copy is in place well before anything needs it, so drop the head copy from the other five. documentLoad() then called addEventListener on the result of getElementById("tdbSearch") with no null check, and only v3 has that input, so the function threw partway through on the other four pages and never reached its end. The search box and jump-to-top button do not exist on those pages, so nothing visible was lost, but the exception aborted the rest of documentLoad and would have swallowed anything added after it. Guard the two listeners. All six pages now load with no console errors, checked in a browser. Co-Authored-By: Claude Opus 5 (1M context) diff --git src/hg/htdocs/goldenPath/help/trackDb/trackDbDoc.js src/hg/htdocs/goldenPath/help/trackDb/trackDbDoc.js index c98ccf5cf2b..266e58215a4 100644 --- src/hg/htdocs/goldenPath/help/trackDb/trackDbDoc.js +++ src/hg/htdocs/goldenPath/help/trackDb/trackDbDoc.js @@ -495,80 +495,85 @@ tdbDoc.toggleAll($('img.toggle.all')[0],true); document.addEventListener("keydown", e => { if (e.key === "F3") { e.preventDefault(); jumpToResult(e.shiftKey ? -1 : 1); } }); // add the tdb setting to the img toggle classList let toggles = document.querySelectorAll("IMG.toggle.detail"); toggles.forEach( (toggle) => { toggle.classList.add(toggle.parentNode.className + "_imgToggle"); }); + // Only the current hub spec page carries the search box; the other doc pages + // share this script and have no such input. let inp = document.getElementById("tdbSearch"); + if (inp) { inp.addEventListener("input", (e) => { let term = inp.value.trim(); if (term.length >= 2) { runSearch(term); } else if (term.length === 1) { // Show helpful message for single character runSearch(term); } else if (term.length === 0) { // Clear search when input is empty clearSearchHighlights(); hideSearchStatus(); currentResults = []; currentIndex = -1; } }); // Add keyboard shortcuts for search navigation inp.addEventListener("keydown", (e) => { if (e.key === "Enter") { e.preventDefault(); if (currentResults.length > 0) { jumpToResult(e.shiftKey ? -1 : 1); } } else if (e.key === "Escape") { e.preventDefault(); clearSearch(); } }); + } // Add clear search button functionality let clearButton = document.getElementById("clearSearch"); if (clearButton) { clearButton.addEventListener("click", () => { clearSearch(); }); } // Add jump to top functionality with smooth scrolling let jumpToTopButton = document.getElementById("jumpToTop"); if (jumpToTopButton) { jumpToTopButton.addEventListener("click", (e) => { e.preventDefault(); // Smooth scroll to top window.scrollTo({ top: 0, behavior: "smooth" }); // Also focus the search input for easy continued searching setTimeout(() => { + if (inp) inp.focus(); }, 500); }); } } } function searchHidden(term) { // Reset previous search clearSearchHighlights(); // track elements already processed to prevent repeated ing if (!window.__searchedElements) { window.__searchedElements = new WeakSet(); }