49bbb7e972e5b5cde64576177920bc3e3c0dedf1
tdreszer
  Tue Jun 3 13:06:53 2014 -0700
Changes at Angie's suggestion during pre-code-review. Redmine #13255.
diff --git src/hg/js/utils.js src/hg/js/utils.js
index e6ac827..748f690 100644
--- src/hg/js/utils.js
+++ src/hg/js/utils.js
@@ -86,30 +86,31 @@
             }
         }
     } else {
         // NS 4.x - I gave up trying to get this to work.
         if (debugLevel>2)
            alert("arrayOfInputsThatMatch is unimplemented for this browser");
     }
     return found;
 }
 
 
 function normed(thing)
 {   // RETURNS undefined, the lone member of the set or the full set if more than one member.
     // Used for normalizing returns from jquery DOM selects (e.g. $('tr.track').children('td.data'))
     // jquery returns an "array like 'object'" with 0 or more entries.  
+    // May be used on non-jquery objects and will reduce single element arrays to the element.
     // Use this to treat 0 entries the same as undefined and 1 entry as the item itself
     if (thing === undefined || thing === null
     ||  (thing.length !== undefined && thing.length === 0)  // Empty array (or 'array like object')
     ||  ($.isPlainObject(thing) && $.isEmptyObject(thing))) // Empty simple object
         return undefined;
     if (thing.length && thing.length === 1 && jQuery.type(thing) !== 'string') // string is overkill
         return thing[0]; // Container of one item should return the item itself.
     return thing;
 }
 
 function waitCursor(obj)  // DEAD CODE?
 {
     //document.body.style.cursor="wait"
     obj.style.cursor="wait";
 }
@@ -189,45 +190,45 @@
                 aValue = extra.substring(extraIx+1,endIx);
                 extra  = extra.substring(endIx+1);
             } else {
                 aValue = extra.substring(extraIx+1);
                 extra  = "";
             }
             if (aName.length > 0 && aValue.length > 0)
                 updateOrMakeNamedVariable(theForm,aName,aValue);
         }
     }
     return url;
 }
 
 function postTheForm(formName,href)
 {   // posts the form with a passed in href
-    var goodForm=$("form[name='"+formName+"']");
-    if (goodForm.length === 1) {
+    var goodForm = normed($("form[name='"+formName+"']"));
+    if (goodForm) {
         if (href && href.length > 0) {
             $(goodForm).attr('action',href); // just attach the straight href
         }
         $(goodForm).attr('method','POST');
 
         $(goodForm).submit();
     }
     return false; // Meaning do not continue with anything else
 }
 function setVarAndPostForm(aName,aValue,formName)
 {   // Sets a specific variable then posts
-    var goodForm=$("form[name='"+formName+"']");
-    if (goodForm.length === 1) {
+    var goodForm = normed($("form[name='"+formName+"']"));
+    if (goodForm) {
         updateOrMakeNamedVariable(goodForm,aName,aValue);
     }
     return postTheForm(formName,window.location.href);
 }
 
 // json help routines
 function tdbGetJsonRecord(trackName)  { return hgTracks.trackDb[trackName]; }
 // NOTE: These must jive with tdbKindOfParent() and tdbKindOfChild() in trackDb.h
 function tdbIsFolder(tdb)             { return (tdb.kindOfParent === 1); } 
 function tdbIsComposite(tdb)          { return (tdb.kindOfParent === 2); }
 function tdbIsMultiTrack(tdb)         { return (tdb.kindOfParent === 3); }
 function tdbIsView(tdb)               { return (tdb.kindOfParent === 4); } // Don't expect to use
 function tdbIsContainer(tdb)          { return (tdb.kindOfParent === 2 || tdb.kindOfParent === 3); }
 function tdbIsLeaf(tdb)               { return (tdb.kindOfParent === 0); }
 function tdbIsFolderContent(tdb)      { return (tdb.kindOfChild  === 1); }
@@ -290,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 === undefined || obj.value === null || obj.value === "") 
+        if ((!obj.value || 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) {
@@ -357,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 === undefined || obj.value === null || obj.value === "") 
+        if ((!obj.value || 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,73 +849,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" && common.hgsid !== undefined && common.hgsid !== null)
+    if (common && 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" && common.db !== undefined && common.db !== null)
+    if (common && 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" && common.track !== undefined && common.track !== null)
+    if (common && 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)
@@ -1048,80 +1049,61 @@
         setTimeout(waitMaskClear,timeOutInMs); // Just in case
 
     return waitMask;  // The caller could add css if they wanted.
 }
 
 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 {
-        if (funcArgs.length === 0)
-            func();
-        else if (funcArgs.length === 1)
-            func(funcArgs[0]);
-        else if (funcArgs.length === 2)
-            func(funcArgs[0],funcArgs[1]);
-        else if (funcArgs.length === 3)
-            func(funcArgs[0],funcArgs[1],funcArgs[2]);
-        else if (funcArgs.length === 4)
-            func(funcArgs[0],funcArgs[1],funcArgs[2],funcArgs[3]);
-        else if (funcArgs.length === 5)
-            func(funcArgs[0],funcArgs[1],funcArgs[2],funcArgs[3],funcArgs[4]);
     else
-            warn("_launchWaitOnFunction called with " + funcArgs.length + 
-                                                             " arguments.  Only 5 are supported.");
-    }
+        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[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;
     }
-    if (arguments.length > 6) {
-        warn("waitOnFunction called with " + arguments.length - 1 + 
-                                                             " arguments.  Only 5 are supported.");
-        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 !== undefined && arguments[1].type !== null) {
+    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);
 
 }
 
@@ -1819,52 +1801,52 @@
         this.reverse = [];
         var fields = sortOrder.split(" "); // sortOrder looks like: "cell=+ factor=+ view=+"
         while (fields.length > 0) {
             var pair = fields.shift().split("=");  // Take first and split into
             if (pair.length === 2) {
                 this.tags.push(pair[0]);
                 this.reverse.push(pair[1] !== '+');
             }
         }
     },
 
     columnsFromTr: function (tr,silent)
     {   // Creates a sortColumns struct from entries in the 'tr.sortable' heading row of the table
         this.inheritFrom = sortTable.columnsFromSortOrder;
         var sortOrder = sortTable.orderFromTr(tr);
-        if (sortOrder.length === 0 && (silent === undefined || silent === null)) {
+        if (sortOrder.length === 0 && !silent) {
             // developer needs to know something is wrong
             warn("Unable to obtain sortOrder from sortable table.");   
             return;
         }
 
         this.inheritFrom(sortOrder);
         // Add two additional arrays
         this.cellIxs = [];
         this.useAbbr = [];
         var ths = $(tr).find('th.sortable');
         for (var tIx=0; tIx < this.tags.length; tIx++) {
             for (ix=0; ix < ths.length; ix++) {
                 if ((ths[ix].id && ths[ix].id === this.tags[tIx])
                 ||  (ths[ix].cellIndex === parseInt(this.tags[tIx])))
                 {
                     this.cellIxs[tIx] = ths[ix].cellIndex;
                     this.useAbbr[tIx] = (ths[ix].abbr.length > 0);
                 }
             }
         }
-        if (this.cellIxs.length === 0 && (silent === undefined || silent === null)) {
+        if (this.cellIxs.length === 0 && !silent) {
             warn("Unable to find any sortOrder.cells for sortable table.  ths.length:"+ths.length + 
                  " tags.length:"+this.tags.length + " sortOrder:["+sortOrder+"]");
             return;
         }
     },
 
     columnsFromTable: function (table)
     {// Creates a sortColumns struct from the contents of a 'table.sortable'
         this.inheritNow = sortTable.columnsFromTr;
         var tr = $(table).find('tr.sortable')[0];
         this.inheritNow(tr);
     },
 
     _sortOnButtonPress: function (anchor)
     {   // Updates the sortColumns struct and sorts the table when a column header has been pressed
@@ -2060,31 +2042,31 @@
         }
         if ($(thead).hasClass('sortable') === false) {
             $(thead).addClass('sortable');
             //warn('Added sortable class to thead');
         }
 
         var sortColumns = new sortTable.columnsFromTr(tr,"silent");
         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 === undefined || sortColumns.cellIxs.length === 0) {
+            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') ) {
                 $(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: '' } ); }
                 );
             }