fc3472e7e9978eb81e3ac14e985bf27e5196ab73 kate Fri Jul 24 10:58:01 2020 -0700 Recommended track sets feature. refs #25601 diff --git src/hg/js/hgTracks.js src/hg/js/hgTracks.js index 3ea5eb8..31e9c32 100644 --- src/hg/js/hgTracks.js +++ src/hg/js/hgTracks.js @@ -772,30 +772,47 @@ return postTheForm($(thisForm).attr('name'),cart.addUpdatesToUrl(obj.href)); } return true; } }; ///////////////////////// //// cart updating ///// /////////////////////// var cart = { // Controls queuing and ultimately updating cart variables vis ajax or submit. Queued vars // are held in an object with unique keys preventing duplicate updates and ensuring last update // takes precedence. WARNING: be careful creating an object with variables on the fly: // cart.setVarsObj({track: vis}) is invalid but cart.setVarsObj({'knownGene': vis}) is ok! + updateSessionPanel: function() + { + // change color of text + $('span.gbSessionChangeIndicator').addClass('gbSessionChanged'); + + // change mouseover on the panel. A bit fragile here inserting text in the mouseover specified in + // hgTracks.js, so depends on match with text there, and should present same message as C code + // (Perhaps this could be added as a script tag, so not duplicated) + var txt = $('span.gbSessionLabelPanel').attr('title'); + if (!txt.match(/with changes/)) { + $('span.gbSessionLabelPanel').attr('title', txt.replace( + "track set", + "track set, with changes (added or removed tracks) you have requested")); + } + return true; + }, + updateQueue: {}, updatesWaiting: function () { // returns TRUE if updates are waiting. return objNotEmpty(cart.updateQueue); }, addUpdatesToUrl: function (url) { // adds any outstanding cart updates to the url, then clears the queue if (cart.updatesWaiting()) { //console.log('cart.addUpdatesToUrl: '+objKeyCount(cart.updateQueue)+' vars'); var updates = cart.varsToUrlData(); // clears the queue if (!url || url.length === 0) return updates; @@ -835,30 +852,31 @@ setVarsObj: function (varsObj, errFunc, async) { // Set all vars in a var hash, appending any queued updates //console.log('cart.setVarsObj: were:'+objKeyCount(cart.updateQueue) + // ' new:'+objKeyCount(varsObj); cart.queueVarsObj(varsObj); // lay ontop of queue, to give new values precedence // Now ajax update all in queue and clear queue if (cart.updatesWaiting()) { setVarsFromHash(cart.updateQueue, errFunc, async); cart.updateQueue = {}; } }, setVars: function (names, values, errFunc, async) { // ajax updates the cart, and includes any queued updates. + cart.updateSessionPanel(); // handles hide from left minibutton cart.setVarsObj(arysToObj(names, values), errFunc, async); }, queueVarsObj: function (varsObj) { // Add object worth of cart updates to the 'to be updated' queue, so they can be sent to // the server later. Note: hash allows overwriting previous updates to the same variable. if (typeof varsObj !== 'undefined' && objNotEmpty(varsObj)) { //console.log('cart.queueVarsObj: were:'+objKeyCount(cart.updateQueue) + // ' new:'+objKeyCount(varsObj)); for (var name in varsObj) { cart.updateQueue[name] = varsObj[name]; // Could update in background, however, failing to hit "refresh" is user choice // first in queue, schedule background update if (objKeyCount(cart.updateQueue) === 1) { @@ -944,30 +962,31 @@ return false; }, initForAjax: function() { // To better support the back-button, it is good to eliminate extraneous form puts // Towards that end, we support visBoxes making ajax calls to update cart. var sels = $('select.normalText,select.hiddenText'); $(sels).change(function() { var track = $(this).attr('name'); if ($(this).val() === 'hide') { var rec = hgTracks.trackDb[track]; if (rec) rec.visibility = 0; // else Would be nice to hide subtracks as well but that may be overkill $(document.getElementById('tr_' + track)).remove(); + cart.updateSessionPanel(); imageV2.highlightRegion(); $(this).attr('class', 'hiddenText'); } else $(this).attr('class', 'normalText'); cart.addVarsToQueue([track], [$(this).val()]); imageV2.markAsDirtyPage(); return false; }); // Now we can rid the submt of the burden of all those vis boxes var form = $('form#TrackForm'); $(form).submit(function () { $('select.normalText,select.hiddenText').attr('disabled',true); }); $(form).attr('method','get'); @@ -2528,31 +2547,31 @@ cart.setVarsObj({'highlight' : hgTracks.highlight}); imageV2.highlightRegion(); } else if (cmd === 'toggleMerge') { // toggle both the cart (if the user goes to trackUi) // and toggle args[key], if the user doesn't leave hgTracks var key = id + ".doMergeItems"; var updateObj = {}; if (args[key] === 1) { args[key] = 0; updateObj[key] = 0; cart.setVarsObj(updateObj,null,false); imageV2.requestImgUpdate(id, id + ".doMergeItems=0"); } else { args[key] = 1; updateObj[key] = 1; - cart.setVars(updateObj,null,false); + cart.setVarsObj(updateObj,null,false); imageV2.requestImgUpdate(id, id + ".doMergeItems=1"); } } else { // if ( cmd in 'hide','dense','squish','pack','full','show' ) // Change visibility settings: // // First change the select on our form: rec = hgTracks.trackDb[id]; selectUpdated = vis.update(id, cmd); // Now change the track image if (imageV2.enabled && cmd === 'hide') { // Hide local display of this track and update server side cart. // Subtracks controlled by 2 settings so del vis and set sel=0. if (tdbIsSubtrack(rec)) { // Remove subtrack level vis and explicitly uncheck. @@ -3245,30 +3264,45 @@ autocompleteCat.init($('#singleAltHaploId'), { baseUrl: 'hgSuggest?db=' + getDb() + '&type=altOrPatch&prefix=', enterSelectsIdentical: true }); // Make option inputs select their associated radio buttons $('input[name="emPadding"]').keyup(function() { $('#virtModeType[value="exonMostly"]').attr('checked', true); }); $('input[name="gmPadding"]').keyup(function() { $('#virtModeType[value="geneMostly"]').attr('checked', true); }); $('#multiRegionsBedInput').keyup(function() { $('#virtModeType[value="customUrl"]').attr('checked', true); }); $('#singleAltHaploId').keyup(function() { $('#virtModeType[value="singleAltHaplo"]').attr('checked', true); }); } }; +// Show the recommended track sets popup +function showRecTrackSetsPopup() { + // Populate links with position + $('a.recTrackSetLink').each(function() { + var $this = $(this); + var _href = $this.attr("href"); + $this.attr("href", _href + genomePos.original); + }); + $('#recTrackSetsPopup').dialog({width:'650'}); +} + +function removeSessionPanel() { + $('#recTrackSetsPanel').remove(); +} + // A function to show the keyboard help dialog box, bound to ? and called from the menu bar function showHotkeyHelp() { $("#hotkeyHelp").dialog({width:'600'}); } // A function to add an entry for the keyboard help dialog box to the menubar // and add text that indicates the shortcuts to many static menubar items as suggested by good old IBM CUA/SAA function addKeyboardHelpEntries() { var html = '<li><a id="keybShorts" title="List all possible keyboard shortcuts" href="#">Keyboard Shortcuts</a><span class="shortcut">?</span></li>'; $('#help .last').before(html); $("#keybShorts").click( function(){showHotkeyHelp();} ); html = '<span class="shortcut">s s</span>'; $('#sessionsMenuLink').after(html); @@ -3430,30 +3464,31 @@ //debugDumpFormCollection("allVars", allVars); //debugDumpFormCollection("changedVars", changedVars); var newVis = changedVars[trackName]; // subtracks do not have "hide", thus '[]' var hide = (newVis && (newVis === 'hide' || newVis === '[]')); if ( ! normed($('#imgTbl')) ) { // On findTracks or config page if (objNotEmpty(changedVars)) cart.setVarsObj(changedVars); } else { // On image page if (hide) { if (objNotEmpty(changedVars)) cart.setVarsObj(changedVars); $(document.getElementById('tr_' + trackName)).remove(); imageV2.afterImgChange(true); + cart.updateSessionPanel(); } else { // Keep local state in sync if user changed visibility if (newVis) { vis.update(trackName, newVis); } if (objNotEmpty(changedVars)) { var urlData = cart.varsToUrlData(changedVars); if (imageV2.mapIsUpdateable) { imageV2.requestImgUpdate(trackName,urlData,""); } else { window.location = "../cgi-bin/hgTracks?" + urlData + "&hgsid=" + getHgsid(); } } } } @@ -3790,32 +3825,35 @@ var oldJsonRec = oldJson.trackDb[id]; if (newJsonRec.visibility === 0) // hidden 'ruler' is in newJson.trackDb! continue; if (newJsonRec.type === "remote") continue; if (oldJsonRec && oldJsonRec.visibility !== 0 && $('tr#tr_' + id).length === 1) { // New track replacing old: if (!imageV2.updateImgForId(response, id, true, newJsonRec)) warn("Couldn't parse out new image for id: " + id); } else { //if (!oldJsonRec || oldJsonRec.visibility === 0) // New track seen for the first time if (imageV2.backSupport) { $(imgTbl).append("<tr id='tr_" + id + "' abbr='0'" + // abbr gets filled in " class='imgOrd trDraggable'></tr>"); - if (!imageV2.updateImgForId(response, id, true, newJsonRec)) + if (!imageV2.updateImgForId(response, id, true, newJsonRec)) { warn("Couldn't insert new image for id: " + id); + } else { + cart.updateSessionPanel(); + } } } } if (imageV2.backSupport) { // Removes OLD: those in oldJson but not in newJson for (id in oldJson.trackDb) { if ( ! newJson.trackDb[id] ) $(document.getElementById('tr_' + id)).remove(); } // Need to reorder the rows based upon abbr dragReorder.sort($(imgTbl)); } }, @@ -3942,30 +3980,32 @@ warn("hgTracks object is missing from the response"); } else { if (this.id) { if (newJson.trackDb[this.id]) { var visibility = vis.enumOrder[newJson.trackDb[this.id].visibility]; var limitedVis; if (newJson.trackDb[this.id].limitedVis) limitedVis = vis.enumOrder[newJson.trackDb[this.id].limitedVis]; if (this.newVisibility && limitedVis && this.newVisibility !== limitedVis) // see redmine 1333#note-9 alert("There are too many items to display the track in " + this.newVisibility + " mode."); var rec = oldJson.trackDb[this.id]; rec.limitedVis = newJson.trackDb[this.id].limitedVis; vis.update(this.id, visibility); + if (visibility === "hide") + cart.updateSessionPanel(); // notify when vis change to hide track valid = true; } else { // what got returned from the AJAX request was a different // set of tracks. Let's do a reload and hope for the best imageV2.fullReload(); } } else { valid = true; } } if (valid) { if (imageV2.enabled && this.id && this.cmd && this.cmd !== 'wholeImage'