dc12d7fd1157d99004e2a2fb2cf4090fbc47939a
tdreszer
  Wed Jun 11 16:27:02 2014 -0700
Backing out several of the previous 'tightening screws' changes.  In particular typeof(thing.var) !== 'undefined' if thing.var === null.  I thought I tested this eariler, but now it is breaking sortTable, as reported by QA.
diff --git src/hg/js/utils.js src/hg/js/utils.js
index 6814a83..65ccb53 100644
--- src/hg/js/utils.js
+++ src/hg/js/utils.js
@@ -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 ((typeof(obj.value) === 'undefined' || obj.value === "") 
+        if ((obj.value === undefined || obj.value === null || 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 ((typeof(obj.value) === 'undefined' || obj.value === "") 
+        if ((obj.value === undefined || obj.value === null || 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) {
@@ -848,74 +848,73 @@
 }
 
 function getHgsid()
 {// return current session id
 
     // .first() because hgTracks turned up 3 of these!
     var hgsid = normed($("input[name='hgsid']").first());
     if (hgsid)
         return hgsid.value;
 
     hgsid = getURLParam(window.location.href, "hgsid");
     if (hgsid.length > 0)
         return hgsid;
 
     // This may be moved to 1st position as the most likely source
-    if (typeof(common) !== 'undefined' && typeof(common.hgsid) !== 'undefined'
-    && common.hgsid !== null)
+    if (typeof(common) !== 'undefined' && common.hgsid !== undefined && common.hgsid !== null)
         return common.hgsid;
 
     hgsid = normed($("input#hgsid").first());
     if (hgsid)
         return hgsid.value;
 
     return "";
 }
 
 function getDb()
 {
     var db = normed($("input[name='db']").first());
     if (db)
         return db.value;
 
     db = getURLParam(window.location.href, "db");
     if (db.length > 0)
         return db;
 
     // This may be moved to 1st position as the most likely source
-    if (typeof(common) !== 'undefined' && typeof(common.db) !== 'undefined')
+    if (typeof(common) !== 'undefined' && common.db)
         return common.db;
 
     db = normed($("input#db").first());
     if (db)
         return db.value;
 
     return "";
 }
 
 function getTrack()
 {
     var track = normed($("input[name='g']").first());
     if (track)
         return track.value;
 
     track = getURLParam(window.location.href, "g");
     if (track.length > 0)
         return track;
 
     // This may be moved to 1st position as the most likely source
-    if (typeof(common) !== 'undefined' && typeof(common.track) !== 'undefined')
+    if (typeof(common) !== 'undefined' && common.track)
         return common.track;
 
     track = normed($("input#g").first());
     if (track)
         return track.value;
 
     return "";
 }
 
 function Rectangle()  // DEAD CODE?
 {
 // Rectangle object constructor:
 // calling syntax:
 //
 // new Rectangle(startX, endX, startY, endY)
@@ -1053,57 +1052,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 && typeof(funcArgs[0].type) !== 'undefined') {
+    if (funcArgs.length > 0 && funcArgs[0].type) {
         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 && typeof(arguments[1].type) !== 'undefined') {
+    if (arguments.length > 1 && arguments[1].type) {
         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);
 
 }
 
@@ -1768,31 +1767,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 (typeof(this.id) !== 'undefined' && this.id.length > 0)
+                    if (this.id && 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)
@@ -2049,31 +2048,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 ( typeof($(this).attr('onclick')) === 'undefined') {
+            if ( ! $(this).attr('onclick') ) {
                 $(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
@@ -2127,31 +2126,31 @@
             'tableName':          1, 'tissueSourceType': 1, 'view':            1
         };
         var expected = $('tr.mdbSelect').length;
         var ix=1;
         if (index !== 0) {
             ix=index;
             expected=index;
         }
         for (; ix <= expected; ix++) {
             var helpLink = $("span#helpLink" + ix);
             if (helpLink.length > 0) {
                 // NOTE must match METADATA_NAME_PREFIX in hg/hgTracks/searchTracks.c
                 var val = $("select[name='hgt_mdbVar" + ix + "']").val();  
                 var text = $("select[name='hgt_mdbVar" + ix + "'] option:selected").text();
                 helpLink.html("&nbsp;"); // Do not want this with length === 0 later!
-                if (typeof(disabled[val]) === 'undefined') {
+                if ( ! disabled[val] ) {
                     var str;
                     if (val === 'cell') {
                         if (db.substr(0, 2) === "mm") {
                             str = "../ENCODE/cellTypesMouse.html";
                         } else {
                             str = "../ENCODE/cellTypes.html";
                         }
                     } else if (val.toLowerCase() === 'antibody') {
                         str = "../ENCODE/antibodies.html";
                     } else {
                         str = "../ENCODE/otherTerms.html#" + val;
                     }
                     helpLink.html("&nbsp;<a target='_blank' " +
                                   "title='detailed descriptions of terms'" + 
                                   " href='" + str + "'>" + text + "</a>");
@@ -2279,31 +2278,31 @@
         $('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 = (typeof(tdb.parentTrack) === 'string' && tdb.parentTrack !== '');
         var shouldPack = tdb.canPack && tdb.kindOfParent === 0; // If parent then not pack but full
         if (shouldPack
-        &&  typeof(tdb.shouldPack) !== 'undefined' && tdb.shouldPack !== null && !tdb.shouldPack)
+        &&  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 );