2b3deca3eaea47cb2920cb937a375334760da7d1 tdreszer Mon May 19 15:35:49 2014 -0700 Formatting changes to be laid on top of jshint polishing. diff --git src/hg/js/hgTracks.js src/hg/js/hgTracks.js index 7c7bfd9..6017517 100644 --- src/hg/js/hgTracks.js +++ src/hg/js/hgTracks.js @@ -32,41 +32,45 @@ genomePos.originalSize = $('#size').text(); dragSelect.originalCursor = jQuery('body').css('cursor'); imageV2.imgTbl = $('#imgTbl'); // imageV2.enabled === true unless: advancedJavascript===false, or trackSearch, or config pg imageV2.enabled = (imageV2.imgTbl && imageV2.imgTbl.length > 0); jQuery.each(jQuery.browser, function(i, val) { if (val) { browser = i; } }); // jQuery load function with stuff to support drag selection in track img if (browser === "safari") { if (navigator.userAgent.indexOf("Chrome") !== -1) { - // Handle the fact that (as of 1.3.1), jQuery.browser reports "safari" when the browser is in fact Chrome. + // Handle the fact that (as of 1.3.1), jQuery.browser reports "safari" + // when the browser is in fact Chrome. browser = "chrome"; } else { - // Safari has the following bug: if we update the hgTracks map dynamically, the browser ignores the changes (even - // though if you look in the DOM the changes are there). So we have to do a full form submission when the - // user changes visibility settings or track configuration. + // Safari has the following bug: if we update the hgTracks map dynamically, + // the browser ignores the changes (even though if you look in the DOM the changes + // are there). So we have to do a full form submission when the user changes + // visibility settings or track configuration. // As of 5.0.4 (7533.20.27) this is problem still exists in safari. - // As of 5.1 (7534.50) this problem appears to have been fixed - unfortunately, logs for 7/2011 show vast majority of safari users - // are pre-5.1 (5.0.5 is by far the most common). + // As of 5.1 (7534.50) this problem appears to have been fixed - unfortunately, + // logs for 7/2011 show vast majority of safari users are pre-5.1 (5.0.5 is by far + // the most common). // - // Early versions of Chrome had this problem too, but this problem went away as of Chrome 5.0.335.1 (or possibly earlier). + // Early versions of Chrome had this problem too, but this problem went away + // as of Chrome 5.0.335.1 (or possibly earlier). imageV2.mapIsUpdateable = false; var reg = new RegExp("Version\/([0-9]+.[0-9]+) Safari"); var a = reg.exec(navigator.userAgent); if (a && a[1]) { var version = Number(a[1]); if (version >= 5.1) { imageV2.mapIsUpdateable = true; } } } } imageV2.inPlaceUpdate = hgTracks.inPlaceUpdate && imageV2.mapIsUpdateable; } } @@ -145,52 +149,56 @@ for (var i = 0; i < tags.length; i++) { var ele = tags[i]; ele.value = position; } } if ($('#positionDisplay').length) { $('#positionDisplay').text(position); } if (size) { $('#size').text(size); } var pos = parsePosition(position); if (pos) { // fixup external static links on page' - // Example ensembl link: http://www.ensembl.org/Homo_sapiens/contigview?chr=21&start=33031934&end=33041241 + // Example ensembl link: + // http://www.ensembl.org/Homo_sapiens/contigview?chr=21&start=33031934&end=33041241 genomePos.linkFixup(pos, "ensemblLink", new RegExp("(.+start=)[0-9]+"), "end"); - // Example NCBI link: http://www.ncbi.nlm.nih.gov/mapview/maps.cgi?taxid=9606&CHR=21&BEG=33031934&END=33041241 + // Example NCBI link: + // http://www.ncbi.nlm.nih.gov/mapview/maps.cgi?taxid=9606&CHR=21&BEG=33031934&END=33041241 genomePos.linkFixup(pos, "ncbiLink", new RegExp("(.+BEG=)[0-9]+"), "END"); - // Example medaka link: http://utgenome.org/medakabrowser_ens_jump.php?revision=version1.0&chr=chromosome18&start=14435198&end=14444829 + // Example medaka link: + // http://utgenome.org/medakabrowser_ens_jump.php?revision=version1.0&chr=chromosome18&start=14435198&end=14444829 genomePos.linkFixup(pos, "medakaLink", new RegExp("(.+start=)[0-9]+"), "end"); var link; var reg; var a; if ($('#wormbaseLink').length) { // e.g. http://www.wormbase.org/db/gb2/gbrowse/c_elegans?name=II:14646301-14667800 link = $('#wormbaseLink').attr('href'); reg = new RegExp("(.+:)[0-9]+"); a = reg.exec(link); if (a && a[1]) { $('#wormbaseLink').attr('href', a[1] + pos.start + "-" + pos.end); } } - // Fixup DNA link; e.g.: hgc?hgsid=2999470&o=114385768&g=getDna&i=mixed&c=chr7&l=114385768&r=114651696&db=panTro2&hgsid=2999470 + // Fixup DNA link; e.g.: + // hgc?hgsid=2999470&o=114385768&g=getDna&i=mixed&c=chr7&l=114385768&r=114651696&db=panTro2&hgsid=2999470 if ($('#dnaLink').length) { link = $('#dnaLink').attr('href'); reg = new RegExp("(.+&o=)[0-9]+.+&db=[^&]+(.*)"); a = reg.exec(link); if (a && a[1]) { var url = a[1] + (pos.start - 1) + "&g=getDna&i=mixed&c=" + pos.chrom; url += "&l=" + (pos.start - 1) + "&r=" + pos.end + "&db=" + getDb() + a[2]; $('#dnaLink').attr('href', url); } } } if (!imageV2.backSupport) imageV2.markAsDirtyPage(); }, @@ -390,50 +398,54 @@ return (posting.blockUseMap === false); }, blockTheMapOnMouseMove: function (ev) { if (!posting.blockUseMap && mouse.hasMoved(ev)) { posting.blockUseMap=true; } }, mapClk: function () { var done = 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 it preserves the users current relative position in the track image). + // 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 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); + 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); + imageV2.navigateInPlace("position=" + encodeURIComponent(a[1] + ":" + a[2]), + null, true); done = true; } else { - // handle toggle visibility. Request may include a track set, so we cannot use requestImgUpdate. + // 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; } } } } if (done) return false; else return posting.saveSettings(this); @@ -537,53 +549,54 @@ setVars: function (names, values, errFunc, async) { // ajax updates the cart, and includes any queued updates. 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]; - // NOTE: could update in background, however, failing to hit "refresh" is a user choice + // Could update in background, however, failing to hit "refresh" is user choice // first in queue, schedule background update if (objKeyCount(cart.updateQueue) === 1) { // By unbind/bind, we assure that there is only one instance bound $(window).unbind('beforeunload', cart.beforeUnload); $(window).bind( 'beforeunload', cart.beforeUnload); } } } }, addVarsToQueue: function (names,values) { // creates a string of updates to save for ajax batch or a submit cart.queueVarsObj(arysToObj(names,values)); } }; /////////////////////////////////////////////// //// visibility (mixed with group toggle) ///// /////////////////////////////////////////////// var vis = { - enumOrder: new Array("hide", "dense", "full", "pack", "squish"), // map cgi enum visibility codes to strings + // map cgi enum visibility codes to strings + enumOrder: new Array("hide", "dense", "full", "pack", "squish"), update: function (track, visibility) { // Updates visibility state in hgTracks.trackDb and any visible elements on the page. // returns true if we modify at least one select in the group list var rec = hgTracks.trackDb[track]; var selectUpdated = false; $("select[name=" + escapeJQuerySelectorChars(track) + "]").each(function(t) { $(this).attr('class', visibility === 'hide' ? 'hiddenText' : 'normalText'); $(this).val(visibility); selectUpdated = true; }); if (rec) { rec.localVisibility = visibility; } return selectUpdated; @@ -602,44 +615,46 @@ return null; } }, makeTrackVisible: function (track) { if (track && vis.get(track) !== "full") { vis.update(track, 'pack'); $("<input type='hidden' name='" + track + "'value='pack'>").appendTo( $(document.TrackHeaderForm)); } }, toggleForGroup: function (button, prefix) { // toggle visibility of a track group; prefix is the prefix of all the id's of tr's in the - // relevant group. This code also modifies the corresponding hidden fields and the gif of the +/- img tag. + // relevant group. This code also modifies the corresponding hidden fields and the gif + // of the +/- img tag. imageV2.markAsDirtyPage(); if (arguments.length > 2) return setTableRowVisibility(button, prefix, "hgtgroup", "group",false,arguments[2]); else return setTableRowVisibility(button, prefix, "hgtgroup", "group",false); }, expandAllGroups: function (newState) { // Set visibility of all track groups to newState (true means expanded). // This code also modifies the corresponding hidden fields and the gif's of the +/- img tag. imageV2.markAsDirtyPage(); - $(".toggleButton[id$='_button']").each( function (i) { // works for old img type AND new BUTTONS_BY_CSS - vis.toggleForGroup(this,this.id.substring(0,this.id.length - 7),newState); // clip '_button' suffix + $(".toggleButton[id$='_button']").each( function (i) { + // works for old img type AND new BUTTONS_BY_CSS // - 7: clip '_button' suffix + vis.toggleForGroup(this,this.id.substring(0,this.id.length - 7),newState); }); 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 @@ -860,33 +875,36 @@ } } }; ///////////////////////////////////// //// Chrom Drag/Zoom/Expand code //// ///////////////////////////////////// jQuery.fn.chromDrag = function(){ this.each(function(){ // Plan: // mouseDown: determine where in map: convert to img location: pxDown // mouseMove: flag drag // mouseUp: if no drag, then create href centered on bpDown loc with current span // if drag, then create href from bpDown to bpUp // if ctrlKey then expand selection to containing cytoBand(s) - var img = { top: -1, scrolledTop: -1, height: -1, left: -1, scrolledLeft: -1, width: -1 }; // Image dimensions all in pix + + // Image dimensions all in pix + var img = { top: -1, scrolledTop: -1, height: -1, left: -1, scrolledLeft: -1, width: -1 }; + // chrom Dimensions beg,end,size in bases, rest in pix var chr = { name: "", reverse: false, beg: -1, end: -1, size: -1, - top: -1, bottom: -1, left: -1, right: -1, width: -1 }; // chrom Dimenaions beg,end,size in bases, rest in pix + top: -1, bottom: -1, left: -1, right: -1, width: -1 }; var pxDown = 0; // pix X location of mouseDown var chrImg = $(this); var mouseIsDown = false; var mouseHasMoved = false; var hilite = null; initialize(); function initialize(){ findDimensions(); if (chr.top === -1) warn("chromIdeo(): failed to register "+this.id); else { @@ -926,98 +944,98 @@ else hiliteShow(pxDown,chr.right); } } } function chromUp(e) { // If mouse was down, handle final selection $(document).unbind('mousemove',chromMove); $(document).unbind('mouseup',chromUp); chromMove(e); // Just in case if (mouseIsDown) { updateImgOffsets(); var bands; var pxUp = e.clientX - img.scrolledLeft; var pxY = e.clientY - img.scrolledTop; - //warn("chromIdeo("+chr.name+") selected range (pix):"+pxDown+"-"+pxUp+" chrom range (pix):"+chr.left+"-"+chr.right+" chrom range (bp):"+chr.name+":"+chr.beg+"-"+chr.end); if (isWithin(0,pxY,img.height)) { // within vertical range or else cancel var selRange = { beg: -1, end: -1, width: -1 }; var dontAsk = true; if (e.ctrlKey) { bands = findCytoBand(pxDown,pxUp); if (bands.end > -1) { pxDown = bands.left; pxUp = bands.right; mouseHasMoved = true; dontAsk = false; selRange.beg = bands.beg; selRange.end = bands.end; hiliteShow(pxDown,pxUp); } } else if (mouseHasMoved) { - if ( isWithin(-20,pxUp,chr.left) ) // bounded by chrom dimensions: but must remain within image! + // bounded by chrom dimensions: but must remain within image! + if (isWithin(-20,pxUp,chr.left)) pxUp = chr.left; if (isWithin(chr.right,pxUp,img.width + 20)) pxUp = chr.right; if ( isWithin(chr.left,pxUp,chr.right+1) ) { selRange.beg = convertToBases(pxDown); selRange.end = convertToBases(pxUp); if (Math.abs(selRange.end - selRange.beg) < 20) mouseHasMoved = false; // Drag so small: treat as simple click else dontAsk = false; } - //else warn("chromIdeo("+chr.name+") NOT WITHIN HORIZONTAL RANGE\n selected range (pix):"+pxDown+"-"+pxUp+" chrom range (pix):"+chr.left+"-"+chr.right); } if (mouseHasMoved === false) { // Not else because small drag turns this off hiliteShow(pxUp,pxUp); var curWidth = hgTracks.winEnd - hgTracks.winStart; - selRange.beg = convertToBases(pxUp) - Math.round(curWidth/2); // Notice that beg is based upon up position + // Notice that beg is based upon up position + selRange.beg = convertToBases(pxUp) - Math.round(curWidth/2); selRange.end = selRange.beg + curWidth; } if (selRange.end > -1) { // prompt, then submit for new position selRange = rangeNormalizeToChrom(selRange,chr); if (mouseHasMoved === false) { // Update highlight by converting bp back to pix pxDown = convertFromBases(selRange.beg); pxUp = convertFromBases(selRange.end); hiliteShow(pxDown,pxUp); } //if ((selRange.end - selRange.beg) < 50000) // dontAsk = true; if (dontAsk || confirm("Jump to new position:\n\n"+chr.name+":"+commify(selRange.beg)+ "-"+commify(selRange.end)+" size:"+commify(selRange.width)) ) { genomePos.setByCoordinates(chr.name, selRange.beg, selRange.end); - $('area.cytoBand').mousedown( function(e) { return false; }); // Stop the presses :0) + // Stop the presses :0) + $('area.cytoBand').mousedown( function(e) { return false; }); if (imageV2.backSupport) { imageV2.navigateInPlace("position=" + encodeURIComponent(genomePos.get().replace(/,/g,'')),null,true); hiliteCancel(); } else document.TrackHeaderForm.submit(); return true; // Make sure the setTimeout below is not called. } } } - //else warn("chromIdeo("+chr.name+") NOT WITHIN VERTICAL RANGE\n selected range (pix):"+pxDown+"-"+pxUp+" chrom range (pix):"+chr.left+"-"+chr.right+"\n cytoTop-Bottom:"+chr.top +"-"+chr.bottom); hiliteCancel(); setTimeout(posting.allowMapClicks,50); } mouseIsDown = false; mouseHasMoved = false; } function isWithin(beg,here,end) { // Simple utility return ( beg <= here && here < end ); } function convertToBases(pxX) { // Simple utility to convert pix to bases var offset = (pxX - chr.left)/chr.width; if (chr.reverse) @@ -1071,31 +1089,31 @@ else if (lastX > myRight) chr.reverse = true; // end is advancing, but X is not, so reverse } else if (lastX !== -1 && lastX < myRight) chr.reverse = true; // end is not advancing, but X is, so reverse } $(this).css( 'cursor', 'text'); $(this).attr("href",""); } }); chr.size = (chr.end - chr.beg ); chr.width = (chr.right - chr.left); } function findCytoBand(pxDown,pxUp) - { // Called when mouseup and ctrl: Find the bounding cytoband dimensions, both in pix and bases + { // Called when mouseup and ctrl: Find the bounding cytoband dimensions (in pix and bases) var cyto = { left: -1, right: -1, beg: -1, end: -1 }; $('area.cytoBand').each(function(ix) { var loc = this.coords.split(","); if (loc.length === 4) { var myLeft = parseInt(loc[0]); var myRight = parseInt(loc[2]); var range; var pos; if (cyto.left === -1 || cyto.left > myLeft) { if ( isWithin(myLeft,pxDown,myRight) || isWithin(myLeft,pxUp,myRight) ) { cyto.left = myLeft; range = this.title.substr(this.title.lastIndexOf(':')+1); pos = range.split('-'); if (pos.length === 2) { cyto.beg = (chr.reverse ? parseInt(pos[1]) : parseInt(pos[0])); @@ -1105,31 +1123,32 @@ if (cyto.right === -1 || cyto.right < myRight) { if ( isWithin(myLeft,pxDown,myRight) || isWithin(myLeft,pxUp,myRight) ) { cyto.right = myRight; range = this.title.substr(this.title.lastIndexOf(':')+1); pos = range.split('-'); if (pos.length === 2) { cyto.end = (chr.reverse ? parseInt(pos[0]) : parseInt(pos[1])); } } } } }); return cyto; } function rangeNormalizeToChrom(selection,chrom) - { // Called before presenting or using base range: make sure chrom selection is within chrom range + { // Called before presenting or using base range: make sure chrom selection + // is within chrom range if (selection.end < selection.beg) { var tmp = selection.end; selection.end = selection.beg; selection.beg = tmp; } selection.width = (selection.end - selection.beg); selection.beg += 1; if (selection.beg < chrom.beg) { selection.beg = chrom.beg; selection.end = chrom.beg + selection.width; } if (selection.end > chrom.end) { selection.end = chrom.end; selection.beg = chrom.end - selection.width; if (selection.beg < chrom.beg) { // spans whole chrom @@ -1345,72 +1364,75 @@ var lastBtn = null; var lastMatchesLast=false; var lastBlue=true; var altColors=false; var count=0; var countN=0; for (var ix=0; ix<rows.length; ix++) { // Need to have buttons in order var btn = $( rows[ix] ).find("p.btn"); if (btn.length === 0) continue; var classList = $( btn ).attr("class").split(" "); var curMatchesLast=(classList[0] === lastClass); // centerLabels may be conditionally seen if ($( rows[ix] ).hasClass('clOpt')) { + // if same composite and previous also centerLabel optional then hide center label if (curMatchesLast && $( rows[ix - 1] ).hasClass('clOpt')) - dragReorder.showCenterLabel(rows[ix],false); // if same composite and previous is also centerLabel optional then hide center label + dragReorder.showCenterLabel(rows[ix],false); else dragReorder.showCenterLabel(rows[ix],true); } // On with buttons if (lastBtn) { $( lastBtn ).removeClass('btnN btnU btnL btnD'); if (curMatchesLast && lastMatchesLast) { $( lastBtn ).addClass('btnL'); } else if (lastMatchesLast) { $( lastBtn ).addClass('btnU'); } else if (curMatchesLast) { $( lastBtn ).addClass('btnD'); } else { $( lastBtn ).addClass('btnN'); countN++; } count++; if (altColors) { - lastBlue = (lastMatchesLast === lastBlue); // lastMatch and lastBlue or not lastMatch and notLastBlue + // lastMatch and lastBlue or not lastMatch and notLastBlue + lastBlue = (lastMatchesLast === lastBlue); if (lastBlue) // Too smart by 1/3rd $( lastBtn ).addClass( 'btnBlue' ); else $( lastBtn ).removeClass( 'btnBlue' ); } } lastMatchesLast = curMatchesLast; lastClass = classList[0]; lastBtn = btn; } if (lastBtn) { $( lastBtn ).removeClass('btnN btnU btnL btnD'); if (lastMatchesLast) { $( lastBtn ).addClass('btnU'); } else { $( lastBtn ).addClass('btnN'); countN++; } if (altColors) { - lastBlue = (lastMatchesLast === lastBlue); // lastMatch and lastBlue or not lastMatch and notLastBlue + // lastMatch and lastBlue or not lastMatch and notLastBlue + lastBlue = (lastMatchesLast === lastBlue); if (lastBlue) // Too smart by 1/3rd $( lastBtn ).addClass( 'btnBlue' ); else $( lastBtn ).removeClass( 'btnBlue' ); } count++; } //warn("Zipped "+count+" buttons "+countN+" are independent."); }, dragHandleMouseOver: function () { // Highlights a single row when mouse over a dragHandle column (sideLabel and buttons) if ( ! jQuery.tableDnD ) { //var handle = $("td.dragHandle"); //$(handle) @@ -1444,42 +1466,42 @@ }, buttonMouseOut: function () { // Ends composite highlighting by mouse over var classList = $( this ).attr("class").split(" "); var btns = $( "p." + classList[0] ); $( btns ).removeClass('btnBlue'); $( btns ).addClass('btnGrey'); if (jQuery.tableDnD) { var rows = dragReorder.getContiguousRowSet($(this).parents('tr.trDraggable')[0]); if (rows) $( rows ).removeClass("trDrag"); } }, - trMouseOver: function (e) // LARRY: is this the right thing? - { - // Trying to make sure there is always a imageV2.lastTrack so that we know where we are + trMouseOver: function (e) + { // Trying to make sure there is always a imageV2.lastTrack so that we know where we are var id = ''; var a = /tr_(.*)/.exec($(this).attr('id')); // voodoo if (a && a[1]) { id = a[1]; } if (id.length > 0) { if ( ! imageV2.lastTrack || imageV2.lastTrack.id !== id) - imageV2.lastTrack = rightClick.makeMapItem(id); // currentMapItem gets set by mapItemMapOver - } // This is just backup + imageV2.lastTrack = rightClick.makeMapItem(id); + // currentMapItem gets set by mapItemMapOver. This is just backup + } }, mapItemMouseOver: function () { // Record data for current map area item var id = this.id; if (!id || id.length === 0) { id = ''; var tr = $( this ).parents('tr.imgOrd'); if ( $(tr).length === 1 ) { var a = /tr_(.*)/.exec($(tr).attr('id')); // voodoo if (a && a[1]) { id = a[1]; } } @@ -1519,79 +1541,77 @@ $(".area").each( function(t) { this.onmouseover = dragReorder.mapItemMouseOver; this.onmouseout = dragReorder.mapItemMouseOut; this.onclick = posting.mapClk; }); } }; ////////////////////////// //// Drag Scroll code //// ////////////////////////// jQuery.fn.panImages = function(){ // globals across all panImages - genomePos.original = genomePos.getOriginalPos(); // XXXX what is this for? (this already happened in initVars). + genomePos.original = genomePos.getOriginalPos(); // redundant but makes certain original is set. var leftLimit = hgTracks.imgBoxLeftLabel * -1; var rightLimit = (hgTracks.imgBoxPortalWidth - hgTracks.imgBoxWidth + leftLimit); - var only1xScrolling = ((hgTracks.imgBoxWidth - hgTracks.imgBoxPortalWidth) === 0);//< hgTracks.imgBoxLeftLabel); + var only1xScrolling = ((hgTracks.imgBoxWidth - hgTracks.imgBoxPortalWidth) === 0); var prevX = (hgTracks.imgBoxPortalOffsetX + hgTracks.imgBoxLeftLabel) * -1; var portalWidth = 0; var portalAbsoluteX = 0; var savedPosition; var highlightArea = null; // Used to ensure dragSelect highlight will scroll. this.each(function(){ var pic; var pan; if ( $(this).is("img") ) { pan = $(this).parent("div"); pic = $(this); } else if ( $(this).is("div.scroller") ) { pan = $(this); pic = $(this).children("img#panImg"); // Get the real pic } if (!pan || !pic) { - throw "Not a div with a child image! 'panImages' can only be used with divs contain images."; + throw "Not a div with child image! 'panImages' can only be used with divs contain images."; } // globals across all panImages portalWidth = $(pan).width(); portalAbsoluteX = $(pan).offset().left; // globals to one panImage var newX = 0; var mouseDownX = 0; var mouseIsDown = false; var beyondImage = false; var atEdge = false; initialize(); function initialize(){ $(pan).parents('td.tdData').mousemove(function(e) { if (e.shiftKey) $(this).css('cursor',"crosshair"); // shift-dragZoom else if ( $.browser.msie ) // IE will override map item cursors if this gets set $(this).css('cursor',""); // normal pointer when not over clickable item - //else // NOTE: Open hand cursor is being removed because it makes vis toggling less obvious - // $(this).css('cursor',"url(../images/grabber.cur),w-resize"); // dragScroll }); panAdjustHeight(prevX); pan.mousedown(function(e){ if (e.which > 1 || e.button > 1 || e.shiftKey) return true; if (mouseIsDown === false) { if (rightClick.menu) { rightClick.menu.hide(); } mouseIsDown = true; mouseDownX = e.clientX; highlightArea = $('#highlightItem')[0]; atEdge = (!beyondImage && (prevX >= leftLimit || prevX <= rightLimit)); @@ -1633,43 +1653,44 @@ newX = rightLimit - (rightLimit - newX)/decelerator;// slower //if (newX < rightLimit - wingSize) // Don't go too far over the edge! // newX = rightLimit - wingSize; } else newX = rightLimit; } else if (newX >= rightLimit && newX < leftLimit) beyondImage = false; // could have scrolled back without mouse up newX = panUpdatePosition(newX,true); var nowPos = newX.toString() + "px"; $(".panImg").css( {'left': nowPos }); $('.tdData').css( {'backgroundPosition': nowPos } ); scrollHighlight(relativeX); if (!only1xScrolling) - panAdjustHeight(newX); // NOTE: This will dynamically resize image while scrolling. Do we want to? + panAdjustHeight(newX); // Will dynamically resize image while scrolling. } } } function panMouseUp(e) { // Must be a separate function instead of pan.mouseup event. //if (!e) e = window.event; if (mouseIsDown) { dragMaskClear(); $(document).unbind('mousemove',panner); $(document).unbind('mouseup',panMouseUp); mouseIsDown = false; - setTimeout(posting.allowMapClicks,50); // Necessary incase the dragSelect.selectEnd was over a map item. select takes precedence. + // timeout incase the dragSelect.selectEnd was over a map item. select takes precedence. + setTimeout(posting.allowMapClicks,50); // Outside image? Then abandon. var curY = e.pageY; var imgTbl = $('#imgTbl'); var north = $(imgTbl).offset().top; var south = north + $(imgTbl).height(); if (curY < north || curY > south) { atEdge = false; beyondImage = false; if (savedPosition) genomePos.set(savedPosition,null); var oldPos = prevX.toString() + "px"; $(".panImg").css( {'left': oldPos }); $('.tdData').css( {'backgroundPosition': oldPos } ); if (highlightArea) @@ -1682,71 +1703,72 @@ if (imageV2.inPlaceUpdate) { var pos = parsePosition(genomePos.get()); imageV2.navigateInPlace("position=" + encodeURIComponent(pos.chrom + ":" + pos.start + "-" + pos.end), null, true); } else { document.TrackHeaderForm.submit(); } return true; // Make sure the setTimeout below is not called. } // Just a normal scroll within a >1X image if (prevX !== newX) { prevX = newX; if (!only1xScrolling) { - //panAdjustHeight(newX); // NOTE: This will resize image after scrolling. Do we want to while scrolling? - // This is important, since AJAX could lead to reinit after this within bounds scroll + //panAdjustHeight(newX); // Will resize image AFTER scrolling. + // Important, since AJAX could lead to reinit after this within bounds scroll hgTracks.imgBoxPortalOffsetX = (prevX * -1) - hgTracks.imgBoxLeftLabel; hgTracks.imgBoxPortalLeft = newX.toString() + "px"; } } } } }); // end of this.each(function(){ function panUpdatePosition(newOffsetX,bounded) { // Updates the 'position/search" display with change due to panning - var closedPortalStart = hgTracks.imgBoxPortalStart + 1; // Correction for half open portal coords + var closedPortalStart = hgTracks.imgBoxPortalStart + 1; // Correction for half open var portalWidthBases = hgTracks.imgBoxPortalEnd - closedPortalStart; var portalScrolledX = hgTracks.imgBoxPortalOffsetX+hgTracks.imgBoxLeftLabel + newOffsetX; var recalculate = false; var newPortalStart = 0; if (hgTracks.revCmplDisp) - newPortalStart = closedPortalStart + - Math.round(portalScrolledX*hgTracks.imgBoxBasesPerPixel); // As offset goes down, so do bases seen. + newPortalStart = closedPortalStart + // As offset goes down, so do bases seen. + Math.round(portalScrolledX*hgTracks.imgBoxBasesPerPixel); else - newPortalStart = closedPortalStart - - Math.round(portalScrolledX*hgTracks.imgBoxBasesPerPixel); // As offset goes down, bases seen goes up! + newPortalStart = closedPortalStart - // As offset goes down, bases seen goes up! + Math.round(portalScrolledX*hgTracks.imgBoxBasesPerPixel); if (newPortalStart < hgTracks.chromStart && bounded) { // Stay within bounds newPortalStart = hgTracks.chromStart; recalculate = true; } var newPortalEnd = newPortalStart + portalWidthBases; if (newPortalEnd > hgTracks.chromEnd && bounded) { newPortalEnd = hgTracks.chromEnd; newPortalStart = newPortalEnd - portalWidthBases; recalculate = true; } if (newPortalStart > 0) { var newPos = hgTracks.chromName + ":" + commify(newPortalStart) + "-" + commify(newPortalEnd); genomePos.set(newPos, 0); // 0 means no need to change the size } - if (recalculate && hgTracks.imgBoxBasesPerPixel > 0) { // Need to recalculate X for bounding drag + if (recalculate && hgTracks.imgBoxBasesPerPixel > 0) { + // Need to recalculate X for bounding drag portalScrolledX = (closedPortalStart - newPortalStart) / hgTracks.imgBoxBasesPerPixel; newOffsetX = portalScrolledX - (hgTracks.imgBoxPortalOffsetX+hgTracks.imgBoxLeftLabel); } return newOffsetX; } function mapTopAndBottom(mapName,east,west) { // Find the top and bottom px given left and right boundaries var mapPortal = { top: -10, bottom: -10 }; var items = $("map[name='"+mapName+"']").children(); if ($(items).length>0) { $(items).each(function(t) { var loc = this.coords.split(","); var aleft = parseInt(loc[0]); var aright = parseInt(loc[2]); @@ -1808,50 +1830,50 @@ if (btn.length > 0) { $(btn).height( mapPortal.bottom - mapPortal.top + titlePx); } else { btn = $("#img_btn_"+imgId[2]); if (btn.length > 0) { $(btn).parent().height( mapPortal.bottom - mapPortal.top + titlePx); $(btn).css( {'top': top.toString() + "px" }); } } } } }); dragMaskResize(); // Resizes the dragMask to match current image size } - function dragMaskShow() { // Sets up the dragMask to show grabbing cursor within image and not allowed north and south of image - + function dragMaskShow() + { // Sets up the dragMask to show grabbing cursor within image + // and not allowed north and south of image var imgTbl = $('#imgTbl'); // Find or create the waitMask (which masks the whole page) var dragMask = normed($('div#dragMask')); if (!dragMask) { $("body").prepend("<div id='dragMask' class='waitMask'></div>"); dragMask = $('div#dragMask'); } $('body').css('cursor','not-allowed'); $(dragMask).css('cursor',"url(../images/grabbing.cur),w-resize"); $(dragMask).css({opacity:0.0,display:'block', top: $(imgTbl).position().top.toString() + 'px', height: $(imgTbl).height().toString() + 'px' }); - //$(dragMask).css({opacity:0.4,backgroundColor:'gray',zIndex:999}); // temporarily so I can see it } - function dragMaskResize() { // Resizes dragMask (called when image is dynamically resized in >1x scrolling) - + function dragMaskResize() + { // Resizes dragMask (called when image is dynamically resized in >1x scrolling) var imgTbl = $('#imgTbl'); // Find or create the waitMask (which masks the whole page) var dragMask = normed($('div#dragMask')); if (dragMask) { $(dragMask).height( $(imgTbl).height() ); } } function dragMaskClear() { // Clears the dragMask $('body').css('cursor','auto'); var dragMask = normed($('#dragMask')); if (dragMask) $(dragMask).hide(); } @@ -1874,70 +1896,74 @@ } } }; /////////////////////////////////////// //// rightClick (aka context menu) //// /////////////////////////////////////// var rightClick = { menu: null, selectedMenuItem: null, // currently choosen context menu item (via context menu). floatingMenuItem: null, currentMapItem: null, - supportZoomCodon: false, // turn on experimental zoom-to-codon functionality (currently only on in larry's tree). + supportZoomCodon: false, // turns on experimental feature (currently only in larry's tree). makeMapItem: function (id) - { // Create a dummy mapItem on the fly (for objects that don't have corresponding entry in the map). + { // Create a dummy mapItem on the fly + // (for objects that don't have corresponding entry in the map). if (id && id.length > 0 && hgTracks.trackDb) { var title; var rec = hgTracks.trackDb[id]; if (rec) { title = rec.shortLabel; } else { title = id; } return {id: id, title: "configure " + title}; } else { return null; } }, findMapItem: function (e) { // Find mapItem for given event; returns item object or null if none found. if (rightClick.currentMapItem) { return rightClick.currentMapItem; } - // rightClick for non-map items that can be resolved to their parent tr and then trackName (e.g. items in gray bar) + // rightClick for non-map items that can be resolved to their parent tr and + // then trackName (e.g. items in gray bar) var tr = $( e.target ).parents('tr.imgOrd'); if ($(tr).length === 1) { var a = /tr_(.*)/.exec($(tr).attr('id')); // voodoo if (a && a[1]) { var id = a[1]; return rightClick.makeMapItem(id); } } return null; }, windowOpenFailedMsg: function () { - warn("Your web browser prevented us from opening a new window.\n\nPlease change your browser settings to allow pop-up windows from " + document.domain + "."); + warn("Your web browser prevented us from opening a new window.\n\n" + + "Please change your browser settings to allow pop-up windows from " + + document.domain + "."); }, handleZoomCodon: function (response, status) { var json = JSON.parse(response); if (json.pos) { genomePos.set(json.pos, 3); if (document.TrackForm) document.TrackForm.submit(); else document.TrackHeaderForm.submit(); } else { alert(json.error); } }, @@ -1946,32 +1972,32 @@ { // handles view image response, which must get new image without imageV2 gimmickery jQuery('body').css('cursor', ''); var str = "<IMG[^>]*SRC='([^']+)'"; var reg = new RegExp(str); var a = reg.exec(response); if (a && a[1]) { if ( ! window.open(a[1]) ) { rightClick.windowOpenFailedMsg(); } return; } warn("Couldn't parse out img src"); }, myPrompt: function (msg, callback) - { // replacement for prompt; avoids misleading/confusing security warnings which are caused by prompt in IE 7+ - // callback is called if user presses "OK". + { // replacement for prompt; avoids misleading/confusing security warnings which are caused + // by prompt in IE 7+. Callback is called if user presses "OK". $("body").append("<div id = 'myPrompt'><div id='dialog' title='Basic dialog'><form>" + msg + "<input id='myPromptText' value=''></form>"); $("#myPrompt").dialog({ modal: true, closeOnEscape: true, buttons: { "OK": function() { var myPromptText = $("#myPromptText").val(); $(this).dialog("close"); callback(myPromptText); } } }); }, hit: function (menuItemClicked, menuObject, cmd, args) @@ -2040,34 +2066,35 @@ var newPosition = genomePos.setByCoordinates(chrom, chromStart, chromEnd); var reg = new RegExp("hgg_gene=([^&]+)"); var b = reg.exec(href); var name; // pull item name out of the url so we can set hgFind.matches (redmine 3062) if (b && b[1]) { name = b[1]; } else { reg = new RegExp("[&?]i=([^&]+)"); b = reg.exec(href); if (b && b[1]) { name = b[1]; } } if (imageV2.inPlaceUpdate) { - // XXXX This attempt to "update whole track image in place" didn't work for a variety of reasons - // (e.g. safari doesn't parse map when we update on the client side), so this is currently dead code. - // However, this now works in all other browsers, so we may turn this on for non-safari browsers - // (see redmine #4667). + // XXXX This attempt to "update whole track image in place" didn't work + // for a variety of reasons (e.g. safari doesn't parse map when we + // update on the client side), so this is currently dead code. + // However, this now works in all other browsers, so we may turn this + // on for non-safari browsers (see redmine #4667). jQuery('body').css('cursor', ''); var data = "hgt.trackImgOnly=1&hgt.ideogramToo=1&position=" + newPosition + "&hgsid=" + getHgsid(); if (name) data += "&hgFind.matches=" + name; $.ajax({ type: "GET", url: "../cgi-bin/hgTracks", data: cart.addUpdatesToUrl(data), dataType: "html", trueSuccess: imageV2.updateImgAndMap, success: catchErrorOrDispatch, error: errorHandler, cmd: cmd, loadingId: showLoadingImage("imgTbl"), @@ -2099,76 +2126,72 @@ } rightClick.myPrompt(msg, function(results) { $.ajax({ type: "GET", url: "../cgi-bin/hgApi", data: cart.varsToUrlData({ 'db': getDb(), 'cmd': ajaxCmd, 'num': results, 'table': args.table, 'name': args.name }), trueSuccess: rightClick.handleZoomCodon, success: catchErrorOrDispatch, error: errorHandler, cache: true }); }); } else if (cmd === 'hgTrackUi_popup') { - popUp.hgTrackUi( rightClick.selectedMenuItem.id, false ); // Launches the popup but shields the ajax with a waitOnFunction + // Launches the popup but shields the ajax with a waitOnFunction + popUp.hgTrackUi( rightClick.selectedMenuItem.id, false ); } 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); } else if (cmd === 'viewImg') { - // Fetch a new copy of track img and show it to the user in another window. This code assume we have updated - // remote cart with all relevant chages (e.g. drag-reorder). -/* Here's how to do this more directly with hgRenderTracks: - if ( ! window.open("../cgi-bin/hgRenderTracks?hgt.internal=1&hgsid=" + getHgsid()) ) { - rightClick.windowOpenFailedMsg(); - } - return; -*/ + // Fetch a new copy of track img and show it to the user in another window. This code + // assume we have updated remote cart with all relevant chages (e.g. drag-reorder). jQuery('body').css('cursor', 'wait'); $.ajax({ type: "GET", url: "../cgi-bin/hgTracks", data: cart.varsToUrlData({ 'hgt.imageV1': '1','hgt.trackImgOnly': '1', 'hgsid': getHgsid() }), dataType: "html", trueSuccess: rightClick.handleViewImg, success: catchErrorOrDispatch, error: errorHandler, cmd: cmd, cache: false }); } else if (cmd === 'openLink' || cmd === 'followLink') { href = rightClick.selectedMenuItem.href; var vars = new Array("c", "l", "r", "db"); var valNames = new Array("chromName", "winStart", "winEnd"); for (var i in vars) { - // make sure the link contains chrom and window width info (necessary b/c we are stripping hgsid and/or the cart may be empty); + // make sure the link contains chrom and window width info + // (necessary b/c we are stripping hgsid and/or the cart may be empty); // but don't add chrom to wikiTrack links (see redmine #2476). 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; } } @@ -2190,49 +2213,51 @@ if (rightClick.floatingMenuItem) { // This doesn't work. $('#img_data_' + rightClick.floatingMenuItem).parent().restartFloat(); // This does work $.floatMgr.FOArray = []; } rightClick.floatingMenuItem = id; rightClick.reloadFloatingItem(); imageV2.requestImgUpdate(id, "hgt.transparentImage=0", ""); } } else if (cmd === 'hideSet') { row = $( 'tr#tr_' + id ); rows = dragReorder.getContiguousRowSet(row); if (rows && rows.length > 0) { var varsToUpdate = {}; - for (var ix=rows.length - 1; ix >= 0; ix--) { // from bottom, just in case remove screws with us + // from bottom up, just in case remove screws with us + for (var ix=rows.length - 1; ix >= 0; ix--) { var rowId = $(rows[ix]).attr('id').substring('tr_'.length); // Remove subtrack level vis and explicitly uncheck. varsToUpdate[rowId] = '[]'; varsToUpdate[rowId+'_sel'] = 0; $(rows[ix]).remove(); } if (objNotEmpty(varsToUpdate)) { cart.setVarsObj(varsToUpdate); } imageV2.afterImgChange(true); } } else if (cmd === 'hideComposite') { rec = hgTracks.trackDb[id]; if (tdbIsSubtrack(rec)) { row = $( 'tr#tr_' + id ); rows = dragReorder.getCompositeSet(row); + // from bottom up, just in case remove screws with us if (rows && rows.length > 0) { - for (var rIx=rows.length - 1; rIx >= 0; rIx--) { // from bottom, just in case remove screws with us + for (var rIx=rows.length - 1; rIx >= 0; rIx--) { $(rows[rIx]).remove(); } selectUpdated = vis.update(rec.parentTrack, 'hide'); cart.setVars( [rec.parentTrack], ['hide']); imageV2.afterImgChange(true); } } } else if (cmd === 'jumpToHighlight') { // If highlight exists for this assembly, jump to it if (hgTracks.highlight) { var newPos = parsePositionWithDb(hgTracks.highlight); if (newPos && newPos.db === getDb()) { if ( $('#highlightItem').length === 0) { // not visible? jump to it var curPos = parsePosition(genomePos.get()); var diff = ((curPos.end - curPos.start) - (newPos.end - newPos.start)); if (diff > 0) { // new position is smaller then current, then center it @@ -2252,37 +2277,40 @@ } } else if (cmd === 'removeHighlight') { hgTracks.highlight = null; cart.setVarsObj({ 'highlight': '[]' }); imageV2.highlightRegion(); } 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. Others, just set vis hide. - if(tdbIsSubtrack(rec)) - cart.setVars( [ id, id+"_sel" ], [ '[]', 0 ] ); // Remove subtrack level vis and explicitly uncheck. - else if(tdbIsFolderContent(rec)) - cart.setVars( [ id, id+"_sel" ], [ 'hide', 0 ] ); // supertrack children need to have _sel set to trigger superttrack reshaping - else - cart.setVars([id], ['hide']); + // Subtracks controlled by 2 settings so del vis and set sel=0. + if (tdbIsSubtrack(rec)) { + // Remove subtrack level vis and explicitly uncheck. + cart.setVars( [ id, id+"_sel" ], [ '[]', 0 ] ); + } else if (tdbIsFolderContent(rec)) { + // supertrack children need to have _sel set to trigger superttrack reshaping + cart.setVars( [ id, id+"_sel" ], [ 'hide', 0 ] ); + } else { + cart.setVars([id], ['hide']); // Others, just set vis hide. + } $(document.getElementById('tr_' + id)).remove(); imageV2.afterImgChange(true); } else if (!imageV2.mapIsUpdateable) { jQuery('body').css('cursor', 'wait'); if (selectUpdated) { // assert(document.TrackForm); document.TrackForm.submit(); } else { // add a hidden with new visibility value var form = $(document.TrackHeaderForm); $("<input type='hidden' name='"+id+"'value='"+cmd+"'>").appendTo(form); document.TrackHeaderForm.submit(); } } else { imageV2.requestImgUpdate(id, id + "=" + cmd, "", cmd); @@ -2295,133 +2323,133 @@ return function(menuItemClicked, menuObject) { rightClick.hit(menuItemClicked, menuObject, title); return true; }; }, reloadFloatingItem: function () { // currently dead (experimental code) if (rightClick.floatingMenuItem) { $('#img_data_' + rightClick.floatingMenuItem).parent().makeFloat( {x:"current",y:"current", speed: 'fast', alwaysVisible: true, alwaysTop: true}); } }, makeImgTag: function (img) { // Return img tag with explicit dimensions for img (dimensions are currently hardwired). - // This fixes the "weird shadow problem when first loading the right-click menu" seen in FireFox 3.X, - // which occurred b/c FF doesn't actually fetch the image until the menu is being shown. + // This fixes the "weird shadow problem when first loading the right-click menu" + // seen in FireFox 3.X, which occurred b/c FF doesn't actually fetch the image until + // the menu is being shown. return "<img style='width:16px; height:16px; border-style:none;' src='../images/" + img + "' />"; }, load: function (img) { - rightClick.menu = img.contextMenu( - function() { + rightClick.menu = img.contextMenu(function() { popUp.cleanup(); // Popup box is not getting closed properly so must do it here if ( ! rightClick.selectedMenuItem ) // This is literally an edge case so ignore return; - var o; // TODO: Break this giant routine with shared vars into some sub-functions var str; + var o; // TODO: Break this giant routine with shared vars into some sub-functions + var str; var rec = null; var menu = []; var selectedImg = rightClick.makeImgTag("greenChecksm.png"); var blankImg = rightClick.makeImgTag("invisible16.png"); var done = false; if (rightClick.selectedMenuItem && rightClick.selectedMenuItem.id) { var href = rightClick.selectedMenuItem.href; var isHgc, isGene; if (href) { isGene = href.match("hgGene"); isHgc = href.match("hgc"); } var id = rightClick.selectedMenuItem.id; rec = hgTracks.trackDb[id]; var offerHideSubset = false; var offerHideComposite = false; var offerSingles = true; var row = $( 'tr#tr_' + id ); if (row) { var btn = $(row).find('p.btnBlue'); // btnBlue means cursor over left button if (btn.length === 1) { var compositeSet = dragReorder.getCompositeSet(row); - if (compositeSet && compositeSet.length > 0) { // There is a composite set + if (compositeSet && compositeSet.length > 0) { // There is composite set offerHideComposite = true; $( compositeSet ).find('p.btn').addClass('blueButtons');// blue persists var subSet = dragReorder.getContiguousRowSet(row); if (subSet && subSet.length > 1) { offerSingles = false; if (subSet.length < compositeSet.length) { offerHideSubset = true; $( subSet ).addClass("greenRows"); // green persists } } } } } // First option is hide sets if (offerHideComposite) { if (offerHideSubset) { o = {}; o[blankImg + " hide track subset (green)"] = { onclick: rightClick.makeHitCallback('hideSet')}; - //o[rightClick.makeImgTag("highliteGreenX.png") + " hide track subset"] = {onclick: rightClick.makeHitCallback('hideSet')}; menu.push(o); } o = {}; str = blankImg + " hide track set"; if (offerHideSubset) str += " (blue)"; o[str] = {onclick: rightClick.makeHitCallback('hideComposite')}; - //o[rightClick.makeImgTag("btnBlueX.png") + " hide track set"] = {onclick: rightClick.makeHitCallback('hideComposite')}; menu.push(o); } // Second set of options: visibility for single track if (offerSingles) { if (offerHideComposite) menu.push($.contextMenu.separator); // XXXX what if select is not available (b/c trackControlsOnMain is off)? // Move functionality to a hidden variable? var select = $("select[name=" + escapeJQuerySelectorChars(id) + "]"); - if (select.length > 1) // Not really needed if $('#hgTrackUiDialog').html(""); has worked + if (select.length > 1) + // Not really needed if $('#hgTrackUiDialog').html(""); has worked select = [ $(select)[0] ]; var cur = $(select).val(); if (cur) { $(select).children().each(function(index, o) { var title = $(this).val(); str = blankImg + " " + title; if (title === cur) str = selectedImg + " " + title; o = {}; o[str] = {onclick: function (menuItemClicked, menuObject) { rightClick.hit(menuItemClicked, menuObject, title); return true;}}; menu.push(o); }); done = true; } else { if (rec) { // XXXX check current state from a hidden variable. var visStrings = new Array("hide","dense","squish","pack","full"); for (var i in visStrings) { - // XXXX use maxVisibility and change hgTracks so it can hide subtracks + // use maxVisibility and change hgTracks so it can hide subtracks o = {}; str = blankImg + " " + visStrings[i]; if (rec.canPack || (visStrings[i] !== "pack" && visStrings[i] !== "squish")) { if (rec.localVisibility) { if (visStrings[i] === rec.localVisibility) { str = selectedImg + " " + visStrings[i]; } } else if (visStrings[i] === vis.enumOrder[rec.visibility]) { str = selectedImg + " " + visStrings[i]; } o[str] = { onclick: rightClick.makeHitCallback(visStrings[i]) }; menu.push(o); @@ -2432,31 +2460,33 @@ } } if (done) { o = {}; var any = false; var title = rightClick.selectedMenuItem.title || "feature"; var maxLength = 60; if (title.length > maxLength) { title = title.substring(0, maxLength) + "..."; } if (isGene || isHgc || id === "wikiTrack") { // Add "Open details..." item var displayItemFunctions = false; if (rec) { - if (rec.type.indexOf("wig") === 0 || rec.type.indexOf("bigWig") === 0 || id === "wikiTrack") { + if (rec.type.indexOf("wig") === 0 + || rec.type.indexOf("bigWig") === 0 + || id === "wikiTrack") { displayItemFunctions = false; } else if (rec.type.indexOf("expRatio") === 0) { displayItemFunctions = title !== "zoomInMore"; } else { displayItemFunctions = true; } } 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] = @@ -2515,36 +2545,38 @@ return true; } }; } o[rightClick.makeImgTag("bookOut.png")+ " Open details page in new window..."] = { onclick: function(menuItemClicked, menuObject) { rightClick.hit(menuItemClicked, menuObject, "openLink"); return true; } }; any = true; } if (href && href.length > 0) { // Add "Show details..." item if (title.indexOf("Click to alter ") === 0) { // suppress the "Click to alter..." items - } else if (rightClick.selectedMenuItem.href.indexOf("cgi-bin/hgTracks") !== -1) { + } else if (rightClick.selectedMenuItem.href.indexOf("cgi-bin/hgTracks") + !== -1) { // suppress menu items for hgTracks links (e.g. Next/Prev map items). } else { var item; if (title === "zoomInMore") - // avoid showing menu item that says "Show details for zoomInMore..." (redmine 2447) + // avoid showing menu item that says + // "Show details for zoomInMore..." (redmine 2447) item = rightClick.makeImgTag("book.png") + " Show details..."; else item = rightClick.makeImgTag("book.png")+" Show details for "+ title + "..."; o[item] = {onclick: function(menuItemClicked, menuObject) { rightClick.hit(menuItemClicked,menuObject,"followLink"); return true; } }; any = true; } } if (any) { menu.push($.contextMenu.separator); menu.push(o); } @@ -2644,31 +2676,32 @@ } }; ////////////////////////////////// //// popup (aka modal dialog) //// ////////////////////////////////// var popUp = { trackName: "", trackDescriptionOnly: false, saveAllVars: null, cleanup: function () { // Clean out the popup box on close if ($('#hgTrackUiDialog').html().length > 0 ) { - $('#hgTrackUiDialog').html(""); // clear out html after close to prevent problems caused by duplicate html elements + // clear out html after close to prevent problems caused by duplicate html elements + $('#hgTrackUiDialog').html(""); popUp.trackName = ""; //set to defaults popUp.trackDescriptionOnly = false; popUp.saveAllVars = null; } }, _uiDialigRequest: function (trackName,descriptionOnly) { // popup cfg dialog popUp.trackName = trackName; var myLink = "../cgi-bin/hgTrackUi?g=" + trackName + "&hgsid=" + getHgsid() + "&db=" + getDb(); popUp.trackDescriptionOnly = descriptionOnly; if (popUp.trackDescriptionOnly) myLink += "&descriptionOnly=1"; @@ -2684,47 +2717,47 @@ } myLink += "&ajax=1"; $.ajax({ type: "GET", url: cart.addUpdatesToUrl(myLink), dataType: "html", trueSuccess: popUp.uiDialog, success: catchErrorOrDispatch, error: errorHandler, cmd: rightClick.selectedMenuItem, cache: false }); }, hgTrackUi: function (trackName,descriptionOnly) - { - waitOnFunction( popUp._uiDialigRequest, trackName, descriptionOnly ); // Launches the popup but shields the ajax with a waitOnFunction + { // Launches the popup but shields the ajax with a waitOnFunction + waitOnFunction( popUp._uiDialigRequest, trackName, descriptionOnly ); }, uiDialogOk: function (popObj, trackName) { // When hgTrackUi Cfg popup closes with ok, then update cart and refresh parts of page var rec = hgTracks.trackDb[trackName]; - var subtrack = tdbIsSubtrack(rec) ? trackName :undefined; // If subtrack then vis rules differ - var allVars = getAllVars($('#hgTrackUiDialog'), subtrack );// For unknown reasons IE8 fails to find $('#pop'), occasionally + var subtrack = tdbIsSubtrack(rec) ? trackName : undefined; // subtrack vis rules differ + // For unknown reasons IE8 fails to find $('#pop'), occasionally + var allVars = getAllVars($('#hgTrackUiDialog'), subtrack ); var changedVars = varHashChanges(allVars,popUp.saveAllVars); - //warn("cfgVars:"+varHashToQueryString(changedVars)); var newVis = changedVars[trackName]; - var hide = (newVis && (newVis === 'hide' || newVis === '[]')); // subtracks do not have "hide", thus '[]' + // 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); - //if(hide) // TODO: When findTracks or config page has cfg popup, then vis change needs to be handled in page here } else { // On image page if (hide) { if (objNotEmpty(changedVars)) cart.setVarsObj(changedVars); $(document.getElementById('tr_' + trackName)).remove(); imageV2.afterImgChange(true); } 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) { @@ -2740,122 +2773,127 @@ uiDialog: function (response, status) { // Take html from hgTrackUi 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(/<a /ig, "<a target='_blank' "); var cleanHtml = response; cleanHtml = stripJsFiles(cleanHtml,true); // DEBUG msg with true cleanHtml = stripCssFiles(cleanHtml,true); // DEBUG msg with true cleanHtml = stripJsEmbedded(cleanHtml,true);// DEBUG msg with true $('#hgTrackUiDialog').html("<div id='pop' style='font-size:.9em;'>"+ cleanHtml +"</div>"); // Strategy for poups 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 + // - 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 hgTracks 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 + // - 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. if ( ! popUp.trackDescriptionOnly ) { - var subtrack = tdbIsSubtrack(hgTracks.trackDb[popUp.trackName]) ? popUp.trackName :""; // If subtrack then vis rules differ - popUp.saveAllVars = getAllVars( $('#hgTrackUiDialog'), subtrack ); // Saves the vars that may get changed by the popup cfg. + // If subtrack then vis rules differ + var subtrack = tdbIsSubtrack(hgTracks.trackDb[popUp.trackName]) ? popUp.trackName :""; + // Saves the original vars (and vals) that may get changed by the popup cfg. + popUp.saveAllVars = getAllVars( $('#hgTrackUiDialog'), subtrack ); - // -- popup.ready() -- Here is the place to do things that might otherwise go into a $('#pop').ready() routine! + // -- popup.ready() -- Here is the place to do things that might otherwise go + // into a $('#pop').ready() routine! } // Searching for some selblance of size suitability var popMaxHeight = ($(window).height() - 40); var popMaxWidth = ($(window).width() - 40); var popWidth = 740; if (popWidth > popMaxWidth) popWidth = popMaxWidth; $('#hgTrackUiDialog').dialog({ ajaxOptions: { // This doesn't work cache: true }, - resizable: true, - height: (popUp.trackDescriptionOnly ? popMaxHeight : 'auto'), // Let description scroll vertically + resizable: true, // Let description scroll vertically + height: (popUp.trackDescriptionOnly ? popMaxHeight : 'auto'), width: popWidth, minHeight: 200, minWidth: 700, maxHeight: popMaxHeight, maxWidth: popMaxWidth, modal: true, closeOnEscape: true, autoOpen: false, buttons: { "OK": function() { if ( ! popUp.trackDescriptionOnly ) popUp.uiDialogOk($('#pop'), popUp.trackName); $(this).dialog("close"); }}, - // popup.ready() doesn't seem to work in open. So there is no need for open at this time. - //open: function() { - // var subtrack = tdbIsSubtrack(hgTracks.trackDb[popUp.trackName]) ? popUp.trackName :""; // If subtrack then vis rules differ - // popUp.saveAllVars = getAllVars( $('#pop'), subtrack ); - //}, + // popup.ready() doesn't seem to work in open. + open: function () { if ( ! popUp.trackDescriptionOnly ) { $('#hgTrackUiDialog').find('.filterBy,.filterComp').each( function(i) { if ($(this).hasClass('filterComp')) ddcl.setup(this); else ddcl.setup(this, 'noneIsAll'); } ); } }, close: function() { popUp.cleanup(); } }); + // FIXME: Why are open and close no longer working!!! if (popUp.trackDescriptionOnly) { var myWidth = $(window).width() - 300; if (myWidth > 900) myWidth = 900; $('#hgTrackUiDialog').dialog("option", "maxWidth", myWidth); $('#hgTrackUiDialog').dialog("option", "width", myWidth); $('#hgTrackUiDialog').dialog('option' , 'title' , hgTracks.trackDb[popUp.trackName].shortLabel+" Track Description"); $('#hgTrackUiDialog').dialog('open'); var buttOk = $('button.ui-state-default'); if ($(buttOk).length === 1) $(buttOk).focus(); } else { $('#hgTrackUiDialog').dialog('option' , 'title' , hgTracks.trackDb[popUp.trackName].shortLabel+" Track Settings"); $('#hgTrackUiDialog').dialog('open'); } } }; /////////////////////////////// //// imageV2 (aka imgTbl) //// /////////////////////////////// var imageV2 = { - enabled: false, // Will be set to true unless advancedJavascriptFeatures is turned off OR if track search of config page + enabled: false, // Will be set to true unless advancedJavascriptFeatures + // is turned off OR if track search of config page imgTbl: null, // formerly "trackImgTbl" The imgTbl or null if non-imageV2. - inPlaceUpdate: false, // modified based on value of hgTracks.inPlaceUpdate and mapIsUpdateable + inPlaceUpdate: false, // modified based on value of hgTracks.inPlaceUpdate & mapIsUpdateable mapIsUpdateable:true, - lastTrack: null, // formerly (lastMapItem) this is used to try to keep what the last track the cursor passed. + lastTrack: null, // formerly (lastMapItem) this is used to try to keep what the + // last track the cursor passed. markAsDirtyPage: function () { // Page is marked as dirty so that the back-button knows page doesn't match cart var dirty = normed($('#dirty')); if (dirty) $(dirty).val('true'); }, markAsCleanPage: function () { // Clears signal that history may be out of sync with cart. var dirty = normed($('#dirty')); if (dirty) $(dirty).val('false'); }, @@ -2866,52 +2904,52 @@ var dirty = normed($('#dirty')); if (dirty && $(dirty).val() === 'true') return true; return false; }, updateTiming: function (response) { // update measureTiming text on current page based on what's in the response var reg = new RegExp("(<span class='timing'>.+?</span>)", "g"); var strs = []; for (var a = reg.exec(response); a && a[1]; a = reg.exec(response)) { strs.push(a[1]); } if (strs.length > 0) { $('.timing').remove(); - for(var i = strs.length; i > 0; i--) { - $('body').prepend(strs[i - 1]); + for (var ix = strs.length; ix > 0; ix--) { + $('body').prepend(strs[ix - 1]); } } reg = new RegExp("(<span class='trackTiming'>[\\S\\s]+?</span>)"); a = reg.exec(response); if (a && a[1]) { $('.trackTiming').replaceWith(a[1]); } }, loadSuggestBox: function () { if ($('#positionInput').length) { suggestBox.init(getDb(), $("#suggestTrack").length > 0, function (item) { genomePos.set(item.id, commify(getSizeFromCoordinates(item.id))); }, function (position) { genomePos.set(position, commify(getSizeFromCoordinates(position))); }); - // Make sure suggestTrack is visible when user chooses something via gene select (#3484). + // Make sure suggestTrack is visible when user chooses via gene select (#3484). if ($("#suggestTrack").length) { $(document.TrackForm || document.TrackHeaderForm).submit(function(event) { if ($('#hgFindMatches').length) { vis.makeTrackVisible($("#suggestTrack").val()); } }); } } }, afterImgChange: function (dirty) { // Standard things to do when manipulations change image without ajax update. dragReorder.init(); dragSelect.load(false); imageV2.highlightRegion(); @@ -3134,37 +3172,39 @@ valid = true; } else { warn("Invalid hgTracks.trackDb received from the server"); } } else { valid = true; } } if (valid) { if (imageV2.enabled && this.id && this.cmd && this.cmd !== 'wholeImage' && this.cmd !== 'selectWholeGene') { // Extract <TR id='tr_ID'>...</TR> and update appropriate row in imgTbl; - // this updates src in img_left_ID, img_center_ID and img_data_ID and map in map_data_ID + // this updates src in img_left_ID, img_center_ID and img_data_ID + // and map in map_data_ID var id = this.id; if (imageV2.updateImgForId(response, id, false)) { imageV2.afterReload(id); } else { warn("Couldn't parse out new image for id: " + id); - //alert("Couldn't parse out new image for id: " + id+"BR"+response); // Very helpful + // Very helpful when debugging and alert doesn't render the html: + //alert("Couldn't parse out new image for id: " + id+"BR"+response); } } else { if (imageV2.enabled) { // Implement in-place updating of hgTracks image genomePos.setByCoordinates(newJson.chromName, newJson. winStart + 1, newJson.winEnd); $("input[name='c']").val(newJson.chromName); $("input[name='l']").val(newJson.winStart); $("input[name='r']").val(newJson.winEnd); if (newJson.cgiVersion !== oldJson.cgiVersion) { // Must reload whole page because of a new version on the server; // this should happen very rarely. Note that we have already updated // position based on the user's action. imageV2.fullReload(); @@ -3294,35 +3334,36 @@ } data = data + this.name + "=" + cmd; } } }); if (data.length > 0) { imageV2.navigateInPlace(data, null, false); } return false; } else { return true; } }, navigateInPlace: function (params, disabledEle, keepCurrentTrackVisible) - { - // request an hgTracks image, using params + { // request an hgTracks image, using params // disabledEle is optional; this element will be enabled when update is complete - // If keepCurrentTrackVisible is true, we try to maintain relative position of the item under the mouse after the in-place update. + // If keepCurrentTrackVisible is true, we try to maintain relative position of the item + // under the mouse after the in-place update. // Tim thinks we should consider disabling all UI input while we are doing in-place update. + // TODO: waitOnFuction? jQuery('body').css('cursor', 'wait'); var currentId, currentIdYOffset; if (keepCurrentTrackVisible) { var item = rightClick.currentMapItem || imageV2.lastTrack; if (item) { var top = $(document.getElementById("tr_" + item.id)).position().top; if (top >= $(window).scrollTop() || top < $(window).scrollTop() + $(window).height()) { // don't bother if the item is not currently visible. currentId = item.id; currentIdYOffset = top - $(window).scrollTop(); } } } $.ajax({ @@ -3371,31 +3412,31 @@ else leftPixels += (clippedStartBases - hgTracks.imgBoxPortalStart) * pixelsPerBase; // Impossible to get perfect... Okay to overrun by a pixel on each side leftPixels = Math.floor(leftPixels); widthPixels = Math.ceil(widthPixels); if (widthPixels < 2) { widthPixels = 3; leftPixels -= 1; } var area = jQuery("<div id='highlightItem' class='highlightItem'></div>"); $(area).css({ backgroundColor: hexColor, // display: 'none' left: leftPixels + 'px', top: $('#imgTbl').offset().top + 1 + 'px', width: widthPixels + 'px', height: $('#imgTbl').css('height') }); - $(area).data({leftPixels: leftPixels, widthPixels: widthPixels});// needed for dragScroll + $(area).data({leftPixels: leftPixels, widthPixels: widthPixels});// needed by dragScroll // Larry originally appended to imgTbl, but discovered that doesn't work on IE 8 and 9. $('body').append($(area)); // z-index is done in css class, so highlight is beneath transparent data images. // NOTE: ideally highlight would be below transparent blue-lines, but THAT is a // background-image so z-index can't get below it! PS/PDF looks better for blue-lines! } }, backSupport: (window.History.enabled !== undefined), // support of r back button via: history: null, // jquery.history.js and HTML5 history API setupHistory: function () { // Support for back-button using jquery.history.js. // Sets up the history and initializes a state. @@ -3523,32 +3564,34 @@ imageV2.history.pushState({position: newPos, hgsid: + getHgsid()},title, "hgTracks?db=" + getDb() + "&position=" + newPos + "&hgsid="+sid); } } } }; ////////////////////// //// track search //// ////////////////////// var trackSearch = { searchKeydown: function (event) { if (event.which === 13) { - // Required to fix problem on IE and Safari where value of hgt_tSearch is "-" (i.e. not "Search"). - $("input[name=hgt_tsPage]").val(0); // NOTE: must match TRACK_SEARCH_PAGER in hg/inc/searchTracks.h + // Required to fix problem on IE and Safari where value of hgt_tSearch is "-" + // (i.e. not "Search"). + // NOTE: must match TRACK_SEARCH_PAGER in hg/inc/searchTracks.h + $("input[name=hgt_tsPage]").val(0); $('#trackSearch').submit(); // This doesn't work with IE or Safari. // $('#searchSubmit').click(); } }, init: function () { // Track search uses tabs if ($("#tabs").length > 0) { // Search page specific code var val = $('#currentTab').val(); $("#tabs").tabs({ show: function(event, ui) { @@ -3579,31 +3622,32 @@ // The page may be reached via browser history (back button) // If so, then this code should detect if the image has been changed via js/ajax // and will reload the image if necessary. // NOTE: this is needed for IE but other browsers can detect the dirty page much earlier if (!imageV2.backSupport) { if (imageV2.isDirtyPage()) { // mark as non dirty to avoid infinite loop in chrome. imageV2.markAsCleanPage(); jQuery('body').css('cursor', 'wait'); window.location = "../cgi-bin/hgTracks?hgsid=" + getHgsid(); return false; } } initVars(); imageV2.loadSuggestBox(); - // Convert map AREA gets to post the form, ensuring that cart variables are kept up to date (but turn this off for search form). + // Convert map AREA gets to post the form, ensuring that cart variables are kept + // up to date (but turn this off for search form). if ($("FORM").length > 0 && $('#trackSearch').length === 0) { var allLinks = $('a'); $( allLinks ).unbind('click'); $( allLinks ).click( posting.saveSettings ); } if ($('#pdfLink').length === 1) { $('#pdfLink').click(function(i) { var thisForm = normed($('#TrackForm')); if (thisForm) { //alert("posting form:"+$(thisForm).attr('name')); updateOrMakeNamedVariable($(thisForm),'hgt.psOutput','on'); return postTheForm($(thisForm).attr('name'),this.href); } return true; }); @@ -3634,41 +3678,41 @@ } }, onDrop: function(table, row, dragStartIndex) { var compositeSet = dragReorder.getCompositeSet(row); if (compositeSet && compositeSet.length > 0) $( compositeSet ).find('p.btn').removeClass('blueButtons');// blue persists if ($(row).attr('rowIndex') !== dragStartIndex) { // NOTE Even if dragging a contiguous set of rows, // still only need to check the one under the cursor. if (dragReorder.setOrder) { dragReorder.setOrder(table); } dragReorder.zipButtons( table ); } $(document).unbind('mousemove',posting.blockTheMapOnMouseMove); - setTimeout(posting.allowMapClicks,50); // Necessary incase the onDrop was over a map item. onDrop takes precedence. + // Timeout necessary incase the onDrop over map item. onDrop takes precedence. + setTimeout(posting.allowMapClicks,100); } }); } // Drag scroll init if (hgTracks.imgBoxPortal) { // Turn on drag scrolling. $("div.scroller").panImages(); } - //$("#zoomSlider").slider({ min: -4, max: 3, step: 1 });//, handle: '.ui-slider-handle' }); // Retrieve tracks via AJAX that may take too long to draw initialliy (i.e. a remote bigWig) var retrievables = $('#imgTbl').find("tr.mustRetrieve"); if ($(retrievables).length > 0) { $(retrievables).each( function (i) { var trackName = $(this).attr('id').substring(3); imageV2.requestImgUpdate(trackName,"",""); }); } imageV2.loadRemoteTracks(); makeItemsByDrag.load(); // Any highlighted region must be shown and warnBox must play nice with it. imageV2.highlightRegion(); // When warnBox is dismissed, any image highlight needs to be redrawn.