afbb996b456d1b16740c5251f2605cf0490fc267 tdreszer Mon May 19 13:38:57 2014 -0700 Polished for jshint, which uncovered a couple minor bugs. Minimal reformatting. Plan to check in a reformatted version of the file soon. diff --git src/hg/js/hgTracks.js src/hg/js/hgTracks.js index 69e6f62..7c7bfd9 100644 --- src/hg/js/hgTracks.js +++ src/hg/js/hgTracks.js @@ -1,71 +1,74 @@ // Javascript for use in hgTracks CGI // "use strict"; +// Don't complain about line break before '||' etc: +/* jshint -W014 */ + var debug = false; var browser; // browser ("msie", "safari" etc.) // move to utils.js? /* Data passed in from CGI via the hgTracks object: * * string cgiVersion // CGI_VERSION * string chromName // current chromosome * int winStart // genomic start coordinate (0-based, half-open) * int winEnd // genomic end coordinate * int newWinWidth // new width (in bps) if user clicks on the top ruler * boolean revCmplDisp // true if we are in reverse display * int insideX // width of side-bar (in pixels) * int rulerClickHeight // height of ruler (in pixels) - zero if ruler is hidden * boolean inPlaceUpdate // true if in-place-update is turned on * int imgBox* // various drag-scroll values * boolean measureTiming // true if measureTiming is on * Object trackDb // hash of trackDb entries for tracks which are visible on current page */ function initVars() { // There are various entry points, so we call initVars in several places to make sure all is well - if (typeof(hgTracks) != "undefined" && !genomePos.original) { + if (typeof(hgTracks) !== "undefined" && !genomePos.original) { // remember initial position and size so we can restore it if user cancels genomePos.original = genomePos.getOriginalPos(); 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 != undefined && imageV2.imgTbl.length > 0); + // 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) { + 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. 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. // 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). // // 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 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; } } ///////////////////////////////////// ////////// Genomic position ///////// @@ -86,109 +89,112 @@ } } }, setByCoordinates: function (chrom, start, end) { var newPosition = chrom + ":" + commify(start) + "-" + commify(end); genomePos.set(newPosition, commify(end - start + 1)); return newPosition; }, getElement: function () { // Return position box object var tags = document.getElementsByName("position"); - // There are multiple tags with name == "position" (the visible position text input + // There are multiple tags with name === "position" (the visible position text input // and a hidden with id='positionHidden'); we return value of visible element. for (var i = 0; i < tags.length; i++) { var ele = tags[i]; - if(ele.id != "positionHidden") { + if (ele.id !== "positionHidden") { return ele; } } return null; }, get: function () { // Return current value of position box var ele = genomePos.getElement(); - if(ele != null) { + if (ele) { return ele.value; } return null; }, getOriginalPos: function () { return genomePos.original || genomePos.get(); }, revertToOriginalPos: function () { // undo changes to position (i.e. after user aborts a drag-and-select). this.set(this.original, this.originalSize); this.original = this.originalSize = null; // not sure if this is necessary. }, set: function (position, size) { // Set value of position and size (in hiddens and input elements). // We assume size has already been commified. // Either position or size may be null. if(position) { - // There are multiple tags with name == "position" + // There are multiple tags with name === "position" // (one in TrackHeaderForm and another in TrackForm). var tags = document.getElementsByName("position"); 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 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 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 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 - var link = $('#wormbaseLink').attr('href'); - var reg = new RegExp("(.+:)[0-9]+"); - var a = reg.exec(link); + 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 if($('#dnaLink').length) { - var link = $('#dnaLink').attr('href'); - var reg = new RegExp("(.+&o=)[0-9]+.+&db=[^&]+(.*)"); - var a = reg.exec(link); + 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(); }, check: function (img, selection) { // return true if user's selection is still w/n the img (including some slop). var imgWidth = jQuery(img).width(); var imgHeight = jQuery(img).height(); @@ -203,44 +209,46 @@ var rightX = hgTracks.revCmplDisp ? imgOfs.left + imgWidth - hgTracks.insideX + slop : imgOfs.left + imgWidth + slop; return ( (selection.event.pageX >= leftX) && (selection.event.pageX < rightX) && (selection.event.pageY >= (imgOfs.top - slop)) && (selection.event.pageY < (imgOfs.top + imgHeight + slop))); }, pixelsToBases: function (img, selStart, selEnd, winStart, winEnd) { // Convert image coordinates to chromosome coordinates var imgWidth = jQuery(img).width() - hgTracks.insideX; var width = hgTracks.winEnd - hgTracks.winStart; var mult = width / imgWidth; // mult is bp/pixel multiplier var startDelta; // startDelta is how many bp's to the right/left + var x1; if(hgTracks.revCmplDisp) { - var x1 = Math.min(imgWidth, selStart); + x1 = Math.min(imgWidth, selStart); startDelta = Math.floor(mult * (imgWidth - x1)); } else { - var x1 = Math.max(hgTracks.insideX, selStart); + x1 = Math.max(hgTracks.insideX, selStart); startDelta = Math.floor(mult * (x1 - hgTracks.insideX)); } var endDelta; + var x2; if(hgTracks.revCmplDisp) { endDelta = startDelta; - var x2 = Math.min(imgWidth, selEnd); + x2 = Math.min(imgWidth, selEnd); startDelta = Math.floor(mult * (imgWidth - x2)); } else { - var x2 = Math.max(hgTracks.insideX, selEnd); + x2 = Math.max(hgTracks.insideX, selEnd); endDelta = Math.floor(mult * (x2 - hgTracks.insideX)); } var newStart = hgTracks.winStart + startDelta; var newEnd = hgTracks.winStart + 1 + endDelta; if(newEnd > winEnd) { newEnd = winEnd; } return {chromStart : newStart, chromEnd : newEnd}; }, selectionPixelsToBases: function (img, selection) { // Convert selection x1/x2 coordinates to chromStart/chromEnd. return genomePos.pixelsToBases(img, selection.x1, selection.x2, hgTracks.winStart, hgTracks.winEnd); }, @@ -250,170 +258,170 @@ var pos = genomePos.pixelsToBases(img, selection.x1, selection.x2, hgTracks.winStart, hgTracks.winEnd); // singleClick is true when the mouse hasn't moved (or has only moved a small amount). if(singleClick) { var center = (pos.chromStart + pos.chromEnd)/2; pos.chromStart = Math.floor(center - hgTracks.newWinWidth/2); pos.chromEnd = pos.chromStart + hgTracks.newWinWidth; } var newPosition = genomePos.setByCoordinates(hgTracks.chromName, pos.chromStart+1, pos.chromEnd); return newPosition; }, handleChange: function (response, status) { - var json = eval("(" + response + ")"); + var json = JSON.parse(response); genomePos.set(json.pos); }, changeAssemblies: function (ele) // UNUSED? Larry's experimental code { // code to update page when user changes assembly select list. $.ajax({ type: "GET", url: "../cgi-bin/hgApi", data: cart.varsToUrlData({ 'cmd': 'defaultPos', 'db': getDb() }), dataType: "html", trueSuccess: genomePos.handleChange, success: catchErrorOrDispatch, error: errorHandler, cache: true }); return false; } -} +}; ///////////////////////////////////// //// Creating items by dragging ///// ///////////////////////////////////// var makeItemsByDrag = { end: function (img, selection) { var image = $(img); var imageId = image.attr('id'); var trackName = imageId.substring('img_data_'.length); var pos = genomePos.selectionPixelsToBases(image, selection); var command = document.getElementById('hgt_doJsCommand'); command.value = "makeItems " + trackName + " " + hgTracks.chromName; command.value += " " + pos.chromStart + " " + pos.chromEnd; document.TrackHeaderForm.submit(); return true; }, init: function (trackName) { // Set up so that they can drag out to define a new item on a makeItems track. var img = $("#img_data_" + trackName); - if(img != undefined && img.length != 0) { + if (img && img.length !== 0) { var imgHeight = imageV2.imgTbl.height(); jQuery(img.imgAreaSelect( { selectionColor: 'green', outerColor: '', minHeight: imgHeight, maxHeight: imgHeight, onSelectEnd: makeItemsByDrag.end, autoHide: true, movable: false})); } }, load: function () { for (var id in hgTracks.trackDb) { var rec = hgTracks.trackDb[id]; - if(rec.type != null && rec.type.indexOf("makeItems") == 0) { + if (rec && rec.type && rec.type.indexOf("makeItems") === 0) { this.init(id); } } } -} +}; /////////////////// ///// mouse ///// /////////////////// var mouse = { savedOffset: {x:0, y:0}, saveOffset: function (ev) { // Save the mouse offset associated with this event mouse.savedOffset = {x: ev.clientX, y: ev.clientY}; }, hasMoved: function (ev) { // return true if mouse has moved a significant amount var minPixels = 10; var movedX = ev.clientX - mouse.savedOffset.x; var movedY = ev.clientY - mouse.savedOffset.y; - if (arguments.length == 2) { + if (arguments.length === 2) { var num = Number(arguments[1]); if(isNaN(num)) { - if ( arguments[1].toLowerCase() == "x" ) + if ( arguments[1].toLowerCase() === "x" ) return (movedX > minPixels || movedX < (minPixels * -1)); - if ( arguments[1].toLowerCase() == "y" ) + if ( arguments[1].toLowerCase() === "y" ) return (movedY > minPixels || movedY < (minPixels * -1)); } else minPixels = num; } return ( movedX > minPixels || movedX < (minPixels * -1) || movedY > minPixels || movedY < (minPixels * -1)); } -} +}; ///////////////// //// posting //// ///////////////// var posting = { blockUseMap: false, blockMapClicks: function () // Blocks clicking on map items when in effect. Drag opperations frequently call this. { posting.blockUseMap=true; }, allowMapClicks:function () // reallows map clicks. Called after operations that compete with clicks (e.g. dragging) { $('body').css('cursor', ''); // Explicitly remove wait cursor. posting.blockUseMap=false; }, mapClicksAllowed: function () // Verify that click-competing operation (e.g. dragging) isn't currently occurring. { - return (posting.blockUseMap == false); + 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). // // 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) { + 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; } 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); @@ -421,78 +429,76 @@ 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); }, saveSettings: function (obj) { - if(posting.blockUseMap==true) { + if (posting.blockUseMap === true) { return false; } - if(obj == undefined || obj.href == undefined) // called directly with obj + 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); return true; } - var thisForm=$(obj).parents('form'); - if(thisForm == undefined || $(thisForm).length == 0) - thisForm=$("FORM"); - if($(thisForm).length > 1 ) - thisForm=$(thisForm)[0]; - if(thisForm != undefined && $(thisForm).length == 1) { + var thisForm = normed($(obj).parents('form').first()); + if (!thisForm) + thisForm = normed($("FORM").first()); + if (thisForm) { //alert("posting form:"+$(thisForm).attr('name')); 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! 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 (typeof url === 'undefined' || url.length === 0) + if (!url || url.length === 0) return updates; if (updates.length > 0) { var dataOnly = (url.indexOf("cgi-bin") === -1); // all urls should be to our cgis if (!dataOnly && url.lastIndexOf("?") === -1) url += "?" + updates; else url += '&' + updates; } } return url; }, beforeUnload: function () { // named function that can be bound and unbound to beforeunload event @@ -545,74 +551,73 @@ // NOTE: could update in background, however, failing to hit "refresh" is a 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 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).attr('class', visibility === 'hide' ? 'hiddenText' : 'normalText'); $(this).val(visibility); selectUpdated = true; }); if(rec) { rec.localVisibility = visibility; } return selectUpdated; }, get: function (track) { // return current visibility for given track var rec = hgTracks.trackDb[track]; if(rec) { if(rec.localVisibility) { return rec.localVisibility; } else { return vis.enumOrder[rec.visibility]; } } else { return null; } }, makeTrackVisible: function (track) { - if(track != null && vis.get(track) != "full") { + 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. imageV2.markAsDirtyPage(); if(arguments.length > 2) return setTableRowVisibility(button, prefix, "hgtgroup", "group",false,arguments[2]); else return setTableRowVisibility(button, prefix, "hgtgroup", "group",false); }, @@ -621,98 +626,98 @@ { // 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 }); 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') { + 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(); 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'); }, restoreFromBackButton: function() // Re-enabling vis dropdowns is necessarty because intiForAjax() disables them on submit. { $('select.normalText,select.hiddenText').attr('disabled',false); } +}; -} //////////////////////////////////////////////////////////// // dragSelect is also known as dragZoom or shift-dragZoom // //////////////////////////////////////////////////////////// var dragSelect = { areaSelector: null, // formerly "imgAreaSelect". jQuery element used for imgAreaSelect originalCursor: null, startTime: null, selectStart: function (img, selection) { initVars(); if(rightClick.menu) { rightClick.menu.hide(); } var now = new Date(); dragSelect.startTime = now.getTime(); posting.blockMapClicks(); }, selectChange: function (img, selection) { - if(selection.x1 != selection.x2) { + if (selection.x1 !== selection.x2) { if (genomePos.check(img, selection)) { genomePos.update(img, selection, false); jQuery('body').css('cursor', dragSelect.originalCursor); } else { jQuery('body').css('cursor', 'not-allowed'); } } return true; }, highlightThisRegion: function(newPosition) // set highlighting newPosition in server-side cart and apply the highlighting in local UI. { var start, end; - if (arguments.length == 2) { + if (arguments.length === 2) { start = arguments[0]; end = arguments[1]; } else { var pos = parsePosition(newPosition); start = pos.start; end = pos.end; } hgTracks.highlight = getDb() + "." + hgTracks.chromName + ":" + start + "-" + end; hgTracks.highlight += '#AAFFFF'; // Also include highlight color // we include enableHighlightingDialog because it may have been changed by the dialog cart.setVarsObj({ 'highlight': hgTracks.highlight, 'enableHighlightingDialog': hgTracks.enableHighlightingDialog ? 1 : 0 }); imageV2.highlightRegion(); }, @@ -732,31 +737,31 @@ title: "Drag-and-select", closeOnEscape: true, resizable: false, autoOpen: false, revertToOriginalPos: true, minWidth: 400, buttons: { "Zoom In": function() { // Zoom to selection $(this).dialog("option", "revertToOriginalPos", false); if ($("#disableDragHighlight").attr('checked')) hgTracks.enableHighlightingDialog = false; if (imageV2.inPlaceUpdate) { var params = "position=" + newPosition; if (!hgTracks.enableHighlightingDialog) - params += "&enableHighlightingDialog=0" + params += "&enableHighlightingDialog=0"; imageV2.navigateInPlace(params, null, true); } else { $('body').css('cursor', 'wait'); if (!hgTracks.enableHighlightingDialog) cart.setVarsObj({'enableHighlightingDialog': 0 }); document.TrackHeaderForm.submit(); } $(this).dialog("close"); }, "Highlight": function() { // Highlight selection $(imageV2.imgTbl).imgAreaSelect({hide:true}); if ($("#disableDragHighlight").attr('checked')) hgTracks.enableHighlightingDialog = false; dragSelect.highlightThisRegion(newPosition); @@ -777,154 +782,154 @@ genomePos.revertToOriginalPos(); if($("#disableDragHighlight").attr('checked')) $(this).remove(); else $(this).hide(); $('body').css('cursor', ''); // Occasionally wait cursor got left behind } }); $(dragSelectDialog).dialog('open'); }, selectEnd: function (img, selection) { var now = new Date(); var doIt = false; - if(dragSelect.originalCursor != null) + if (dragSelect.originalCursor) jQuery('body').css('cursor', dragSelect.originalCursor); // ignore releases outside of the image rectangle (allowing a 10 pixel slop) if (genomePos.check(img, selection)) { // ignore single clicks that aren't in the top of the image // (this happens b/c the clickClipHeight test in dragSelect.selectStart // doesn't occur when the user single clicks). - doIt = dragSelect.startTime != null || selection.y1 <= hgTracks.rulerClickHeight; + doIt = dragSelect.startTime !== null || selection.y1 <= hgTracks.rulerClickHeight; } if(doIt) { // dragSelect.startTime is null if mouse has never been moved - var singleClick = ( (selection.x2 == selection.x1) - || dragSelect.startTime == null + var singleClick = ( (selection.x2 === selection.x1) + || dragSelect.startTime === null || (now.getTime() - dragSelect.startTime) < 100); var newPosition = genomePos.update(img, selection, singleClick); - if(newPosition != undefined) { + if (newPosition) { if (hgTracks.enableHighlightingDialog) dragSelect.selectionEndDialog(newPosition); else { $(imageV2.imgTbl).imgAreaSelect({hide:true}); if (imageV2.inPlaceUpdate) { imageV2.navigateInPlace("position=" + newPosition, null, true); } else { jQuery('body').css('cursor', 'wait'); document.TrackHeaderForm.submit(); } } } } else { $(imageV2.imgTbl).imgAreaSelect({hide:true}); genomePos.revertToOriginalPos(); } dragSelect.startTime = null; // blockMapClicks/allowMapClicks() is necessary if selectEnd was over a map item. - setTimeout('posting.allowMapClicks();',50); + setTimeout(posting.allowMapClicks,50); return true; }, load: function (firstTime) { var imgHeight = 0; if (imageV2.enabled) imgHeight = imageV2.imgTbl.innerHeight() - 1; // last little bit makes border look ok // No longer disable without ruler, because shift-drag still works - if(typeof(hgTracks) != "undefined") { + if (typeof(hgTracks) !== "undefined") { - if (hgTracks.rulerClickHeight == undefined || hgTracks.rulerClickHeight == null) + if (hgTracks.rulerClickHeight === undefined || hgTracks.rulerClickHeight === null) hgTracks.rulerClickHeight = 0; // will be zero if no ruler track var heights = hgTracks.rulerClickHeight; dragSelect.areaSelector = jQuery((imageV2.imgTbl).imgAreaSelect({ selectionColor: 'blue', outerColor: '', minHeight: imgHeight, maxHeight: imgHeight, onSelectStart: dragSelect.selectStart, onSelectChange: dragSelect.selectChange, onSelectEnd: dragSelect.selectEnd, autoHide: false, // gets hidden after possible dialog movable: false, clickClipHeight: heights })); } } -} +}; ///////////////////////////////////// //// 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 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 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) + if (chr.top === -1) warn("chromIdeo(): failed to register "+this.id); else { hiliteSetup(); $('area.cytoBand').unbind('mousedown'); // Make sure this is only bound once $('area.cytoBand').mousedown( function(e) { // mousedown on chrom portion of image only (map items) updateImgOffsets(); pxDown = e.clientX - img.scrolledLeft; var pxY = e.clientY - img.scrolledTop; - if(mouseIsDown == false + if (mouseIsDown === false && isWithin(chr.left,pxDown,chr.right) && isWithin(chr.top,pxY,chr.bottom)) { mouseIsDown = true; mouseHasMoved = false; $(document).bind('mousemove',chromMove); $(document).bind( 'mouseup', chromUp); hiliteShow(pxDown,pxDown); return false; } }); } } function chromMove(e) { // If mouse was down, determine if dragged, then show hilite if ( mouseIsDown ) { var pxX = e.clientX - img.scrolledLeft; var relativeX = (pxX - pxDown); - if(mouseHasMoved || (mouseHasMoved == false && Math.abs(relativeX) > 2)) { + if (mouseHasMoved || (mouseHasMoved === false && Math.abs(relativeX) > 2)) { mouseHasMoved = true; if(isWithin(chr.left,pxX,chr.right)) hiliteShow(pxDown,pxX); else if(pxX < chr.left) hiliteShow(pxDown,chr.left); 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 @@ -956,163 +961,165 @@ 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 + 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 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) + 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) + genomePos.setByCoordinates(chr.name, selRange.beg, selRange.end); $('area.cytoBand').mousedown( function(e) { return false; }); // Stop the presses :0) 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); + 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) offset = 1 - offset; return Math.round(offset * chr.size); } function convertFromBases(bases) { // Simple utility to convert bases to pix var offset = bases/chr.size; if(chr.reverse) offset = 1 - offset; return Math.round(offset * chr.width) + chr.left; } function findDimensions() { // Called at init: determine the dimensions of chrom from 'cytoband' map items var lastX = -1; $('area.cytoBand').each(function(ix) { var loc = this.coords.split(","); - if(loc.length == 4) { + if (loc.length === 4) { var myLeft = parseInt(loc[0]); var myRight = parseInt(loc[2]); - if (chr.top == -1) { + if (chr.top === -1) { chr.left = myLeft; chr.right = myRight; chr.top = parseInt(loc[1]); chr.bottom = parseInt(loc[3]); } else { if (chr.left > myLeft) chr.left = myLeft; if (chr.right < parseInt(loc[2])) chr.right = parseInt(loc[2]); } - var range = this.title.substr(this.title.lastIndexOf(':')+1) + var range = this.title.substr(this.title.lastIndexOf(':')+1); var pos = range.split('-'); - if(pos.length == 2) { - if (chr.name.length == 0) { + if (pos.length === 2) { + if (chr.name.length === 0) { chr.beg = parseInt(pos[0]); //chr.end = parseInt(pos[1]); chr.name = this.title.substring(this.title.lastIndexOf(' ')+1, - this.title.lastIndexOf(':')) + this.title.lastIndexOf(':')); } else { if (chr.beg > parseInt(pos[0])) chr.beg = parseInt(pos[0]); } if (chr.end < parseInt(pos[1])) { chr.end = parseInt(pos[1]); - if(lastX == -1) + if (lastX === -1) lastX = myRight; else if(lastX > myRight) chr.reverse = true; // end is advancing, but X is not, so reverse - } else if(lastX != -1 && lastX < myRight) + } 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 var cyto = { left: -1, right: -1, beg: -1, end: -1 }; $('area.cytoBand').each(function(ix) { var loc = this.coords.split(","); - if(loc.length == 4) { + if (loc.length === 4) { var myLeft = parseInt(loc[0]); var myRight = parseInt(loc[2]); - if(cyto.left == -1 || cyto.left > myLeft) { + var range; + var pos; + if (cyto.left === -1 || cyto.left > myLeft) { if ( isWithin(myLeft,pxDown,myRight) || isWithin(myLeft,pxUp,myRight) ) { cyto.left = myLeft; - var range = this.title.substr(this.title.lastIndexOf(':')+1) - var pos = range.split('-'); - if(pos.length == 2) { + 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])); } } } - if(cyto.right == -1 || cyto.right < myRight) { + if (cyto.right === -1 || cyto.right < myRight) { if ( isWithin(myLeft,pxDown,myRight) || isWithin(myLeft,pxUp,myRight) ) { cyto.right = myRight; - var range = this.title.substr(this.title.lastIndexOf(':')+1) - var pos = range.split('-'); - if(pos.length == 2) { + 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 if(selection.end < selection.beg) { var tmp = selection.end; selection.end = selection.beg; selection.beg = tmp; } @@ -1146,352 +1153,352 @@ begX = down + img.left; wide = (cur - down); } $(hilite).css({ left: begX + 'px', width: wide + 'px', top: topY + 'px', height: high + 'px', display:'' }); $(hilite).show(); } function hiliteCancel(left,width,top,height) { // Called on mouseup: Make green drag hilite disappear when no longer wanted $(hilite).hide(); $(hilite).css({ left: '0px', width: '0px', top: '0px', height: '0px' }); } function hiliteSetup() { // Called on init: setup of drag region hilite (but don't show yet) - if (hilite == null) { // setup only once + if (hilite === null) { // setup only once hilite = jQuery("<div id='chrHi'></div>"); $(hilite).css({ backgroundColor: 'green', opacity: 0.4, borderStyle: 'solid', borderWidth: '1px', bordercolor: '#0000FF' }); $(hilite).css({ display: 'none', position: 'absolute', overflow: 'hidden', zIndex: 1 }); jQuery($(chrImg).parents('body')).append($(hilite)); } return hilite; } function updateImgOffsets() { // Called on mousedown: Gets the current offsets var offs = $(chrImg).offset(); img.top = Math.round(offs.top ); img.left = Math.round(offs.left); img.scrolledTop = img.top - $("body").scrollTop(); img.scrolledLeft = img.left - $("body").scrollLeft(); if($.browser.msie) { img.height = $(chrImg).outerHeight(); img.width = $(chrImg).outerWidth(); } else { img.height = $(chrImg).height(); img.width = $(chrImg).width(); } return img; } }); -} +}; /////////////////////////// //// Drag Reorder Code //// /////////////////////////// var dragReorder = { setOrder: function (table) { // Sets the 'order' value for the image table after a drag reorder var varsToUpdate = {}; $("tr.imgOrd").each(function (i) { - if ($(this).attr('abbr') != $(this).attr('rowIndex').toString()) { + if ($(this).attr('abbr') !== $(this).attr('rowIndex').toString()) { $(this).attr('abbr',$(this).attr('rowIndex').toString()); var name = this.id.substring('tr_'.length) + '_imgOrd'; varsToUpdate[name] = $(this).attr('abbr'); } }); if (objNotEmpty(varsToUpdate)) { cart.setVarsObj(varsToUpdate); imageV2.markAsDirtyPage(); } }, sort: function (table) { // Sets the table row order to match the order of the abbr attribute. // This is needed for back-button, and for visBox changes combined with refresh. var tbody = $(table).find('tbody')[0]; - if(tbody == undefined) + if (!tbody) tbody = table; // Do we need to sort? var trs = tbody.rows; var needToSort = false; $(trs).each(function(ix) { - if ($(this).attr('abbr') != $(this).attr('rowIndex').toString()) { + if ($(this).attr('abbr') !== $(this).attr('rowIndex').toString()) { needToSort = true; return false; // break for each() loops } }); if (!needToSort) return false; // Create array of tr holders to sort - var ary = new Array(); + var ary = []; $(trs).each(function(ix) { // using sortTable found in utils.js ary.push(new sortTable.field(parseInt($(this).attr('abbr')),false,this)); }); // Sort the array ary.sort(sortTable.fieldCmp); // most efficient reload of sorted rows I have found var sortedRows = jQuery.map(ary, function(ary, i) { return ary.row; }); $(tbody).append( sortedRows ); // removes tr from current position and adds to end. return true; }, showCenterLabel: function (tr, show) { // Will show or hide centerlabel as requested // adjust button, sideLabel height, sideLabelOffset and centerlabel display if (!$(tr).hasClass('clOpt')) return; - var center = $(tr).find(".sliceDiv.cntrLab"); - if($(center) == undefined) + var center = normed($(tr).find(".sliceDiv.cntrLab")); + if (!center) return; - var seen = ($(center).css('display') != 'none'); - if(show == seen) + var seen = ($(center).css('display') !== 'none'); + if (show === seen) return; var centerHeight = $(center).height(); - var btn = $(tr).find("p.btn"); - var side = $(tr).find(".sliceDiv.sideLab"); - if($(btn) != undefined && $(side) != undefined) { - var sideImg = $(side).find("img"); - if($(sideImg) != undefined) { + var btn = normed($(tr).find("p.btn")); + var side = normed($(tr).find(".sliceDiv.sideLab")); + if (btn && side) { + var sideImg = normed($(side).find("img")); + if (sideImg) { var top = parseInt($(sideImg).css('top')); if(show) { $(btn).css('height',$(btn).height() + centerHeight); $(side).css('height',$(side).height() + centerHeight); top += centerHeight; // top is a negative number $(sideImg).css( {'top': top.toString() + "px" }); $( center ).show(); } else if (!show) { $(btn).css('height',$(btn).height() - centerHeight); $(side).css('height',$(side).height() - centerHeight); top -= centerHeight; // top is a negative number $(sideImg).css( {'top': top.toString() + "px" }); $( center ).hide(); } } } }, getContiguousRowSet: function (row) { // Returns the set of rows that are of the same class and contiguous - if(row == null) + if (!row) return null; var btn = $( row ).find("p.btn"); - if (btn.length == 0) + if (btn.length === 0) return null; var classList = $( btn ).attr("class").split(" "); var matchClass = classList[0]; var table = $(row).parents('table#imgTbl')[0]; var rows = $(table).find('tr'); // Find start index var startIndex = $(row).attr('rowIndex'); var endIndex = startIndex; for(var ix=startIndex-1;ix>=0;ix--) { btn = $( rows[ix] ).find("p.btn"); - if (btn.length == 0) + if (btn.length === 0) break; classList = $( btn ).attr("class").split(" "); - if (classList[0] != matchClass) + if (classList[0] !== matchClass) break; startIndex = ix; } // Find end index - for(var ix=endIndex;ix<rows.length;ix++) { - btn = $( rows[ix] ).find("p.btn"); - if (btn.length == 0) + for (var rIx=endIndex; rIx<rows.length; rIx++) { + btn = $( rows[rIx] ).find("p.btn"); + if (btn.length === 0) break; classList = $( btn ).attr("class").split(" "); - if (classList[0] != matchClass) + if (classList[0] !== matchClass) break; - endIndex = ix; + endIndex = rIx; } return rows.slice(startIndex,endIndex+1); // endIndex is 1 based! }, getCompositeSet: function (row) { // Returns the set of rows that are of the same class and contiguous - if(row == null) + if (!row) return null; var rowId = $(row).attr('id').substring('tr_'.length); var rec = hgTracks.trackDb[rowId]; - if (tdbIsSubtrack(rec) == false) + if (tdbIsSubtrack(rec) === false) return null; var rows = $('tr.trDraggable:has(p.' + rec.parentTrack+')'); return rows; }, zipButtons: function (table) { // Goes through the image and binds composite track buttons when adjacent var rows = $(table).find('tr'); var lastClass=""; - var lastBtn; + 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) + if (btn.length === 0) continue; var classList = $( btn ).attr("class").split(" "); - var curMatchesLast=(classList[0] == lastClass); + var curMatchesLast=(classList[0] === lastClass); // centerLabels may be conditionally seen if($( rows[ix] ).hasClass('clOpt')) { 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 else dragReorder.showCenterLabel(rows[ix],true); } // On with buttons - if(lastBtn != undefined) { + 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 + lastBlue = (lastMatchesLast === lastBlue); // lastMatch and lastBlue or not lastMatch and notLastBlue if(lastBlue) // Too smart by 1/3rd $( lastBtn ).addClass( 'btnBlue' ); else $( lastBtn ).removeClass( 'btnBlue' ); } } lastMatchesLast = curMatchesLast; lastClass = classList[0]; lastBtn = btn; } - if(lastBtn != undefined) { + if (lastBtn) { $( lastBtn ).removeClass('btnN btnU btnL btnD'); if(lastMatchesLast) { - $( btn).addClass('btnU'); + $( lastBtn ).addClass('btnU'); } else { $( lastBtn ).addClass('btnN'); countN++; } if(altColors) { - lastBlue = (lastMatchesLast == lastBlue); // lastMatch and lastBlue or not lastMatch and notLastBlue + lastBlue = (lastMatchesLast === lastBlue); // lastMatch and lastBlue or not lastMatch and notLastBlue 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 == undefined) { + if ( ! jQuery.tableDnD ) { //var handle = $("td.dragHandle"); //$(handle) // .unbind('mouseenter')//, jQuery.tableDnD.mousemove); // .unbind('mouseleave');//, jQuery.tableDnD.mouseup); return; } - if (jQuery.tableDnD.dragObject == null) { + if ( ! jQuery.tableDnD.dragObject ) { $( this ).parents("tr.trDraggable").addClass("trDrag"); } }, dragHandleMouseOut: function () { // Ends row highlighting by mouse over $( this ).parents("tr.trDraggable").removeClass("trDrag"); }, buttonMouseOver: function () { // Highlights a composite set of buttons, regarless of whether tracks are adjacent - if(jQuery.tableDnD == undefined || jQuery.tableDnD.dragObject == null) { + if ( ! jQuery.tableDnD || ! jQuery.tableDnD.dragObject ) { var classList = $( this ).attr("class").split(" "); var btns = $( "p." + classList[0] ); $( btns ).removeClass('btnGrey'); $( btns ).addClass('btnBlue'); - if (jQuery.tableDnD != undefined) { + if (jQuery.tableDnD) { var rows = dragReorder.getContiguousRowSet($(this).parents('tr.trDraggable')[0]); if (rows) $( rows ).addClass("trDrag"); } } }, 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 != undefined) { + 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 var id = ''; var a = /tr_(.*)/.exec($(this).attr('id')); // voodoo if(a && a[1]) { id = a[1]; } if (id.length > 0) { - if (imageV2.lastTrack == null || imageV2.lastTrack.id != id) + if ( ! imageV2.lastTrack || imageV2.lastTrack.id !== id) 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 == undefined || id == null || id.length == 0) { + if (!id || id.length === 0) { id = ''; var tr = $( this ).parents('tr.imgOrd'); - if ( $(tr).length == 1 ) { + if ( $(tr).length === 1 ) { var a = /tr_(.*)/.exec($(tr).attr('id')); // voodoo if(a && a[1]) { id = a[1]; } } } if (id.length > 0) { rightClick.currentMapItem = rightClick.makeMapItem(id); - if(rightClick.currentMapItem != null) { + if (rightClick.currentMapItem) { rightClick.currentMapItem.href = this.href; rightClick.currentMapItem.title = this.title; } } }, mapItemMouseOut: function () { imageV2.lastTrack = rightClick.currentMapItem; // Just a backup rightClick.currentMapItem = null; }, init: function () { // Make side buttons visible (must also be called when updating rows in the imgTbl). var btns = $("p.btn"); @@ -1504,63 +1511,63 @@ var handle = $("td.dragHandle"); if(handle.length > 0) { $(handle).mouseenter( dragReorder.dragHandleMouseOver ); $(handle).mouseleave( dragReorder.dragHandleMouseOut ); } // setup mouse callbacks for the area tags $(imageV2.imgTbl).find("tr").mouseover( dragReorder.trMouseOver ); $(".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). 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);//< hgTracks.imgBoxLeftLabel); 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 == undefined || pic == undefined) { + if (!pan || !pic) { throw "Not a div with a 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(); @@ -1568,51 +1575,51 @@ $(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 (mouseIsDown === false) { if(rightClick.menu) { rightClick.menu.hide(); } mouseIsDown = true; mouseDownX = e.clientX; highlightArea = $('#highlightItem')[0]; atEdge = (!beyondImage && (prevX >= leftLimit || prevX <= rightLimit)); $(document).bind('mousemove',panner); $(document).bind( 'mouseup', panMouseUp); // Will exec only once return false; } }); } function panner(e) { //if (!e) e = window.event; if ( mouseIsDown ) { var relativeX = (e.clientX - mouseDownX); - if(relativeX != 0) { + if (relativeX !== 0) { if (posting.mapClicksAllowed()) { // need to throw up a z-index div. Wait mask? savedPosition = genomePos.get(); dragMaskShow(); posting.blockMapClicks(); } var decelerator = 1; //var wingSize = 1000; // 0 stops the scroll at the edges. // Remeber that offsetX (prevX) is negative newX = prevX + relativeX; if ( newX >= leftLimit ) { // scrolled all the way to the left if(atEdge) { // Do not drag straight off edge. Force second drag beyondImage = true; newX = leftLimit + (newX - leftLimit)/decelerator;// slower //if (newX >= leftLimit + wingSize) // Don't go too far over the edge! @@ -1638,65 +1645,65 @@ $('.tdData').css( {'backgroundPosition': nowPos } ); scrollHighlight(relativeX); if (!only1xScrolling) panAdjustHeight(newX); // NOTE: This will dynamically resize image while scrolling. Do we want to? } } } 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. + setTimeout(posting.allowMapClicks,50); // Necessary incase the dragSelect.selectEnd was over a map item. select takes precedence. // 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 != undefined) + if (savedPosition) genomePos.set(savedPosition,null); var oldPos = prevX.toString() + "px"; $(".panImg").css( {'left': oldPos }); $('.tdData').css( {'backgroundPosition': oldPos } ); if (highlightArea) imageV2.highlightRegion(); return true; } // Do we need to fetch anything? if(beyondImage) { 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) { + 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 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 @@ -1805,157 +1812,156 @@ 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 var imgTbl = $('#imgTbl'); // Find or create the waitMask (which masks the whole page) - var dragMask = $('div#dragMask'); - if (dragMask == undefined || dragMask.length == 0) { + 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) var imgTbl = $('#imgTbl'); // Find or create the waitMask (which masks the whole page) - var dragMask = $('div#dragMask'); - if (dragMask != undefined && dragMask.length >= 1) { + var dragMask = normed($('div#dragMask')); + if (dragMask) { $(dragMask).height( $(imgTbl).height() ); } } function dragMaskClear() { // Clears the dragMask - $('body').css('cursor','auto') - var dragMask = $('#dragMask'); - if (dragMask != undefined ) + $('body').css('cursor','auto'); + var dragMask = normed($('#dragMask')); + if (dragMask) $(dragMask).hide(); } function scrollHighlight(relativeX) // Scrolls the highlight region if one exists { if (highlightArea) { // Best to have a left and right, then min/max the edges, then set width var hiOffset = $(highlightArea).offset(); var hiDefinedLeft = $(highlightArea).data('leftPixels'); var hiDefinedWidth = $(highlightArea).data('widthPixels'); hiOffset.left = Math.max(hiDefinedLeft + relativeX, portalAbsoluteX); var right = Math.min(hiDefinedLeft + hiDefinedWidth + relativeX, portalAbsoluteX + portalWidth); var newWidth = Math.max(right - hiOffset.left,0); - if (hiDefinedWidth != newWidth) + if (hiDefinedWidth !== newWidth) $(highlightArea).width(newWidth); $(highlightArea).offset(hiOffset); } } }; /////////////////////////////////////// //// 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). makeMapItem: function (id) { // Create a dummy mapItem on the fly (for objects that don't have corresponding entry in the map). - if(id && id.length > 0 - && typeof(hgTracks.trackDb) != "undefined" && hgTracks.trackDb != null) { + 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) var tr = $( e.target ).parents('tr.imgOrd'); - if ( $(tr).length == 1 ) { + 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 + "."); }, handleZoomCodon: function (response, status) { - var json = eval("(" + response + ")"); + 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); } }, handleViewImg: function (response, status) { // 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]) == null) { + 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". $("body").append("<div id = 'myPrompt'><div id='dialog' title='Basic dialog'><form>" + msg + "<input id='myPromptText' value=''></form>"); $("#myPrompt").dialog({ modal: true, closeOnEscape: true, @@ -1966,90 +1972,95 @@ } } }); }, hit: function (menuItemClicked, menuObject, cmd, args) { setTimeout( function() { rightClick.hitFinish(menuItemClicked, menuObject, cmd, args); }, 1); }, hitFinish: function (menuItemClicked, menuObject, cmd, args) { // dispatcher for context menu hits var id = rightClick.selectedMenuItem.id; - var url = null; + var url = null; // TODO: Break this giant routine with shared vars into some sub-functions + var href = null; + var rec = null; + var row = null; + var rows = null; + var selectUpdated = null; if(menuObject.shown) { // warn("Spinning: menu is still shown"); setTimeout(function() { rightClick.hitFinish(menuItemClicked, menuObject, cmd); }, 10); return; } - if (cmd == 'selectWholeGene' || cmd == 'getDna' || cmd == 'highlightItem') { + if (cmd === 'selectWholeGene' || cmd === 'getDna' || cmd === 'highlightItem') { // bring whole gene into view or redirect to DNA screen. - var href = rightClick.selectedMenuItem.href; + href = rightClick.selectedMenuItem.href; var chromStart, chromEnd; var a = /hgg_chrom=(\w+)&/.exec(href); // Many links leave out the chrom (b/c it's in the server side cart as "c") var chrom = hgTracks.chromName; if(a) { if(a && a[1]) chrom = a[1]; a = /hgg_start=(\d+)/.exec(href); if(a && a[1]) chromStart = parseInt(a[1]) + 1; a = /hgg_end=(\d+)/.exec(href); if(a && a[1]) chromEnd = parseInt(a[1]); } else { // a = /hgc.*\W+c=(\w+)/.exec(href); a = /hgc.*\W+c=(\w+)/.exec(href); if(a && a[1]) chrom = a[1]; a = /o=(\d+)/.exec(href); if(a && a[1]) chromStart = parseInt(a[1]) + 1; a = /t=(\d+)/.exec(href); if(a && a[1]) chromEnd = parseInt(a[1]); } - if(chrom == null || chromStart == null || chromEnd == null) { + if (!chrom || chrom.length === 0 || !chromStart || !chromEnd) {// 1-based chromStart warn("couldn't parse out genomic coordinates"); } else { - if(cmd == 'getDna') { + if (cmd === 'getDna') { // NOTE: this should be shared with URL generation for getDna blue bar menu url = "../cgi-bin/hgc?g=getDna&i=mixed&c=" + chrom; url += "&l=" + (chromStart - 1) + "&r=" + chromEnd; url += "&db=" + getDb() + "&hgsid=" + getHgsid(); - if (window.open(url) === null) { + if ( ! window.open(url) ) { rightClick.windowOpenFailedMsg(); } - } else if (cmd == 'highlightItem') { + } else if (cmd === 'highlightItem') { dragSelect.highlightThisRegion(parseInt(chromStart), parseInt(chromEnd)); } else { var newPosition = genomePos.setByCoordinates(chrom, chromStart, chromEnd); var reg = new RegExp("hgg_gene=([^&]+)"); - var a = reg.exec(href); + var b = reg.exec(href); var name; // pull item name out of the url so we can set hgFind.matches (redmine 3062) - if(a && a[1]) { - name = a[1]; + if(b && b[1]) { + name = b[1]; } else { reg = new RegExp("[&?]i=([^&]+)"); - a = reg.exec(href); - if(a && a[1]) { - name = a[1]; + 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). 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", @@ -2065,205 +2076,205 @@ } else { // do a full page refresh to update hgTracks image jQuery('body').css('cursor', 'wait'); var ele; if(document.TrackForm) ele = document.TrackForm; else ele = document.TrackHeaderForm; if(name) $(ele).append("<input type='hidden' name='hgFind.matches' " + "value='" + name + "'>"); ele.submit(); } } } - } else if (cmd == 'zoomCodon' || cmd == 'zoomExon') { + } else if (cmd === 'zoomCodon' || cmd === 'zoomExon') { var num, ajaxCmd, msg; - if(cmd == 'zoomCodon') { + if (cmd === 'zoomCodon') { msg = "Please enter the codon number to jump to:"; ajaxCmd = 'codonToPos'; } else { msg = "Please enter the exon number to jump to:"; ajaxCmd = 'exonToPos'; } 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') { + } else if (cmd === 'hgTrackUi_popup') { popUp.hgTrackUi( rightClick.selectedMenuItem.id, false ); // Launches the popup but shields the ajax with a waitOnFunction - } else if (cmd == 'hgTrackUi_follow') { + } else if (cmd === 'hgTrackUi_follow') { - var url = "hgTrackUi?hgsid=" + getHgsid() + "&g="; - var rec = hgTracks.trackDb[id]; + url = "hgTrackUi?hgsid=" + getHgsid() + "&g="; + rec = hgTracks.trackDb[id]; if (tdbHasParent(rec) && tdbIsLeaf(rec)) - url += rec.parentTrack + url += rec.parentTrack; else { - var link = $( 'td#td_btn_'+ rightClick.selectedMenuItem.id ).children('a'); // The button already has the ref - if ($(link) != undefined) + // 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') { + } 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()) == null) { + if ( ! window.open("../cgi-bin/hgRenderTracks?hgt.internal=1&hgsid=" + getHgsid()) ) { rightClick.windowOpenFailedMsg(); } return; */ 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') { - var href = rightClick.selectedMenuItem.href; + } 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); // but don't add chrom to wikiTrack links (see redmine #2476). var v = vars[i]; var val; - if(v == "db") { + if (v === "db") { val = getDb(); } else { val = hgTracks[valNames[i]]; } if (val - && id != "wikiTrack" - && (href.indexOf("?" + v + "=") == -1) - && (href.indexOf("&" + v + "=") == -1)) { + && id !== "wikiTrack" + && (href.indexOf("?" + v + "=") === -1) + && (href.indexOf("&" + v + "=") === -1)) { href = href + "&" + v + "=" + val; } } - if(cmd == 'followLink') { + if (cmd === 'followLink') { // XXXX This is blocked by Safari's popup blocker (without any warning message). location.assign(href); } else { // Remove hgsid to force a new session (see redmine ticket 1333). href = removeHgsid(href); - if(window.open(href) == null) { + if ( ! window.open(href) ) { rightClick.windowOpenFailedMsg(); } } - } else if (cmd == 'float') { - if(rightClick.floatingMenuItem && rightClick.floatingMenuItem == id) { - $.floatMgr.FOArray = new Array(); + } 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 = new Array(); + $.floatMgr.FOArray = []; } rightClick.floatingMenuItem = id; rightClick.reloadFloatingItem(); imageV2.requestImgUpdate(id, "hgt.transparentImage=0", ""); } - } else if (cmd == 'hideSet') { - var row = $( 'tr#tr_' + id ); - var rows = dragReorder.getContiguousRowSet(row); + } 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 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') { - var rec = hgTracks.trackDb[id]; + } else if (cmd === 'hideComposite') { + rec = hgTracks.trackDb[id]; if (tdbIsSubtrack(rec)) { - var row = $( 'tr#tr_' + id ); - var rows = dragReorder.getCompositeSet(row); + row = $( 'tr#tr_' + id ); + rows = dragReorder.getCompositeSet(row); if (rows && rows.length > 0) { - for (var ix=rows.length - 1; ix >= 0; ix--) { // from bottom, just in case remove screws with us - $(rows[ix]).remove(); + for (var rIx=rows.length - 1; rIx >= 0; rIx--) { // from bottom, just in case remove screws with us + $(rows[rIx]).remove(); } - var selectUpdated = vis.update(rec.parentTrack, 'hide'); + 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 + } 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 + 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 newPos.start = Math.max( Math.floor(newPos.start - (diff/2) ), 0 ); newPos.end = newPos.start + (curPos.end - curPos.start); } } if (imageV2.inPlaceUpdate) { var params = "position=" + newPos.chrom+':'+newPos.start+'-'+newPos.end; imageV2.navigateInPlace(params, null, true); } else { genomePos.setByCoordinates(newPos.chrom, newPos.start, newPos.end); jQuery('body').css('cursor', 'wait'); document.TrackHeaderForm.submit(); } } } - } else if (cmd == 'removeHighlight') { + } 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: - var rec = hgTracks.trackDb[id]; - var selectUpdated = vis.update(id, cmd); + rec = hgTracks.trackDb[id]; + selectUpdated = vis.update(id, cmd); // Now change the track image - if(imageV2.enabled && cmd == 'hide') - { + 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']); $(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(); @@ -2296,192 +2307,194 @@ 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. return "<img style='width:16px; height:16px; border-style:none;' src='../images/" + img + "' />"; }, load: function (img) { rightClick.menu = img.contextMenu( function() { popUp.cleanup(); // Popup box is not getting closed properly so must do it here - if (rightClick.selectedMenuItem == null) // This is literally an edge case so ignore + 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 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 != null) { + 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; - var rec = hgTracks.trackDb[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) { + if (btn.length === 1) { var compositeSet = dragReorder.getCompositeSet(row); if (compositeSet && compositeSet.length > 0) { // There is a 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) { - var o = new Object(); + 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); } - var o = new Object(); - var str = blankImg + " hide track set"; + 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 select = [ $(select)[0] ]; var cur = $(select).val(); if(cur) { $(select).children().each(function(index, o) { var title = $(this).val(); - var str = blankImg + " " + title; - if(title == cur) + str = blankImg + " " + title; + if (title === cur) str = selectedImg + " " + title; - var o = new Object(); + 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 - var o = new Object(); - var str = blankImg + " " + visStrings[i]; + o = {}; + str = blankImg + " " + visStrings[i]; if (rec.canPack - || (visStrings[i] != "pack" && visStrings[i] != "squish")) { + || (visStrings[i] !== "pack" && visStrings[i] !== "squish")) { if(rec.localVisibility) { - if(visStrings[i] == rec.localVisibility) { + if (visStrings[i] === rec.localVisibility) { str = selectedImg + " " + visStrings[i]; } - } else if(visStrings[i] == vis.enumOrder[rec.visibility]) { + } else if (visStrings[i] === vis.enumOrder[rec.visibility]) { str = selectedImg + " " + visStrings[i]; } o[str] = { onclick: rightClick.makeHitCallback(visStrings[i]) }; menu.push(o); } } done = true; } } } if(done) { - var o = new Object(); + 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") { + 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 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] = { onclick: function(menuItemClicked, menuObject) { rightClick.hit(menuItemClicked, menuObject, "highlightItem"); return true; } }; - if(rightClick.supportZoomCodon && rec.type.indexOf("genePred") != -1) { + if (rightClick.supportZoomCodon && rec.type.indexOf("genePred") !== -1) { // http://hgwdev-larrym.cse.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=([^&]+)"); var a = reg.exec(href); if(a && a[1]) { name = a[1]; reg = new RegExp("hgg_type=([^&]+)"); a = reg.exec(href); if(a && a[1]) { table = a[1]; } } else { // http://hgwdev-larrym.cse.ucsc.edu/cgi-bin/hgc?o=55086724&t=55275031&g=refGene&i=NM_005228&c=chr7 // http://hgwdev-larrym.cse.ucsc.edu/cgi-bin/hgc?o=55086713&t=55270769&g=wgEncodeGencodeManualV4&i=ENST00000455089&c=chr7 - var reg = new RegExp("i=([^&]+)"); - var a = reg.exec(href); + reg = new RegExp("i=([^&]+)"); + a = reg.exec(href); if(a && a[1]) { name = a[1]; reg = new RegExp("g=([^&]+)"); a = reg.exec(href); if(a && a[1]) { table = a[1]; } } } if(name && table) { o[rightClick.makeImgTag("magnify.png")+" Zoom to codon"] = { onclick: function(menuItemClicked, menuObject) { rightClick.hit(menuItemClicked, menuObject, "zoomCodon", {name: name, table: table}); @@ -2498,186 +2511,184 @@ } o[rightClick.makeImgTag("dnaIcon.png")+" Get DNA for "+title] = { onclick: function(menuItemClicked, menuObject) { rightClick.hit(menuItemClicked, menuObject, "getDna"); 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 != undefined && href.length > 0) { + 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) { - ; // suppress menu items for hgTracks links (e.g. Next/Prev map items). + if (title.indexOf("Click to alter ") === 0) { + // suppress the "Click to alter..." items + } 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") + if (title === "zoomInMore") // 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); } } } if(rightClick.selectedMenuItem && rec) { // Add cfg options at just shy of end... - var o = new Object(); + o = {}; if(tdbIsLeaf(rec)) { - if (rec["configureBy"] != 'none' - && (!tdbIsCompositeSubtrack(rec) || rec["configureBy"] != 'clickThrough')) { + if (rec.configureBy !== 'none' + && (!tdbIsCompositeSubtrack(rec) || rec.configureBy !== 'clickThrough')) { // Note that subtracks never do clickThrough because // parentTrack cfg is the desired clickThrough o[rightClick.makeImgTag("wrench.png")+" Configure "+rec.shortLabel] = { onclick: function(menuItemClicked, menuObject) { rightClick.hit(menuItemClicked, menuObject, "hgTrackUi_popup"); return true; } }; } - if(rec.parentTrack != undefined) { + if (rec.parentTrack) { o[rightClick.makeImgTag("folderWrench.png")+" Configure "+ rec.parentLabel + " track set..."] = { onclick: function(menuItemClicked, menuObject) { rightClick.hit(menuItemClicked,menuObject,"hgTrackUi_follow"); return true; } }; } } else { o[rightClick.makeImgTag("folderWrench.png")+" Configure "+rec.shortLabel + " track set..."] = { onclick: function(menuItemClicked, menuObject) { rightClick.hit(menuItemClicked, menuObject, "hgTrackUi_follow"); return true; } }; } if(jQuery.floatMgr) { - o[(rightClick.selectedMenuItem.id == rightClick.floatingMenuItem ? + o[(rightClick.selectedMenuItem.id === rightClick.floatingMenuItem ? selectedImg : blankImg) + " float"] = { onclick: function(menuItemClicked, menuObject) { rightClick.hit(menuItemClicked, menuObject, "float"); return true; } }; } menu.push($.contextMenu.separator); menu.push(o); } menu.push($.contextMenu.separator); if(hgTracks.highlight) { - var o; - if (hgTracks.highlight.search(getDb() + '.') == 0) { + if (hgTracks.highlight.search(getDb() + '.') === 0) { var currentlySeen = ($('#highlightItem').length > 0); - o = new Object(); + o = {}; // Jumps to highlight when not currently seen in image var text = (currentlySeen ? " Zoom" : " Jump") + " to highlighted region"; o[rightClick.makeImgTag("highlightZoom.png") + text] = { onclick: rightClick.makeHitCallback('jumpToHighlight') }; if ( currentlySeen ) { // Remove only when seen o[rightClick.makeImgTag("highlightRemove.png") + " Remove highlighting"] = { onclick: rightClick.makeHitCallback('removeHighlight') }; } menu.push(o); } } // Add view image at end - var o = new Object(); + o = {}; o[rightClick.makeImgTag("eye.png") + " View image"] = { onclick: function(menuItemClicked, menuObject) { rightClick.hit(menuItemClicked, menuObject, "viewImg"); return true; } }; menu.push(o); return menu; }, { beforeShow: function(e) { // console.log(mapItems[rightClick.selectedMenuItem]); rightClick.selectedMenuItem = rightClick.findMapItem(e); // XXXX? posting.blockUseMap = true; return true; }, hideTransition:'hide', // hideCallback fails if these are not defined. hideSpeed:10, hideCallback: function() { $('p.btn.blueButtons').removeClass('blueButtons'); $('tr.trDraggable.greenRows').removeClass('greenRows'); } }); return; } - -} +}; ////////////////////////////////// //// 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 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"; var rec = hgTracks.trackDb[trackName]; - if (!descriptionOnly && rec != null && rec["configureBy"] != null) { - if (rec["configureBy"] == 'none') + if (!descriptionOnly && rec && rec.configureBy) { + if (rec.configureBy === 'none') return; - else if (rec["configureBy"] == 'clickThrough') { + else if (rec.configureBy === 'clickThrough') { jQuery('body').css('cursor', 'wait'); window.location = cart.addUpdatesToUrl(myLink); return; } // default falls through to configureBy popup } myLink += "&ajax=1"; $.ajax({ type: "GET", url: cart.addUpdatesToUrl(myLink), dataType: "html", trueSuccess: popUp.uiDialog, success: catchErrorOrDispatch, error: errorHandler, cmd: rightClick.selectedMenuItem, cache: false @@ -2685,45 +2696,45 @@ }, hgTrackUi: function (trackName,descriptionOnly) { waitOnFunction( popUp._uiDialigRequest, trackName, descriptionOnly ); // Launches the popup but shields the ajax with a waitOnFunction }, 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 changedVars = varHashChanges(allVars,popUp.saveAllVars); //warn("cfgVars:"+varHashToQueryString(changedVars)); var newVis = changedVars[trackName]; - var hide = (newVis != null && (newVis == 'hide' || newVis == '[]')); // subtracks do not have "hide", thus '[]' - if($('#imgTbl') == undefined) { // On findTracks or config page + var hide = (newVis && (newVis === 'hide' || newVis === '[]')); // subtracks do not have "hide", thus '[]' + 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 != null) { + 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(); } } } } }, uiDialog: function (response, status) @@ -2747,31 +2758,31 @@ // - 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. // -- 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; + popWidth = popMaxWidth; $('#hgTrackUiDialog').dialog({ ajaxOptions: { // This doesn't work cache: true }, resizable: true, height: (popUp.trackDescriptionOnly ? popMaxHeight : 'auto'), // Let description scroll vertically width: popWidth, minHeight: 200, minWidth: 700, maxHeight: popMaxHeight, maxWidth: popMaxWidth, modal: true, closeOnEscape: true, @@ -2801,93 +2812,91 @@ 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) + 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 imgTbl: null, // formerly "trackImgTbl" The imgTbl or null if non-imageV2. inPlaceUpdate: false, // modified based on value of hgTracks.inPlaceUpdate and mapIsUpdateable mapIsUpdateable:true, 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 = $('#dirty'); - if (dirty != undefined && dirty.length != 0) + var dirty = normed($('#dirty')); + if (dirty) $(dirty).val('true'); }, markAsCleanPage: function () { // Clears signal that history may be out of sync with cart. - var dirty = $('#dirty'); - if (dirty != undefined && dirty.length != 0) + var dirty = normed($('#dirty')); + if (dirty) $(dirty).val('false'); }, isDirtyPage: function () { // returns true if page was marked as dirty // This will allow the backbutton to be overridden - var dirty = $('#dirty'); - if (dirty != undefined && dirty.length > 0) { - if ($(dirty).val() == 'true') + 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 != null && a[1] != null; a = reg.exec(response)) { + 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]); } } reg = new RegExp("(<span class='trackTiming'>[\\S\\s]+?</span>)"); a = reg.exec(response); - if(a != null && a[1] != null) { + 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). @@ -2938,46 +2947,47 @@ if (imageV2.backSupport) { imageV2.setInHistory(false); // Set this new position into History stack } else { imageV2.markAsDirtyPage(); } }, updateImgForId: function (html, id, fullImageReload, newJsonRec) { // update row in imgTbl for given id. // return true if we successfully pull slice for id and update it in imgTrack. var newTr = $(html).find("tr[id='tr_" + id + "']"); if (newTr.length > 0) { var tr = $(document.getElementById("tr_" + id)); if (tr.length > 0) { - $(tr).html(newTr.children()) + $(tr).html(newTr.children()); // Need to update tr class list too - var classes = $(html).find("tr[id='tr_"+ id + "']")[0].className + var classes = $(html).find("tr[id='tr_"+ id + "']")[0].className; if(classes && classes.length > 0) { $(tr).removeClass(); $(tr).addClass(classes); } // NOTE: Want to examine the png? Uncomment: //var img = $('#tr_' + id).find("img[id^='img_data_']").attr('src'); //warn("Just parsed image:<BR>"+img); // >1x dragScrolling needs some extra care. if(hgTracks.imgBoxPortal && (hgTracks.imgBoxWidth > hgTracks.imgBoxPortalWidth)) { - if (hgTracks.imgBoxPortalLeft != undefined) { + if (hgTracks.imgBoxPortalLeft !== undefined + && hgTracks.imgBoxPortalLeft !== null) { $(tr).find('.panImg').css({'left': hgTracks.imgBoxPortalLeft }); $(tr).find('.tdData').css( {'backgroundPosition': hgTracks.imgBoxPortalLeft}); } } // Need to update vis box (in case this is reached via back-button) if (imageV2.backSupport && fullImageReload) { // Update abbr so that rows can be resorted properly var abbr = $(newTr).attr('abbr'); if(abbr) { $(tr).attr('abbr', abbr); } @@ -2985,56 +2995,57 @@ vis.update(id, vis.enumOrder[newJsonRec.visibility]); } return true; } } return false; }, updateImgForAllIds: function (response, oldJson, newJson) { // update all rows in imgTbl based upon navigateInPlace response. var imgTbl = $('#imgTbl'); // We update rows one at a time // (b/c updating the whole imgTbl at one time doesn't work in IE). - for (var id in newJson.trackDb) { + var id; + for (id in newJson.trackDb) { var newJsonRec = newJson.trackDb[id]; var oldJsonRec = oldJson.trackDb[id]; - if (newJsonRec.visibility == 0) // hidden 'ruler' is in newJson.trackDb! + if (newJsonRec.visibility === 0) // hidden 'ruler' is in newJson.trackDb! continue; - if (newJsonRec.type == "remote") + if (newJsonRec.type === "remote") continue; - if (oldJsonRec != undefined && oldJsonRec.visibility != 0) { + if (oldJsonRec && oldJsonRec.visibility !== 0) { // New track replacing old: if (!imageV2.updateImgForId(response, id, true, newJsonRec)) warn("Couldn't parse out new image for id: " + id); - } else { //if (oldJsonRec == undefined || oldJsonRec.visibility == 0) + } 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)) warn("Couldn't insert new image for id: " + id); } } } if (imageV2.backSupport) { // Removes OLD: those in oldJson but not in newJson - for (var id in oldJson.trackDb) { - if(newJson.trackDb[id] == undefined) + 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)); } }, updateChromImg: function (response) { // Parse out new chrom 'ideoGram' (if available) // e.g.: <IMG SRC = "../trash/hgtIdeo/hgtIdeo_hgwdev_larrym_61d1_8b4a80.gif" // BORDER=1 WIDTH=1039 HEIGHT=21 USEMAP=#ideoMap id='chrom'> // Larry's regex voodoo: var a = /<IMG([^>]+SRC[^>]+id='chrom'[^>]*)>/.exec(response); if (a && a[1]) { @@ -3047,33 +3058,33 @@ // $("map[name='idelMap']").html('src', a[1]); if (imageV2.backSupport) { // Reinit chrom dragging. if ($('area.cytoBand').length >= 1) { $('img#chrom').chromDrag(); } } } } }, requestImgUpdate: function (trackName,extraData,loadingId,newVisibility) { // extraData, loadingId and newVisibility are optional var data = "hgt.trackImgOnly=1&hgsid=" + getHgsid() + "&hgt.trackNameFilter=" + trackName; - if(extraData != undefined && extraData != "") + if (extraData && extraData !== "") data += "&" + extraData; - if(loadingId == undefined || loadingId == "") + if (!loadingId || loadingId === "") loadingId = showLoadingImage("tr_" + trackName); var getOrPost = "GET"; if ((data.length) > 2000) // extraData could contain a bunch of changes from the cfg dialog getOrPost = "POST"; $.ajax({ type: getOrPost, url: "../cgi-bin/hgTracks", data: cart.addUpdatesToUrl(data), dataType: "html", trueSuccess: imageV2.updateImgAndMap, success: catchErrorOrDispatch, error: errorHandler, cmd: 'refresh', loadingId: loadingId, id: trackName, @@ -3083,88 +3094,88 @@ }, fullReload: function() { // force reload of whole page via trackform submit // This function does not return jQuery('body').css('cursor', 'wait'); document.TrackHeaderForm.submit(); }, updateImgAndMap: function (response, status) { // Handle ajax response with an updated trackMap image, map and optional ideogram. // // this.cmd can be used to figure out which menu item triggered this. - // this.id == appropriate track if we are retrieving just a single track. + // this.id === appropriate track if we are retrieving just a single track. // update local hgTracks.trackDb to reflect possible side-effects of ajax request. var newJson = scrapeVariable(response, "hgTracks"); var oldJson = hgTracks; var valid = false; - if (newJson == undefined) { - var stripped = new Object(); + if (!newJson) { + var stripped = {}; stripJsEmbedded(response, true, stripped); - if(stripped.warnMsg == null) + if ( ! stripped.warnMsg ) warn("hgTracks object is missing from the response"); } else { - if(this.id != null) { + 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) + 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); 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') { + && 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 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 } } 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) { + 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(); } else { // Will rebuild image adding new, removing old and resorting tracks imageV2.updateImgForAllIds(response,oldJson,newJson); imageV2.updateChromImg(response); hgTracks = newJson; genomePos.original = undefined; initVars(); imageV2.afterReload(); } } else { warn("ASSERT: Attempt to update track without advanced javascript features."); @@ -3177,118 +3188,119 @@ if(this.disabledEle) { this.disabledEle.removeAttr('disabled'); } if(this.loadingId) { hideLoadingImage(this.loadingId); } jQuery('body').css('cursor', ''); if(valid && this.currentId) { var top = $(document.getElementById("tr_" + this.currentId)).position().top; $(window).scrollTop(top - this.currentIdYOffset); } }, loadRemoteTracks: function () { - if(typeof(hgTracks.trackDb) != "undefined" && hgTracks.trackDb != null) { + if (hgTracks.trackDb) { for (var id in hgTracks.trackDb) { var rec = hgTracks.trackDb[id]; - if(rec.type == "remote") { + if (rec.type === "remote") { if($("#img_data_" + id).length > 0) { // load the remote track renderer via jsonp rec.loadingId = showLoadingImage("tr_" + id); var script = document.createElement('script'); var pos = parsePosition(genomePos.get()); var name = rec.remoteTrack || id; script.setAttribute('src', rec.url + "?track=" + name + "&jsonp=imageV2.remoteTrackCallback&position=" + encodeURIComponent(pos.chrom + ":" + pos.start + "-" + pos.end) + "&pix=" + $('#imgTbl').width() ); document.getElementsByTagName('head')[0].appendChild(script); } } } } }, remoteTrackCallback: function (rec) // jsonp callback to load a remote track. { if(rec.error) { - alert("retrieval from remote site failed with error: " + rec.error) + alert("retrieval from remote site failed with error: " + rec.error); } else { var remoteTrack = rec.track; for (var track in hgTracks.trackDb) { - if(hgTracks.trackDb[track].remoteTrack == remoteTrack) { + if (hgTracks.trackDb[track].remoteTrack === remoteTrack) { $('#img_data_' + track).attr('style', "left:-116px; top: -23px;"); $('#img_data_' + track).attr('height', rec.height); // XXXX use width in some way? // $('#img_data_' + track).attr('width', rec.width); $('#img_data_' + track).attr('width', $('#img_data_ruler').width()); $('#img_data_' + track).attr('src', rec.img); + /* jshint loopfunc: true */// function inside loop works and replacement is awkward. $('#td_data_' + track + ' > div').each(function(index) { - if(index == 1) { + if (index === 1) { var style = $(this).attr('style'); style = style.replace(/height:\s*\d+/i, "height:" + rec.height); $(this).attr('style', style); } }); var style = $('#p_btn_' + track).attr('style'); style = style.replace(/height:\s*\d+/i, "height:" + rec.height); $('#p_btn_' + track).attr('style', style); if(hgTracks.trackDb[track].loadingId) { hideLoadingImage(hgTracks.trackDb[track].loadingId); } } } } }, navigateButtonClick: function (ele) // called from hgTracks.c { // code to update just the imgTbl in response to navigation buttons (zoom-out etc.). if(imageV2.inPlaceUpdate) { var params = ele.name + "=" + ele.value; $(ele).attr('disabled', 'disabled'); // dinking navigation needs additional data - if(ele.name == "hgt.dinkLL" || ele.name == "hgt.dinkLR") { + if (ele.name === "hgt.dinkLL" || ele.name === "hgt.dinkLR") { params += "&dinkL=" + $("input[name='dinkL']").val(); - } else if(ele.name == "hgt.dinkRL" || ele.name == "hgt.dinkRR") { + } else if (ele.name === "hgt.dinkRL" || ele.name === "hgt.dinkRR") { params += "&dinkR=" + $("input[name='dinkR']").val(); } imageV2.navigateInPlace(params, $(ele), false); return false; } else { return true; } }, updateButtonClick: function (ele) // UNUSED? { // code to update the imgTbl based on changes in the track controls. // This is currently experimental code and is dead in the main branch. if(imageV2.mapIsUpdateable) { var data = ""; $("select").each(function(index, o) { var cmd = $(this).val(); - if(cmd == "hide") { - if(hgTracks.trackDb[this.name] != undefined) { + if (cmd === "hide") { + if (hgTracks.trackDb[this.name]) { alert("Need to implement hide"); } } else { - if(hgTracks.trackDb[this.name] == undefined - || cmd != vis.enumOrder[hgTracks.trackDb[this.name].visibility]) { + if ( ! hgTracks.trackDb[this.name] + || cmd !== vis.enumOrder[hgTracks.trackDb[this.name].visibility]) { if(data.length > 0) { data = data + "&"; } data = data + this.name + "=" + cmd; } } }); if(data.length > 0) { imageV2.navigateInPlace(data, null, false); } return false; } else { return true; } }, @@ -3323,41 +3335,41 @@ success: catchErrorOrDispatch, error: errorHandler, cmd: 'wholeImage', loadingId: showLoadingImage("imgTbl"), disabledEle: disabledEle, currentId: currentId, currentIdYOffset: currentIdYOffset, cache: false }); }, highlightRegion: function() // highlight vertical region in imgTbl based on hgTracks.highlight (#709). { var pos; - var hexColor = '#FFAAAA' + var hexColor = '#FFAAAA'; $('#highlightItem').remove(); if(hgTracks.highlight) { pos = parsePositionWithDb(hgTracks.highlight); if(pos) { pos.start--; // make start 0-based to match hgTracks.winStart if (pos.color) hexColor = pos.color; } } - if(pos != null && pos.chrom == hgTracks.chromName && pos.db == getDb() + if (pos && pos.chrom === hgTracks.chromName && pos.db === getDb() && pos.start <= hgTracks.imgBoxPortalEnd && pos.end >= hgTracks.imgBoxPortalStart) { var portalWidthBases = hgTracks.imgBoxPortalEnd - hgTracks.imgBoxPortalStart; var portal = $('#imgTbl td.tdData')[0]; var leftPixels = $(portal).offset().left + 3; // 3 for borders and cgi item calcs ?? var pixelsPerBase = ($(portal).width() - 2) / portalWidthBases; var clippedStartBases = Math.max(pos.start, hgTracks.imgBoxPortalStart); var clippedEndBases = Math.min(pos.end, hgTracks.imgBoxPortalEnd); var widthPixels = (clippedEndBases - clippedStartBases) * pixelsPerBase; if(hgTracks.revCmplDisp) leftPixels += (hgTracks.imgBoxPortalEnd - clippedEndBases) * pixelsPerBase - 1; 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); @@ -3369,323 +3381,322 @@ 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 // 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: + 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. // Since ajax updates leave the browser cached pages different from the server state, // simple back-button fails. Using a 'dirty flag' we had forced an update from server, // whenever the back button was hit, meaning there was no going back from server-state! // NOW using the hitsory API, the back-button triggers a 'statechange' event which can // contain data. We save the position in the data and ajax update the image when the // back-button is pressed. This works great for going back through ajax-updated position // changes, but is a bit messier when going back past a full-page retrieved state (as // described below). // NOTE: many things besides position could be ajax updated (e.g. track visibility). We are // using the back-button to keep track of position only. Since the image should be updated // every-time the back button is pressed, all track settings should persist (not go back). // What will occasionally fail is vis box state and group expansion state. This is because // the back-button goes to a browser cached page and then the image alone is updated. imageV2.history = window.History; // The 'statechange' function triggerd by the back-button. // Whenever the position changes, then use ajax-update to refetch the position imageV2.history.Adapter.bind(window,'statechange',function(){ var prevPos = imageV2.history.getState().data.position; var curPos = encodeURIComponent(genomePos.get().replace(/,/g,'')); - if (prevPos != undefined && prevPos != curPos) { + if (prevPos && prevPos !== curPos) { // NOTE: this function is NOT called when backing passed a full retrieval boundary genomePos.set(decodeURIComponent(prevPos)); imageV2.navigateInPlace("position=" + prevPos, null, false); } }); // TODO: move elsewhere? // With history support it is best that most position changes will ajax-update the image // This ensures that the 'go' and 'refresh' button will do so unless the chrom changes. $("input[value='go'],input[value='refresh']").click(function () { var newPos = genomePos.get().replace(/,/g,''); var newChrom = newPos.split(':')[0]; var oldChrom = genomePos.getOriginalPos().split(':')[0]; - if (newChrom == oldChrom) { + if (newChrom === oldChrom) { imageV2.markAsDirtyPage(); imageV2.navigateInPlace("position="+encodeURIComponent(newPos), null, false); window.scrollTo(0,0); return false; } // If chrom changed AND there are vis updates waiting... if (cart.updatesWaiting()) { var url = "../cgi-bin/hgTracks?" + cart.varsToUrlData({ 'db': getDb(), 'position': newPos, 'hgsid': getHgsid() }); - window.location.assign(url) + window.location.assign(url); return false; } return true; }); // Have vis box changes update cart through ajax. This helps keep page/cart in sync. vis.initForAjax(); // We reach here from these possible paths: // A) Forward: Full page retrieval: hgTracks is first navigated to (or chrom change) // B) Back-button past a full retrieval (B in: ->A,->b,->c(full page),->d,<-c,<-B(again)) // B1) Dirty page: at least one non-position change (e.g. 1 track vis changed in b) // B2) Clean page: only position changes from A->b->| var curPos = encodeURIComponent(genomePos.get().replace(/,/g,'')); var cachedPos = imageV2.history.getState().data.position; // A) Forward: Full page retrieval: hgTracks is first navigated to (or chrom change) - if (cachedPos == undefined) { // Not a back-button operation + if (!cachedPos) { // Not a back-button operation // set the current position into history outright (will replace). No img update needed imageV2.setInHistory(true); } else { // B) Back-button past a full retrieval genomePos.set(decodeURIComponent(cachedPos)); // B1) Dirty page: at least one non-position change if (imageV2.isDirtyPage()) { imageV2.markAsCleanPage(); // Only forcing a full page refresh if chrom changes var cachedChrom = decodeURIComponent(cachedPos).split(':')[0]; var curChrom = decodeURIComponent( curPos).split(':')[0]; - if (cachedChrom == curChrom) { + if (cachedChrom === curChrom) { imageV2.navigateInPlace("db="+getDb()+"&position=" + cachedPos, null, false); } else { imageV2.fullReload(); } } else { // B2) Clean page: only position changes from a->b - if (cachedPos != curPos) { + if (cachedPos !== curPos) { imageV2.navigateInPlace("db="+getDb()+"&position=" + cachedPos, null, false); } } // Special because FF is leaving vis drop-downs disabled vis.restoreFromBackButton(); } }, setInHistory: function (fullPageLoad) { // Keep a position history and allow the back-button to work (sort of) // replaceState on initial page load, pushState on each advance - // When call triggered by back button, the lastPos==newPos, so no action. + // When call triggered by back button, the lastPos===newPos, so no action. var lastPos = imageV2.history.getState().data.position; var newPos = encodeURIComponent(genomePos.get().replace(/,/g,'')); // no commas // A full page load could be triggered by back-button, but then there will be a lastPos // if this is the case then don't set the position in history again! - if (fullPageLoad && lastPos != undefined) + if (fullPageLoad && lastPos) return; - if (lastPos == undefined || lastPos == null || lastPos != newPos) { + if (!lastPos || lastPos !== newPos) { // Swap the position into the title var title = $('TITLE')[0].text; var ttlWords = title.split(' '); if (ttlWords.length >= 2) { ttlWords[1] = genomePos.get(); - title = ttlWords.join(' ') + title = ttlWords.join(' '); } else - title = genomePos.get() + title = genomePos.get(); var sid = getHgsid(); // Wish you were here! Come on, someone must catch this. if (fullPageLoad) { // Should only be on initial set-up: first navigation to page imageV2.history.replaceState({position: newPos, hgsid: + sid },title, "hgTracks?db=" + getDb() + "&position=" + newPos + "&hgsid="+sid); } else { // Should be when advancing (not-back-button) 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) { + 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 $('#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) { $('#currentTab').val(ui.panel.id); }, select: function(event, ui) { findTracks.switchTabs(ui); } }); $('#tabs').show(); $("#tabs").tabs('option', 'selected', '#' + val); - if(val =='simpleTab' && $('div#found').length < 1) { + if (val === 'simpleTab' && $('div#found').length < 1) { $('input#simpleSearch').focus(); } $("#tabs").css('font-family', jQuery('body').css('font-family')); $("#tabs").css('font-size', jQuery('body').css('font-size')); $('.submitOnEnter').keydown(trackSearch.searchKeydown); findTracks.normalize(); findTracks.updateMdbHelp(0); } } -} +}; /////////////// //// READY //// /////////////// $(document).ready(function() { // 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). - if($("FORM").length > 0 && $('#trackSearch').length == 0) { + if ($("FORM").length > 0 && $('#trackSearch').length === 0) { var allLinks = $('a'); $( allLinks ).unbind('click'); $( allLinks ).click( posting.saveSettings ); } - if($('#pdfLink').length == 1) { + if ($('#pdfLink').length === 1) { $('#pdfLink').click(function(i) { - var thisForm=$('#TrackForm'); - if(thisForm != undefined && $(thisForm).length == 1) { + 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; }); } if(imageV2.enabled) { // Make imgTbl allow drag reorder of imgTrack rows dragReorder.init(); var imgTable = $(".tableWithDragAndDrop"); if($(imgTable).length > 0) { $(imgTable).tableDnD({ onDragClass: "trDrag", dragHandle: "dragHandle", scrollAmount: 40, onDragStart: function(ev, table, row) { mouse.saveOffset(ev); $(document).bind('mousemove',posting.blockTheMapOnMouseMove); // Can drag a contiguous set of rows if dragging blue button table.tableDnDConfig.dragObjects = [ row ]; // defaults to just the one var btn = $( row ).find('p.btnBlue'); // btnBlue means cursor over left button - if (btn.length == 1) { + if (btn.length === 1) { table.tableDnDConfig.dragObjects = dragReorder.getContiguousRowSet(row); var compositeSet = dragReorder.getCompositeSet(row); if (compositeSet && compositeSet.length > 0) $( compositeSet ).find('p.btn').addClass('blueButtons'); // blue persists } }, 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) { + 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. + setTimeout(posting.allowMapClicks,50); // Necessary incase the onDrop was over a map item. onDrop takes precedence. } }); } // 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") + 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. - $('#warnOK').click(function (e) { imageV2.highlightRegion()}); + $('#warnOK').click(function (e) { imageV2.highlightRegion();}); // Also extend the function that shows the warn box so that it too redraws the highlight. showWarnBox = (function (oldShowWarnBox) { function newShowWarnBox() { oldShowWarnBox.apply(); imageV2.highlightRegion(); } return newShowWarnBox; })(showWarnBox); } // Drag select in chromIdeogram - if($('img#chrom').length == 1) { + if ($('img#chrom').length === 1) { if($('area.cytoBand').length >= 1) { $('img#chrom').chromDrag(); } } // Track search uses tabs trackSearch.init(); // Drag select initialize if (imageV2.enabled) { // moved from window.load(). dragSelect.load(true); if($('#hgTrackUiDialog')) $('#hgTrackUiDialog').hide();