dc954816332fdd522f6999b04cb7409a2a9f8239
tdreszer
  Wed Jun 4 17:42:48 2014 -0700
Tightened the screws on several descrete cases where comparison to undefined might have been acting on undeclared variable.  I have looked through all the js files I altered for jshint and only found these few cases which might (but in practice probably don't) trigger exceptions.
diff --git src/hg/js/utils.js src/hg/js/utils.js
index 36cbe07..6814a83 100644
--- src/hg/js/utils.js
+++ src/hg/js/utils.js
@@ -146,42 +146,42 @@
             strReturn = aParam[1];
             break;
          }
       }
     }
     return unescape(strReturn);
 }
 
 function makeHiddenInput(theForm,aName,aValue)
 {   // Create a hidden input to hold a value
     $(theForm).find("input:last").after("<input type=hidden name='"+aName+"' value='"+aValue+"'>");
 }
 
 function updateOrMakeNamedVariable(theForm,aName,aValue)
 {   // Store a value to a named input.  Will make the input if necessary
-    var inp = $(theForm).find("input[name='"+aName+"']:last");
-    if (inp && inp.length > 0) {
+    var inp = normed($(theForm).find("input[name='"+aName+"']:last"));
+    if (inp) {
         inp.val(aValue);
         inp.disabled = false;
     } else
         makeHiddenInput(theForm,aName,aValue);
 }
 
 function disableNamedVariable(theForm,aName)
 {   // Store a value to a named input.  Will make the input if necessary
-    var inp = $(theForm).find("input[name='"+aName+"']:last");
-    if (inp && inp.length > 0)
+    var inp = normed($(theForm).find("input[name='"+aName+"']:last"));
+    if (inp)
         inp.disabled = true;
 }
 
 function parseUrlAndUpdateVars(theForm,href)  // DEAD CODE?
 {   // Parses the URL and converts GET vals to POST vals
     var url = href;
     var extraIx = url.indexOf("?");
     if (extraIx > 0) {
         var extra = url.substring(extraIx+1);
         url = url.substring(0,extraIx);
         // now extra must be repeatedly broken into name=var
         extraIx = extra.indexOf("=");
         for (; extraIx > 0;extraIx = extra.indexOf("=")) {
             var aValue;
             var aName = extra.substring(0,extraIx);
@@ -291,31 +291,31 @@
 }
 function isFloat(s)
 {
     return (!isNaN(parseFloat(s)) && isFinite(s));
 }
 
 function validateInt(obj,min,max)
 {   // validates an integer which may be restricted to a range (if min and/or max are numbers)
     var title = obj.title;
     var rangeMin=parseInt(min);
     var rangeMax=parseInt(max);
     if (title.length === 0)
         title = "Value";
     var popup=( $.browser.msie === false );
     for (;;) {
-        if ((!obj.value || obj.value === "") 
+        if ((typeof(obj.value) === 'undefined' || obj.value === "") 
         &&  isInteger(obj.defaultValue))
             obj.value = obj.defaultValue;
         if (!isInteger(obj.value)) {
             if (popup) {
                 obj.value = prompt(title +" is invalid.\nMust be an integer.",obj.value);
                 continue;
             } else {
                 alert(title +" of '"+obj.value +"' is invalid.\nMust be an integer.");
                 obj.value = obj.defaultValue;
                 return false;
             }
         }
         var val = parseInt(obj.value);
         if (isInteger(min) && isInteger(max)) {
             if (val < rangeMin || val > rangeMax) {
@@ -358,31 +358,31 @@
             }
         }
         return true;
     }
 }
 
 function validateFloat(obj,min,max)
 {   // validates an float which may be restricted to a range (if min and/or max are numbers)
     var title = obj.title;
     var rangeMin=parseFloat(min);
     var rangeMax=parseFloat(max);
     if (title.length === 0)
         title = "Value";
     var popup=( $.browser.msie === false );
     for (;;) {
-        if ((!obj.value || obj.value === "") 
+        if ((typeof(obj.value) === 'undefined' || obj.value === "") 
         &&  isFloat(obj.defaultValue))
             obj.value = obj.defaultValue;
         if (!isFloat(obj.value)) {
             if (popup) {
                 obj.value = prompt(title +" is invalid.\nMust be a number.",obj.value);
                 continue;
             } else {
                 alert(title +" of '"+obj.value +"' is invalid.\nMust be a number."); // try a prompt box!
                 obj.value = obj.defaultValue;
                 return false;
             }
         }
         var val = parseFloat(obj.value);
         if (isFloat(min) && isFloat(max)) {
             if (val < rangeMin || val > rangeMax) {
@@ -431,46 +431,45 @@
 function validateUrl(url)
 {   // returns true if url is a valid url, otherwise returns false and shows an alert
 
     // I got this regexp from http://stackoverflow.com/questions/1303872/url-validation-using-javascript
     var regexp = /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&amp;'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&amp;'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&amp;'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&amp;'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&amp;'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i;
     if (regexp.test(url)) {
         return true;
     } else {
         alert(url + " is an invalid url");
         return false;
     }
 }
 
 function metadataIsVisible(trackName)
 {
-    var divit = $("#div_"+trackName+"_meta");
-    if (!divit || divit.length === 0)
+    var divit = normed($("#div_"+trackName+"_meta"));
+    if (!divit)
         return false;
     return ($(divit).css('display') !== 'none');
 }
 
 function metadataShowHide(trackName,showLonglabel,showShortLabel)
 {
 // Will show subtrack specific configuration controls
 // Config controls not matching name will be hidden
-    var divit = $("#div_"+trackName+"_meta");
-    if (!divit || divit.length === 0)
+    var divit = normed($("#div_"+trackName+"_meta"));
+    if (!divit)
         return false;
-    var img = $(divit).prev('a').find("img");
-    if (img && $(img).length === 1) {
-        img = $(img)[0];
+    var img = normed($(divit).prev('a').find("img"));
+    if (img) {
         if ($(divit).css('display') === 'none')
             $(img).attr('src','../images/upBlue.png');
         else
             $(img).attr('src','../images/downBlue.png');
     }
     if ($(divit).css('display') === 'none') {
         if (typeof(subCfg) === "object") {// subCfg.js file included?
             var cfg = normed($("#div_cfg_"+trackName));
             if (cfg)   // Hide any configuration when opening metadata
                 $(cfg).hide();
         }
 
         if ($(divit).find('table').length === 0) {
             lookupMetadata(trackName,showLonglabel,showShortLabel);
             return false;
@@ -488,32 +487,32 @@
         if (bgClass) {
             $(divit).children('table').removeClass('bgLevel1 bgLevel2 bgLevel3 bgLevel4');
             $(divit).children('table').addClass(bgClass);
         }
     }
     $(divit).toggle();  // jQuery hide/show
     return false;
 }
 
 function setTableRowVisibility(button, prefix, hiddenPrefix, titleDesc, doAjax)
 {
 // Show or hide one or more table rows whose id's begin with prefix followed by "-".
 // This code also modifies the corresponding hidden field (cart variable) and the
 // src of the +/- img button.
     var retval = true;
-    var hidden = $("input[name='"+hiddenPrefix+"_"+prefix+"_close']");
-    if (button && hidden && $(hidden).length > 0) {
+    var hidden = normed($("input[name='"+hiddenPrefix+"_"+prefix+"_close']"));
+    if (button && hidden) {
 	var newVal = -1;
         if (arguments.length > 5)
             newVal = arguments[5] ? 0 : 1;
         var oldSrc = $(button).attr("src");
         if (oldSrc && oldSrc.length > 0) {
             // Old img version of the toggleButton
             if (newVal === -1)
                 newVal = oldSrc.indexOf("/remove") > 0 ? 1 : 0;
             if (newVal === 1)
                 $(button).attr("src", oldSrc.replace("/remove", "/add") );
             else
                 $(button).attr("src", oldSrc.replace("/add", "/remove") );
         } else {
             // new BUTTONS_BY_CSS
             if (newVal === -1) {
@@ -565,36 +564,36 @@
     html +=  "window.scrollTo(0, 0);";
     html += "}";
     html += "function hideWarnBox() {";
     html += "var warnBox=document.getElementById('warnBox');";
     html += "warnBox.style.display='none';warnBox.innerHTML='';";
     html += "var endOfPage = document.body.innerHTML.substr(document.body.innerHTML.length-20);";
     html += "if(endOfPage.lastIndexOf('-- ERROR --') > 0) { history.back(); }";
     html += "}";
     html += "</script>";
 
     $('body').prepend(html);
 }
 
 function warn(msg)
 { // adds warnings to the warnBox
-    var warnList = $('#warnList'); // warnBox contains warnList
-    if (!warnList || $(warnList).length === 0) {
+    var warnList = normed($('#warnList')); // warnBox contains warnList
+    if (!warnList) {
         warnBoxJsSetup();
-        warnList = $('#warnList');
+        warnList = normed($('#warnList'));
     }
-    if ($(warnList).length === 0)
+    if (!warnList)
         alert(msg);
     else {
         $( warnList ).append('<li>'+msg+'</li>');
         if ($.isFunction(showWarnBox))
             showWarnBox();
         else
             alert(msg);
     }
 }
 
 var gWarnSinceMSecs = 0;
 function warnSince(msg)  // DEAD CODE?
 {   // Warn messages with msecs since last warnSince msg
     // This is necessary because IE Developer tools are hanging
     var now = new Date();
@@ -1018,35 +1017,35 @@
 // This code is intended to allow setting up a wait cursor while waiting on the function
 var gWaitFuncArgs = [];
 var gWaitFunc;
 
 function waitMaskClear()
 { // Clears the waitMask
     var  waitMask = normed($('#waitMask'));
     if (waitMask)
         $(waitMask).hide();
 }
 
 function waitMaskSetup(timeOutInMs)
 { // Sets up the waitMask to block page manipulation until cleared
 
     // Find or create the waitMask (which masks the whole page)
-    var  waitMask = $('#waitMask');
-    if (!waitMask || waitMask.length !== 1) {
+    var  waitMask = normed($('#waitMask'));
+    if (!waitMask) {
         // create the waitMask
         $("body").append("<div id='waitMask' class='waitMask');'></div>");
-        waitMask = $('#waitMask');
+        waitMask = normed($('#waitMask'));
     }
     $(waitMask).css({opacity:0.0,display:'block',top: '0px', 
                         height: $(document).height().toString() + 'px' });
     // Special for IE, since it takes so long, make mask obvious
     //if ($.browser.msie)
     //    $(waitMask).css({opacity:0.4,backgroundColor:'gray'});
 
     // Things could fail, so always have a timeout.
     if (!timeOutInMs)  // works for undefined, null and 0
         timeOutInMs = 30000; // IE can take forever!
 
     if (timeOutInMs > 0)
         setTimeout(waitMaskClear,timeOutInMs); // Just in case
 
     return waitMask;  // The caller could add css if they wanted.
@@ -1054,57 +1053,57 @@
 
 function _launchWaitOnFunction()
 { // should ONLY be called by waitOnFunction()
   // Launches the saved function
     var func = gWaitFunc;
     gWaitFunc = null;
     var funcArgs = gWaitFuncArgs;
     gWaitFuncArgs = [];
 
     if (!func || !jQuery.isFunction(func))
         warn("_launchWaitOnFunction called without a function");
     else
         func.apply(this, funcArgs);
 
     // Special if the first var is a button that can visually be inset
-    if (funcArgs.length > 0 && funcArgs[0].type) {
+    if (funcArgs.length > 0 && typeof(funcArgs[0].type) !== 'undefined') {
         if (funcArgs[0].type === 'button' && $(funcArgs[0]).hasClass('inOutButton')) {
             $(funcArgs[0]).css('borderStyle',"outset");
         }
     }
     // Now we can get rid of the wait cursor
     waitMaskClear();
 }
 
 function waitOnFunction(func)
 {   // sets the waitMask (wait cursor and no clicking),
     // then launches the function with up to 5 arguments
     if (!jQuery.isFunction(func)) {
         warn("waitOnFunction called without a function");
         return false;
     }
     if (gWaitFunc) {
         if (gWaitFunc === func) // already called (sometimes hapens when onchange event is triggered
             return true;       // by js (rather than direct user action).  Happens in IE8
         warn("waitOnFunction called but already waiting on a function");
         return false;
     }
 
     waitMaskSetup(0);  // Find or create waitMask (which masks whole page) but gives up after 5sec
 
     // Special if the first var is a button that can visually be inset
-    if (arguments.length > 1 && arguments[1].type) {
+    if (arguments.length > 1 && typeof(arguments[1].type) !== 'undefined') {
         if (arguments[1].type === 'button' && $(arguments[1]).hasClass('inOutButton')) {
             $(arguments[1]).css( 'borderStyle',"inset");
         }
     }
 
     // Build up the aruments array
     for (var aIx=1; aIx < arguments.length; aIx++) {
         gWaitFuncArgs.push(arguments[aIx]);
     }
     gWaitFunc = func;
 
     setTimeout(_launchWaitOnFunction,10);
 
 }
 
@@ -1769,31 +1768,31 @@
                 while (classList.length > 0) {
                     var aClass = classList.pop();
                     if (aClass.indexOf("sort") === 0) {
                         if (aClass === "sortRev")
                             reverse = true;
                         else {
                             aClass = aClass.substring(4);  // clip off the "sort" portion
                             var ix = parseInt(aClass);
                             if (!isNaN(ix)) {
                                 sortIx = ix;
                             }
                         }
                     }
                 }
                 if (sortIx >= 0) {
-                    if (this.id && this.id.length > 0)
+                    if (typeof(this.id) !== 'undefined' && this.id.length > 0)
                         fields[sortIx] = this.id + "=" + (reverse ? "-":"+");
                     else
                         fields[sortIx] = this.cellIndex + "=" + (reverse ? "-":"+");
                 }
             });
             if (fields.length > 0) {
                 if (!fields[0])
                     fields.shift();  // 1 based sort ix and 0 based fields ix
                 return fields.join(' ');
             }
         }
         return "";
     },
 
     columnsFromSortOrder: function (sortOrder)
@@ -2050,31 +2049,31 @@
         if (!sortColumns || sortColumns.cellIxs.length === 0) {
             // could mark all columns as sortable!
             $(tr).find('th').each(function (ix) {
                 $(this).addClass('sortable');
                 $(this).addClass('sort'+(ix+1));
                 //warn("Added class='sortable sort"+(ix+1)+"' to th:"+this.innerHTML);
             });
             sortColumns = new sortTable.columnsFromTr(tr,"silent");
             if (!sortColumns || sortColumns.cellIxs.length === 0) {
                 warn("sortable table's header row contains no sort columns.");
                 return;
             }
         }
         // Can wrap all columnn headers with link
         $(tr).find("th.sortable").each(function (ix) {
-            if ( ! $(this).attr('onclick') ) {
+            if ( typeof($(this).attr('onclick')) === 'undefined') {
                 $(this).click( function () { sortTable.sortOnButtonPress(this);} );
             }
             if ($.browser.msie) { // Special case for IE since CSS :hover doesn't work
                 $(this).hover(
                     function () { $(this).css( { backgroundColor: '#CCFFCC', cursor: 'hand' } ); },
                     function () { $(this).css( { backgroundColor: '#FCECC0', cursor: '' } ); }
                 );
             }
             if ( $(this).attr('title').length === 0) {
                 var title = $(this).text().replace(/[^a-z0-9 ]/ig,'');
                 if (title.length > 0 && $(this).find('sup'))
                     title = title.replace(/[0-9]$/g,'');
                 if (title.length > 0)
                     $(this).attr('title',"Sort list on '" + title + "'." );
                 else
@@ -2277,34 +2276,34 @@
         }
         $(hiddenVis).attr('disabled',false);
 
         $('input.viewBtn').val('View in Browser');
     },
 
     clickedOne: function (selCb,justClicked)
     {   // called by on click of CB and findTracks.checkAll()
         var selName = $(selCb).attr('id');
         var trackName = selName.substring(0,selName.length - "_sel_id".length);
         var hiddenSel = $("input[name='"+trackName+"_sel']");
         var seenVis = $('select#' + trackName + "_id");
         var hiddenVis = $("input[name='"+trackName+"']");
         var tr = $(selCb).parents('tr.found');
         var tdb = tdbGetJsonRecord(trackName);
-        var needSel = (tdb.parentTrack !== undefined && tdb.parentTrack !== null);
+        var needSel = (typeof(tdb.parentTrack) === 'string' && tdb.parentTrack !== '');
         var shouldPack = tdb.canPack && tdb.kindOfParent === 0; // If parent then not pack but full
         if (shouldPack
-        && tdb.shouldPack !== undefined && tdb.shouldPack !== null && !tdb.shouldPack)
+        &&  typeof(tdb.shouldPack) !== 'undefined' && tdb.shouldPack !== null && !tdb.shouldPack)
             shouldPack = false;
         var checked = $(selCb).attr('checked');
 
         // First deal with seenVis control
         if (checked) {
             $(seenVis).attr('disabled', false);
             if ($(seenVis).attr('selectedIndex') === 0) {
                 if (shouldPack)
                     $(seenVis).attr('selectedIndex',3);  // packed
                 else
                     $(seenVis).attr('selectedIndex',$(seenVis).attr('length') - 1);
             }
         } else {
             $(seenVis).attr('selectedIndex',0);  // hide
             $(seenVis).attr('disabled', true );