3d3f084876b33513ffa9047d3129c71f628b6ebc chmalee Wed Mar 13 16:29:59 2024 -0700 Show hgc details pages in a dialog on hgTracks. Currently under hg.conf control , refs #33216 diff --git src/hg/js/hgTracks.js src/hg/js/hgTracks.js index b83ebe5..02ecf90 100644 --- src/hg/js/hgTracks.js +++ src/hg/js/hgTracks.js @@ -704,82 +704,70 @@ return (posting.blockUseMap === false); }, blockTheMapOnMouseMove: function (ev) { if (!posting.blockUseMap && mouse.hasMoved(ev)) { posting.blockUseMap=true; } }, mapClk: function () { var done = false; // if we clicked on a merged item then show all the items, similar to clicking a // dense track to turn it to pack - if (this && this.href && this.href.indexOf("i=mergedItem") !== -1) { - var id = this.href.slice(this.href.indexOf("&g=")); - id = id.split(/&[^=]+=/)[1]; + if (!(this && this.href)) { + writeToApacheLog(`no href for mapClk, this = `); + } + let parsedUrl = parseUrl(this.href); + let cgi = parsedUrl.cgi; + let id = parsedUrl.queryArgs.g; + if (parsedUrl.queryArgs.i === "mergedItem") { updateObj={}; updateObj[id+".doMergeItems"] = 0; hgTracks.trackDb[id][id+".doMergeItems"] = 0; cart.setVarsObj(updateObj,null,false); imageV2.requestImgUpdate(id, id + ".doMergeItems=0"); return false; } - if (false && imageV2.inPlaceUpdate) { - // XXXX experimental and only turned on in larrym's tree. - // Use in-place update if the map item just modifies the current position (this is nice - // because it's faster and preserves the users relative position in the track image). - // - // First test handles next/prev item. - var str = "/cgi-bin/hgTracks\\?position=([^:]+):(.+)&hgsid=(\\d+)" + - "&(hgt.(next|prev)Item=[^&]+)"; - var reg = new RegExp(str); - var a = reg.exec(this.href); - if (a && a[1] && a[1] === hgTracks.chromName) { - imageV2.navigateInPlace("position=" + encodeURIComponent(a[1] + ":" + a[2]) + - "&" + a[4], null, true); - done = true; - } else { - // handle next/prev exon - str = "/cgi-bin/hgTracks\\?position=([^:]+):(.+)&hgsid=(\\d+)$"; - reg = new RegExp(str); - a = reg.exec(this.href); - if (a && a[1]) { - imageV2.navigateInPlace("position=" + encodeURIComponent(a[1] + ":" + a[2]), - null, true); - done = true; + if (done) + return false; + else { + if (cgi === "hgGene") { + id = parsedUrl.queryArgs.hgg_type; + popUpHgcOrHgGene.hgc(id, this.href); + return false; + } else if (cgi === "hgTrackUi") { + rec = hgTracks.trackDb[id]; + if (rec && tdbIsLeaf(rec)) { + popUp.hgTrackUi(id, false); } else { - // handle toggle visibility. - // Request may include a track set, so we cannot use requestImgUpdate. - str = "/cgi-bin/hgTracks\\?(position=[^:]+:.+&hgsid=\\d+&([^=]+)=([^&]+))$"; - reg = new RegExp(str); - a = reg.exec(this.href); - if (a && a[1]) { - imageV2.navigateInPlace(a[1], null, true); - // imageV2.requestImgUpdate(a[1], a[1] + "=" + a[2], "", a[2]); - done = true; + location.assign(href); } + } else if (cgi === "hgc") { + if (id.startsWith("multiz")) { + // multiz tracks have a form that lets you change highlighted bases + // that does not play well in a pop up + location.assign(href); + return false; } + popUpHgcOrHgGene.hgc(id, this.href); + return false; } } - if (done) - return false; - else - return posting.saveSettings(this); }, saveSettings: function (obj) { if (posting.blockUseMap === true) { return false; } if (!obj || !obj.href) // called directly with obj obj = this; // and from callback without obj if ($(obj).hasClass('noLink')) // TITLE_BUT_NO_LINK return false; if (obj.href.match('#') || obj.target.length > 0) { //alert("Matched # ["+obj.href+"] or has target:"+obj.target); @@ -2503,34 +2491,33 @@ var v = vars[i]; var val; if (v === "db") { val = getDb(); } else { val = hgTracks[valNames[i]]; } if (val && id !== "wikiTrack" && (href.indexOf("?" + v + "=") === -1) && (href.indexOf("&" + v + "=") === -1)) { href = href + "&" + v + "=" + val; } } if (cmd === 'followLink') { - // XXXX This is blocked by Safari's popup blocker (without any warning message). - location.assign(href); + popUpHgcOrHgGene.hgc(rightClick.selectedMenuItem.id, href); } else { - // Remove hgsid to force a new session (see redmine ticket 1333). + // XXXX This is blocked by Safari's popup blocker (without any warning message). href = removeHgsid(href); if ( ! window.open(href) ) { rightClick.windowOpenFailedMsg(); } } } else if (cmd === 'float') { if (rightClick.floatingMenuItem && rightClick.floatingMenuItem === id) { $.floatMgr.FOArray = []; rightClick.floatingMenuItem = null; } else { if (rightClick.floatingMenuItem) { // This doesn't work. $('#img_data_' + rightClick.floatingMenuItem).parent().restartFloat(); // This does work $.floatMgr.FOArray = []; @@ -3386,30 +3373,187 @@ } else if (hgTracks.virtModeType == "singleAltHaplo") { msg += "alt haplotype"; } msg += " view.   " + "Select a different viewing mode, or exit and return to normal view."; } $('#multiRegionConfigStatusMsg').html(msg); // Make 'Cancel' button close dialog $('input[name="Cancel"]').click(function() { $('#hgTracksDialog').dialog('close'); }); } }; +var popUpHgcOrHgGene = { + + whichHgcMethod: "", // either hgc or hgGene or whatever else + table: "", // the g= parameter + title: "", + saveAllVars: null, // when a click brings up hgTrackUi or something else with a form + loadingId: null, // the id of the loading overlay + href: "", // the link we're populating the pop up with + + cleanup: function () + { // Clean out the popup box on close + if ($('#hgcDialog').html().length > 0 ) { + // clear out html after close to prevent problems caused by duplicate html elements + $('#hgcDialog').html(""); + popUpHgcOrHgGene.whichHgcMethod = ""; + popUpHgcOrHgGene.title = ""; + popUpHgcOrHgGene.table = ""; + if (loadingId) { + hideLoadingImage(loadingId); + } + } + }, + + _uiDialogRequest: function (table, href) + { // popup cfg dialog + let cgi = parseUrl(href).pathInfo.split('/')[1]; + popUpHgcOrHgGene.whichHgcMethod = cgi; + // the table name gets passed in + popUpHgcOrHgGene.table = table; + popUpHgcOrHgGene.title = hgTracks.trackDb[table].shortLabel; + popUpHgcOrHgGene.href = href; + var rec = hgTracks.trackDb[table]; + if (popUpHgcOrHgGene.whichHgcMethod === "hgTrackUi" && rec && rec.configureBy) { + if (rec.configureBy === 'none') + return; + else if (rec.configureBy === 'clickThrough') { + window.location = cart.addUpdatesToUrl(href); + return; + } // default falls through to configureBy popup + } + loadingId = showLoadingImage("imgTbl"); + $.ajax({ + type: "GET", + url: cart.addUpdatesToUrl(href), + dataType: "html", + trueSuccess: popUpHgcOrHgGene.uiDialog, + success: catchErrorOrDispatch, + error: errorHandler, + loadingId: loadingId, + cache: true + }); + }, + + hgc: function (table, url) + { // Launches the popup but shields the ajax with a waitOnFunction + if (typeof doHgcInPopUp !== 'undefined' && doHgcInPopUp === true) { + waitOnFunction(popUpHgcOrHgGene._uiDialogRequest, table, url); + } else { + window.location = cart.addUpdatesToUrl(url); + } + }, + + uiDialogOk: function (popObj) + { // When popup closes with ok + + }, + + uiDialog: function (response, status) + { + // Take html from hgc/hgGene and put it up as a modal dialog. + + // make sure all links (e.g. help links) open up in a new window + //response = response.replace(/"+ cleanHtml +""); + appendNonceJsToPage(nonceJs); + + + + // Strategy for popups with js: + // - jsFiles and CSS should not be included in html. Here they are shluped out. + // - The resulting files ought to be loadable dynamically (with getScript()), + // but this was not working nicely with the modal dialog + // Therefore include files must be included with hgc CGI ! + // - embedded js should not be in the popup box. + // - Somethings should be in a popup.ready() function, and this is emulated below, + // as soon as the cleanHtml is added + // Since there are many possible popup cfg dialogs, the ready should be all inclusive. + + // -- popup.ready() -- Here is the place to do things that might otherwise go + // into a $('#pop').ready() routine! + + // Searching for some semblance of size suitability + var popMaxHeight = (window.innerHeight - (window.innerHeight * 0.15)); // make 15% of the bottom of the screen still visible + var popMaxWidth = (window.innerWidth - (window.innerWidth * 0.1)); // take up 90% of the window + + // Create dialog buttons for UI popup + var uiDialogButtons = {}; + // this could be more buttons later + uiDialogButtons.OK = function() { + $(this).dialog("close"); + }; + + $('#hgcDialog').dialog({ + resizable: true, // Let scroll vertically + height: popMaxHeight, + width: popMaxWidth, + minHeight: 200, + minWidth: 400, + modal: true, + closeOnEscape: true, + autoOpen: false, + buttons: uiDialogButtons, + + open: function (event) { + // fix popup to a location -- near the top and somewhat centered on the browser image + $(event.target).parent().css('position', 'fixed'); + $(event.target).parent().css('top', '10%'); + $('#hgcDialog').find('.filterBy,.filterComp').each( + function(i) { // ddcl.js is dropdown checklist lib support + if ($(this).hasClass('filterComp')) + ddcl.setup(this); + else + ddcl.setup(this, 'noneIsAll'); + } + ); + }, + + close: function() { + popUpHgcOrHgGene.cleanup(); + } + }); + let titleText = hgTracks.trackDb[popUpHgcOrHgGene.table].shortLabel + + " Item Details " + + "Open in new window"; + $('#hgcDialog').dialog('option' , 'title', titleText); + $('#hgcDialog').dialog('open'); + + // Customize message based on current mode + // Make 'Cancel' button close dialog + $('input[name="Cancel"]').click(function() { + $('#hgcDialog').dialog('close'); + }); + } +}; + // Show the exported data hubs popup function showExportedDataHubsPopup() { let popUp = document.getElementById("exportedDataHubsPopup"); title = popUp.title; if (title.length === 0 && popUp.getAttribute("originaltitle") !== "") {title = popUp.getAttribute("originaltitle");} $('#exportedDataHubsPopup').dialog({width:'650', title: title}); } // Show the recommended track sets popup function showRecTrackSetsPopup() { // Update links with current position $('a.recTrackSetLink').each(function() { var $this = $(this); var link = $this.attr("href").replace(/position=.*/, 'position='); $this.attr("href", link + genomePos.original);