c7221bad6eda31fe88c6f9880276d8f993ff876e chmalee Thu Mar 5 12:37:14 2026 -0800 Disable recent/popular species list selection in the hgConvert toDb dropdown if there are no chains available to them. Leave them in the list but unselectable, refs #36232 diff --git src/hg/js/utils.js src/hg/js/utils.js index 13d1a418f1a..1cd28c0b827 100644 --- src/hg/js/utils.js +++ src/hg/js/utils.js @@ -4813,31 +4813,31 @@ // Set db to the key (database name or accession) so the autocomplete // select handler can save it to recent genomes d.db = key; if (val.hubUrl !== null) { d.category = "UCSC GenArk - bulk annotated assemblies from NCBI GenBank / Refseq"; } else { d.category = "UCSC Genome Browser assemblies - annotation tracks curated by UCSC"; } data.push(d); } }); return data; } function initSpeciesAutoCompleteDropdown(inputId, selectFunction, baseUrl = null, - watermark = null, onServerReply = null, onError = null) { + watermark = null, onServerReply = null, onError = null, onFilterDropdown = null) { /* Generic function for turning an <input> element into a species search bar with an autocomplete * list separating results by category. * Required arguments: * inputId: id of the input element itself, not created here * selectFunction: the function to call when the user actually clicks on a result * Optional arguments: * baseUrl: where we send requests to which will return json we can parse into a list * of results, defaults to 'hubApi/findGenome?browser=mustExist&q=' * watermark: placeholder text in the input * onServerReply: function to run after querying baseUrl, by default use processFindGenome() * to standardize on hubApi, but can be something else * onError: function to call when the server returns an error (e.g. HTTP 400) * signature: onError(jqXHR, textStatus, errorThrown, searchTerm) => results array or null */ let defaultSearchUrl = "hubApi/findGenome?browser=mustExist&q="; @@ -4889,43 +4889,50 @@ return word.length > 0; // Filter out empty strings }); // Apply bolding for each word separately words.forEach(function(word) { // Escape special regex characters in each word var escapedWord = word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // Create case-insensitive regex to find all occurrences var regex = new RegExp('(' + escapedWord + ')', 'gi'); // Replace matches with bolded version (preserves original case) label = label.replace(regex, '<b>$1</b>'); }); } - return $("<li></li>") + let $li = $("<li></li>") .data("ui-autocomplete-item", item) .append($("<a></a>").html(label)) .appendTo(ul); + if (item.disabled) { + $li.attr('title', item.disabledReason || 'Not available'); + $li.css({'opacity': '0.5'}); + $li.find('a').css({'pointer-events': 'none'}); + } + return $li; } } ); autocompleteCat.init($("[id='"+inputId+"']"), { baseUrl: baseUrl !== null ? baseUrl : defaultSearchUrl, watermark: watermark, onSelect: selectFunction, onServerReply: onServerReply !== null ? onServerReply : processFindGenome, onError: onError, + onFilterDropdown: onFilterDropdown, showRecentGenomes: true, enterSelectsIdentical: false }); } function setupGenomeSearchBar(config) { /* Higher-level wrapper for setting up a genome search bar with standard boilerplate. * This handles the common pattern used across CGIs: error handling, DOMContentLoaded, * element binding, search button handler, item validation, and label update. * * config object properties: * inputId (required): ID of the search input element * labelElementId: ID of the element to update with selected genome label (default: 'genomeLabel') * onSelect: Callback function(item, labelElement) when genome is selected. * Called AFTER standard validation and label update.