48d45fa3cbdddcb62775f1fe01eef865407e035e braney Wed Jun 24 13:47:07 2026 -0700 Revert "Add a right click option to change color or background highlight color of individual track items. Only works for bed like items, refs #37778" This reverts commit abd7278ac7167ede325d8c144a35ea59a0798766. diff --git src/hg/js/hgTracks.js src/hg/js/hgTracks.js index 7a52b221a80..e88593ba63d 100644 --- src/hg/js/hgTracks.js +++ src/hg/js/hgTracks.js @@ -3585,44 +3585,30 @@ }); } else if (cmd === 'hgTrackUi_popup') { // Launches the popup but shields the ajax with a waitOnFunction popUp.hgTrackUi( rightClick.selectedMenuItem.id, false ); } else if (cmd === 'hgTrackUi_popup_description') { // Launches the popup but shields the ajax with a waitOnFunction popUp.hgTrackUi( rightClick.selectedMenuItem.id, true ); } else if (cmd === 'changeTrackColor') { rightClick.showColorPicker(id); - } else if (cmd === 'colorThisItem') { - - rightClick.colorThisItem(); - - } else if (cmd === 'removeItemColor') { - - var itemToRemove = rightClick.itemFromHref(rightClick.selectedMenuItem.href); - if (itemToRemove) - rightClick.removeItemColor(itemToRemove.track, itemToRemove.name); - - } else if (cmd === 'clearItemColors') { - - rightClick.clearItemColors(); - } else if (cmd === 'hgTrackUi_follow') { url = "hgTrackUi?hgsid=" + getHgsid() + "&g="; rec = hgTracks.trackDb[id]; if (tdbHasParent(rec) && tdbIsLeaf(rec)) url += rec.parentTrack; else { // The button already has the ref var link = normed($( 'td#td_btn_'+ rightClick.selectedMenuItem.id ).children('a')); if (link) url = $(link).attr('href'); else url += rightClick.selectedMenuItem.id; } location.assign(url); @@ -3944,272 +3930,30 @@ minWidth: 400, buttons: { "Apply": function() { applyColor(); }, "Ok": function() { if (applyColor()) $(this).dialog("close"); } }, close: function() { $("#trackColorPicker").spectrum("destroy"); $(this).remove(); } }); }, - // ---- Per-item color (right-click "Color this item") ---- - // The itemColors cart variable holds db#track#mode#itemName#hexColor records joined by '|', - // where mode is "item" (recolor the glyph) or "bg" (background highlight). db, track and mode - // are the leading fields and the color is the last '#' field, so item names containing '#' - // are tolerated. - - getItemColors: function () - { // Current itemColors cart string, cached and seeded from the page's hgTracks json. - if (rightClick.itemColorsCache === undefined) { - rightClick.itemColorsCache = - (typeof hgTracks !== "undefined" && typeof hgTracks.itemColors === "string") ? - hgTracks.itemColors : ""; - } - return rightClick.itemColorsCache; - }, - - parseItemColors: function (str) - { // Parse the itemColors string into an array of {db, track, mode, name, hex} records. - var records = []; - if (!str) - return records; - str.split("|").forEach(function (rec) { - if (!rec) - return; - var firstHash = rec.indexOf("#"); - var secondHash = rec.indexOf("#", firstHash + 1); - var thirdHash = rec.indexOf("#", secondHash + 1); - var lastHash = rec.lastIndexOf("#"); - if (firstHash < 0 || secondHash < 0 || thirdHash < 0 || lastHash <= thirdHash) - return; - records.push({ - db: rec.substring(0, firstHash), - track: rec.substring(firstHash + 1, secondHash), - mode: rec.substring(secondHash + 1, thirdHash), - name: rec.substring(thirdHash + 1, lastHash), - hex: rec.substring(lastHash + 1) // bare hex, no leading '#' - }); - }); - return records; - }, - - serializeItemColors: function (records) - { - return records.map(function (r) { - return r.db + "#" + r.track + "#" + r.mode + "#" + r.name + "#" + r.hex; - }).join("|"); - }, - - itemFromHref: function (href) - { // Identify the clicked item from its hgc/hgGene link. Use the real name when it has a usable - // one (name field of the returned object), otherwise fall back to genomic position - // ("pos:chrom:start-end"). Nameless items (e.g. bed3) all share a placeholder name, so - // position - which both the link (c=/o=/t=) and the draw code can produce - identifies them. - if (!href) - return null; - var track, name, m; - m = /[&?]g=([^&]+)/.exec(href); - if (m && m[1]) - track = decodeURIComponent(m[1]); - m = /[&?]i=([^&]+)/.exec(href); - if (m && m[1]) - name = decodeURIComponent(m[1].replace(/\+/g, " ")); - if (!name) { // knownGene-style links - m = /[&?]hgg_gene=([^&]+)/.exec(href); - if (m && m[1]) - name = decodeURIComponent(m[1]); - if (!track) { - m = /[&?]hgg_type=([^&]+)/.exec(href); - if (m && m[1]) - track = decodeURIComponent(m[1]); - } - } - if (!track) - return null; - // Custom tracks prefix the bed file path before the item name ("<path> <name>") and use the - // literal "NoItemName" when the row has no name; treat empty or "NoItemName" as nameless. - var nameless = !name || /(^|\s)NoItemName$/.test(name); - if (!nameless) - return {track: track, name: name}; - // o=/t= are 0-based start/end, matching tg->itemStart/itemEnd in the draw code - var chrom, start, end; - m = /[&?]c=([^&]+)/.exec(href); - if (m && m[1]) chrom = decodeURIComponent(m[1]); - m = /[&?]o=([^&]+)/.exec(href); - if (m && m[1]) start = m[1]; - m = /[&?]t=([^&]+)/.exec(href); - if (m && m[1]) end = m[1]; - if (chrom && start && end) - return {track: track, name: "pos:" + chrom + ":" + start + "-" + end}; - return null; - }, - - findItemColor: function (track, name) - { // Return {hex (with leading '#'), mode} stored for this item, or null. - var db = getDb(); - var records = rightClick.parseItemColors(rightClick.getItemColors()); - for (var i = 0; i < records.length; i++) { - if (records[i].db === db && records[i].track === track && records[i].name === name) - return {hex: "#" + records[i].hex, mode: records[i].mode}; - } - return null; - }, - - updateItemColorsVar: function (newStr) - { // Persist the itemColors cart variable and keep the local cache in sync. - rightClick.itemColorsCache = newStr; - if (typeof hgTracks !== "undefined" && hgTracks) - hgTracks.itemColors = newStr; - cart.setVars(["itemColors"], [newStr], null, false); - }, - - setItemColor: function (track, name, hexWithHash, mode) - { - var db = getDb(); - var hex = hexWithHash.replace(/^#/, ""); - var records = rightClick.parseItemColors(rightClick.getItemColors()); - var found = false; - for (var i = 0; i < records.length; i++) { - if (records[i].db === db && records[i].track === track && records[i].name === name) { - records[i].hex = hex; - records[i].mode = mode; - found = true; - break; - } - } - if (!found) - records.push({db: db, track: track, mode: mode, name: name, hex: hex}); - rightClick.updateItemColorsVar(rightClick.serializeItemColors(records)); - imageV2.requestImgUpdate(track, - "itemColors=" + encodeURIComponent(rightClick.getItemColors())); - }, - - removeItemColor: function (track, name) - { - var db = getDb(); - var records = rightClick.parseItemColors(rightClick.getItemColors()).filter(function (r) { - return !(r.db === db && r.track === track && r.name === name); - }); - rightClick.updateItemColorsVar(rightClick.serializeItemColors(records)); - imageV2.requestImgUpdate(track, - "itemColors=" + encodeURIComponent(rightClick.getItemColors())); - }, - - hasItemColorsForCurrentDb: function () - { // Are any item colors set for the database currently shown? - var db = getDb(); - return rightClick.parseItemColors(rightClick.getItemColors()).some(function (r) { - return r.db === db; - }); - }, - - clearItemColors: function () - { // Clear item colors for the current database only, leaving other assemblies' colors alone. - var db = getDb(); - var records = rightClick.parseItemColors(rightClick.getItemColors()).filter(function (r) { - return r.db !== db; - }); - var newStr = rightClick.serializeItemColors(records); - rightClick.updateItemColorsVar(newStr); - imageV2.fullReload("itemColors=" + encodeURIComponent(newStr)); - }, - - colorThisItem: function () - { // Open the per-item color dialog for the right-clicked item. - var sel = rightClick.selectedMenuItem; - var item = sel ? rightClick.itemFromHref(sel.href) : null; - if (!item) { - warn("Couldn't identify the item to color."); - return; - } - var existing = rightClick.findItemColor(item.track, item.name); - var currentColor = existing ? existing.hex : "#ff0000"; - var currentMode = existing ? existing.mode : "item"; - rightClick.showItemColorPicker(item.track, item.name, currentColor, currentMode); - }, - - showItemColorPicker: function (track, itemName, currentColor, currentMode) - { // Spectrum dialog to recolor a single item's glyph or draw a colored background behind it. - var dialogId = "itemColorDialog"; - $("#" + dialogId).remove(); - var $dlg = $("<div>").attr("id", dialogId).html( - "<p>Pick a color for <b></b>:</p>" + - "<input type='text' id='itemColorText' size='8' />" + - " <input id='itemColorPicker' />" + - "<br><br><label><input type='radio' name='itemColorMode' value='item'> " + - "Color whole item</label>" + - "<br><label><input type='radio' name='itemColorMode' value='bg'> " + - "Background highlight</label>"); - $dlg.find("p b").text(itemName); - $dlg.find("#itemColorText").val(currentColor); - $dlg.find("input[name='itemColorMode'][value='" + - (currentMode === "bg" ? "bg" : "item") + "']").prop("checked", true); - $("body").append($dlg); - var hexColorRe = /^#[0-9a-fA-F]{6}$/; - $("#itemColorPicker").spectrum({ - color: currentColor, - showPalette: true, - showSelectionPalette: true, - showInitial: true, - showInput: true, - preferredFormat: "hex", - localStorageKey: "genomebrowser", - hideAfterPaletteSelect: true, - change: function(color) { - $("#itemColorText").val(color.toHexString()); - } - }); - $("#itemColorText").on("change", function() { - var val = $(this).val(); - if (hexColorRe.test(val)) - $("#itemColorPicker").spectrum("set", val); - }); - var applyColor = function() { - var color = $("#itemColorText").val(); - if (!hexColorRe.test(color)) { - warn("Invalid color '" + color + "'. Expected hex format like #1a2b3c."); - return false; - } - var mode = $("input[name='itemColorMode']:checked").val() || "item"; - rightClick.setItemColor(track, itemName, color, mode); - return true; - }; - $("#" + dialogId).dialog({ - modal: true, - title: "Color this item", - closeOnEscape: true, - resizable: false, - minWidth: 400, - buttons: { - "Apply": function() { applyColor(); }, - "Ok": function() { - if (applyColor()) - $(this).dialog("close"); - } - }, - close: function() { - $("#itemColorPicker").spectrum("destroy"); - $(this).remove(); - } - }); - }, - // CGIs now use HTML tags, e.g. "<b>Transcript:</b> ENST00000297261.7<br><b>Strand:</b>" mouseOverToLabel: function(title) { if (title.search(/<b>Transcript: ?<[/]b>/) !== -1) { title = title.split("<br>")[0].split("</b>")[1]; } // for older UCSC genes tracks, the protein name is forced onto the item name if (title.search(/&hgg_prot=/) !== -1) { title = title.split("&hgg_prot=")[0]; } return title; }, // when "exonNumbers on", the mouse over text is not a good item description for the right-click menu // "exonNumbers on" is the default for genePred/bigGenePred tracks but can also be actived for bigBed and others @@ -4415,51 +4159,30 @@ if (displayItemFunctions) { o[rightClick.makeImgTag("magnify.png") + " Zoom to " + title] = { onclick: function(menuItemClicked, menuObject) { rightClick.hit(menuItemClicked, menuObject, "selectWholeGene"); return true; } }; o[rightClick.makeImgTag("highlight.png") + " Highlight " + title] = { onclick: function(menuItemClicked, menuObject) { rightClick.hit(menuItemClicked, menuObject, "highlightItem"); return true; } }; - var itemForColor = rightClick.itemFromHref(href); - if (itemForColor) { - o[rightClick.makeImgTag("palette.png") + " Color " + title + "..."] = - { onclick: function(menuItemClicked, menuObject) { - rightClick.hit(menuItemClicked, menuObject, - "colorThisItem"); - return true; - } - }; - if (rightClick.findItemColor(itemForColor.track, - itemForColor.name)) { - o[rightClick.makeImgTag("palette.png") + - " Remove color from " + title] = - { onclick: function(menuItemClicked, menuObject) { - rightClick.hit(menuItemClicked, menuObject, - "removeItemColor"); - return true; - } - }; - } - } //o[rightClick.makeImgTag("highlight.png") + " Highlight THIS item"] = // { onclick: function(menuItemClicked, menuObject) { // rightClick.hit(menuItemClicked, menuObject, // "highlightThisItem"); // return true; // } // }; if (rightClick.supportZoomCodon && (rec.type.indexOf("genePred") !== -1 || rec.type.indexOf("bigGenePred") !== -1)) { // http://hgwdev-larrym.gi.ucsc.edu/cgi-bin/hgGene?hgg_gene=uc003tqk.2&hgg_prot=P00533&hgg_chrom=chr7&hgg_start=55086724&hgg_end=55275030&hgg_type=knownGene&db=hg19&c=chr7 var name, table; var reg = new RegExp("hgg_gene=([^&]+)"); let a = reg.exec(href); if (a && a[1]) { name = a[1]; @@ -4652,37 +4375,30 @@ } o[rightClick.makeImgTag("book.png")+" Track Description "+rec.shortLabel] = { onclick: function(menuItemClicked, menuObject) { rightClick.hit(menuItemClicked, menuObject, "hgTrackUi_popup_description"); return true; } }; if (rec.defaultColor) { o[rightClick.makeImgTag("palette.png")+" Change Track Color"] = { onclick: function(menuItemClicked, menuObject) { rightClick.hit(menuItemClicked, menuObject, "changeTrackColor"); return true; } }; } - if (rightClick.hasItemColorsForCurrentDb()) { - o[rightClick.makeImgTag("palette.png")+" Clear all item colors"] = { - onclick: function(menuItemClicked, menuObject) { - rightClick.hit(menuItemClicked, menuObject, "clearItemColors"); - return true; } - }; - } menu.push($.contextMenu.separator); menu.push(o); } menu.push($.contextMenu.separator); if (hgTracks.highlight && rightClick.clickedHighlightIdx!==null) { var currentlySeen = ($('#highlightItem').length > 0); o = {}; // Jumps to highlight when not currently seen in image var text = (currentlySeen ? " Zoom" : " Jump") + " to highlight"; o[rightClick.makeImgTag("highlightZoom.png") + text] = { onclick: rightClick.makeHitCallback('jumpToHighlight') };