3d283800e2d599f69c0d16fd6015620f7d27f5a1
tdreszer
  Fri May 9 13:42:40 2014 -0700
Replaced Object.keys() which may not be supported by some browsers and moved three utility type scripts from cart to utils.js. Redmine 13164.
diff --git src/hg/js/hgTracks.js src/hg/js/hgTracks.js
index adbb3dc..69e6f62 100644
--- src/hg/js/hgTracks.js
+++ src/hg/js/hgTracks.js
@@ -460,124 +460,115 @@
 }
 
 /////////////////////////
 //// 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 (Object.keys(cart.updateQueue).length !== 0);
+        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: '+Object.keys(cart.updateQueue).length+' vars');
+            //console.log('cart.addUpdatesToUrl: '+objKeyCount(cart.updateQueue)+' vars');
             var updates = cart.varsToUrlData(); // clears the queue
             if (typeof url === 'undefined' || 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
         // Makes sure any outstanding queued updates are sent before leaving the page.
-        //console.log('cart.beforeUnload: '+Object.keys(cart.updateQueue).length+' vars');
+        //console.log('cart.beforeUnload: '+objKeyCount(cart.updateQueue)+' vars');
         cart.setVarsObj( {}, null, false ); // synchronous
     },
     
     varsToUrlData: function (varsObj)
     {   // creates a url data (var1=val1&var2=val2...) string from vars object and queue
         // The queue will be emptied by this call.
         cart.queueVarsObj(varsObj); // lay ontop of queue, to give new values precedence
         
         // Now convert to url data and clear queue
         var urlData = '';
         if (cart.updatesWaiting()) {
-            //console.log('cart.varsToUrlData: '+Object.keys(cart.updateQueue).length+' vars');
+            //console.log('cart.varsToUrlData: '+objKeyCount(cart.updateQueue)+' vars');
             urlData = varHashToQueryString(cart.updateQueue);
             cart.updateQueue = {};
         }
         return urlData;
     },
     
     setVarsObj: function (varsObj, errFunc, async)
     {   // Set all vars in a var hash, appending any queued updates
-        //console.log('cart.setVarsObj: were:'+Object.keys(cart.updateQueue).length + 
-        //            ' new:'+Object.keys(varsObj).length);
+        //console.log('cart.setVarsObj: were:'+objKeyCount(cart.updateQueue) + 
+        //            ' new:'+objKeyCount(varsObj);
         cart.queueVarsObj(varsObj); // lay ontop of queue, to give new values precedence
         
         // Now ajax update all in queue and clear queue
         if (cart.updatesWaiting()) {
             setVarsFromHash(cart.updateQueue, errFunc, async);
             cart.updateQueue = {};
         }
     },
     
-    arysToObj: function (names,values)
-    {   // Make hash type obj with two parallel arrays. (should be moved to utils.js).
-        var obj = {};
-        for(var ix=0; ix<names.length; ix++) {
-            obj[names[ix]] = values[ix]; 
-        }
-        return obj;
-    },
-    
     setVars: function (names, values, errFunc, async)
     {   // ajax updates the cart, and includes any queued updates.
-        cart.setVarsObj(cart.arysToObj(names, values), errFunc, async);
+        cart.setVarsObj(arysToObj(names, values), errFunc, async);
     },
 
     queueVarsObj: function (varsObj)
     {   // Add object worth of cart updates to the 'to be updated' queue, so they can be sent to
         // the server later. Note: hash allows overwriting previous updates to the same variable.
-        if (typeof varsObj !== 'undefined' && Object.keys(varsObj).length !== 0) {
-            //console.log('cart.queueVarsObj: were:'+Object.keys(cart.updateQueue).length + 
-            //            ' new:'+Object.keys(varsObj).length);
+        if (typeof varsObj !== 'undefined' && objNotEmpty(varsObj)) {
+            //console.log('cart.queueVarsObj: were:'+objKeyCount(cart.updateQueue) + 
+            //            ' new:'+objKeyCount(varsObj));
             for (var name in varsObj) {
                 cart.updateQueue[name] = varsObj[name];
                 
                 // NOTE: could update in background, however, failing to hit "refresh" is a user choice
                 // first in queue, schedule background update
-                if (Object.keys(cart.updateQueue).length === 1) {
+                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(cart.arysToObj(names,values));
+        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];
@@ -1199,31 +1190,31 @@
   ///////////////////////////
  //// 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()) {
                 $(this).attr('abbr',$(this).attr('rowIndex').toString());
                 var name = this.id.substring('tr_'.length) + '_imgOrd';
                 varsToUpdate[name] = $(this).attr('abbr');
             }
         });
-        if (Object.keys(varsToUpdate).length !== 0) {
+        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)
             tbody = table;
         
         // Do we need to sort?
         var trs = tbody.rows;
         var needToSort = false;
@@ -2194,31 +2185,31 @@
                 rightClick.reloadFloatingItem();
                 imageV2.requestImgUpdate(id, "hgt.transparentImage=0", "");
             }
         } else if (cmd == 'hideSet') {
             var row = $( 'tr#tr_' + id );
             var 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 (Object.keys(varsToUpdate).length !== 0) {
+                if (objNotEmpty(varsToUpdate)) {
                     cart.setVarsObj(varsToUpdate);
                 }
                 imageV2.afterImgChange(true);
             }
         } else if (cmd == 'hideComposite') {
             var rec = hgTracks.trackDb[id];
             if (tdbIsSubtrack(rec)) {
                 var row = $( 'tr#tr_' + id );
                 var 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();
                     }
                 var selectUpdated = vis.update(rec.parentTrack, 'hide');
                 cart.setVars( [rec.parentTrack], ['hide']);
@@ -2696,46 +2687,46 @@
     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
-            if (Object.keys(changedVars).length !== 0)
+            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 (Object.keys(changedVars).length !== 0)
+                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) {
                     vis.update(trackName, newVis);
                 }
-                if (Object.keys(changedVars).length !== 0) {
+                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)
     {
     // Take html from hgTrackUi and put it up as a modal dialog.