595531f894a27e59e18b32436f6cb932fa4374a0 lrnassar Tue Sep 8 13:03:44 2026 -0700 BLAT form character counter: per-type limits passed through from the C constants. refs #38293 The counter showed the 75,000 DNA limit for every query type; protein and translated queries are capped at 10,000, so an oversized protein paste looked fine until the server rejected it. The per-sequence limits are now named constants in hgBlat.c, emitted into hgBlatFormData and read by the counter, which keys on the Query type dropdown and recounts when it changes - so the numbers cannot drift apart again. BLAT's guess counts against the DNA limit. diff --git src/hg/js/hgBlat.js src/hg/js/hgBlat.js index e636243b878..178b986220d 100644 --- src/hg/js/hgBlat.js +++ src/hg/js/hgBlat.js @@ -690,35 +690,42 @@ } function blatOpts(list, cur) { return list.map(function(v) { return ``; }).join(''); } function blatFormCount() { // Live character count under the textarea. Only these two nodes are touched on input - the // textarea itself is never re-rendered, so the caret stays where the user put it. var ta = document.getElementById('blatUserSeq'); var out = document.getElementById('blatCountText'); if (!ta || !out) { return; } var n = ta.value.replace(/[^A-Za-z*]/g, '').length; - // 75,000 is the DNA per-sequence limit (hgBlat.c maxSingleSize); protein and translated - // queries top out at 10,000, but the server rejects those with a warning that links to the - // full limits in the docs, so the counter shows only the common case. - out.textContent = blatFmt(n) + ' of 75,000 characters'; - out.classList.toggle('over', n > 75000); + // The per-sequence limit for the selected query type, passed through from the C constants in + // hgBlat.c so the two cannot drift apart (the page claimed a stale 25,000 for years). + // "BLAT's guess" counts against the DNA limit - the common case; a protein query that only + // the server recognizes as such is still rejected there with a warning linking the full + // limits in the docs. + var cfg = hgBlatFormData; + var typeSel = document.querySelector('#blatFormBox select[name=type]'); + var type = typeSel ? typeSel.value : ''; + var isTx = (type === 'protein' || type === 'translated RNA' || type === 'translated DNA'); + var max = isTx ? cfg.maxSingleTx : cfg.maxSingleDna; + out.textContent = blatFmt(n) + ' of ' + blatFmt(max) + ' characters'; + out.classList.toggle('over', n > max); } function blatFormTab(showUpload) { $('#blatTabPaste').toggleClass('on', !showUpload); $('#blatTabUpload').toggleClass('on', showUpload); $('#blatPanePaste').toggle(!showUpload); $('#blatPaneUpload').toggle(showUpload); } function blatFormBusyMarkup() { // Spinner overlay shown between Submit and the arrival of the results page. Built with the // form (hidden) rather than on demand, so nothing has to be parsed or fetched at the moment the // browser is already busy navigating away. return '
' + '
' + @@ -988,30 +995,32 @@ if (holder) { document.getElementById('blatGenomeSlot').appendChild(holder); } // Show the current assembly in the search bar itself instead of in a separate "Current genome:" // line - the bar is wide enough for the whole description. setupGenomeSearchBar writes the new // one in on each pick, and focusing the bar selects all of it, so it reads as a filled-in search // box rather than as a value the user has to clear by hand. var genomeInput = document.getElementById('genomeSearch'); if (genomeInput && cfg.dbLabel) { genomeInput.value = cfg.dbLabel; } // Restore the sequence from the cart without going through innerHTML (avoids re-escaping). document.getElementById('blatUserSeq').value = cfg.userSeq || ''; blatFormCount(); $('#blatUserSeq').on('input', blatFormCount); + // The limit shown depends on the query type, so recount when it changes. + $('#blatFormBox select[name=type]').on('change', blatFormCount); // Mirror the "Keep results" checkbox into its hidden field so an unticked box submits an // explicit 0 rather than nothing at all, and remember the choice in localStorage so it comes // back pre-set on the user's next visit (see keepResultsInit above). $('#blat_keepResults').on('change', function() { document.getElementById('blatKeepResultsVal').value = this.checked ? '1' : '0'; blatSetKeepResultsPref(this.checked); }); $('#blat_onlyLatest').on('change', function() { document.getElementById('blatOnlyLatestVal').value = this.checked ? '1' : '0'; blatSetOnlyLatestPref(this.checked); }); $('#blatTabPaste').on('click', function() { blatFormTab(false); }); $('#blatTabUpload').on('click', function() { blatFormTab(true); }); // The example sequence is a real 2.5 kb query, fetched on demand so it is not carried in every // page load. The button doubles as its own status indicator while the request is in flight,