cdaf6a67926c916a57bb8bdd196e5ffc999f159d
larrym
  Thu Jul 28 21:48:14 2011 -0700
switch to using in-memory json; refactor trackDbJson so it is part of hgTracks global in the client (redmine #4550)
diff --git src/hg/js/hgTracks.js src/hg/js/hgTracks.js
index a83dc38..7312e0e 100644
--- src/hg/js/hgTracks.js
+++ src/hg/js/hgTracks.js
@@ -841,31 +841,31 @@
         if( btn.length == 0)
             break;
         classList = $( btn ).attr("class").split(" ");
         if (classList[0] != matchClass)
             break;
         endIndex = ix;
     }
     return rows.slice(startIndex,endIndex+1); // endIndex is 1 based!
 }
 
 function imgTblCompositeSet(row)
 { // Returns the set of rows that are of the same class and contiguous
     if(row == null)
         return null;
     var rowId = $(row).attr('id').substring('tr_'.length);
-    var rec = trackDbJson[rowId];
+    var rec = hgTracks.trackDb[rowId];
     if (tdbIsSubtrack(rec) == false)
         return null;
 
     var rows = $('tr.trDraggable:has(p.' + rec.parentTrack+')');
     return rows;
 }
 
 function imgTblZipButtons(table)
 {
 // Goes through the image and binds composite track buttons when adjacent
     var rows = $(table).find('tr');
     var lastClass="";
     var lastBtn;
     var lastMatchesLast=false;
     var lastBlue=true;
@@ -1469,61 +1469,61 @@
                             },
                             select: function(event, ui) { findTracksSwitchTabs(ui); }
                         });
         $('#tabs').show();
         $("#tabs").tabs('option', 'selected', '#' + val);
         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(searchKeydown);
         findTracksNormalize();
         updateMetaDataHelpLinks(0);
     }
 
-    if(typeof(trackDbJson) != "undefined" && trackDbJson != null) {
-        for (var id in trackDbJson) {
-            var rec = trackDbJson[id];
+    if(typeof(hgTracks.trackDb) != "undefined" && hgTracks.trackDb != null) {
+        for (var id in hgTracks.trackDb) {
+            var rec = hgTracks.trackDb[id];
             if(rec.type == "remote") {
                 if($("#img_data_" + id).length > 0) {
                     // load the remote track renderer via jsonp
                     var script = document.createElement('script');
                     // XXXX add current image width
                     var pos = parsePosition(getPosition());
                     script.setAttribute('src', rec.url + "?track=" + id + "&jsonp=remoteTrackCallback&c=" + pos.chrom +
                                         "&s=" + pos.start + "&e=" + pos.end);
                     document.getElementsByTagName('head')[0].appendChild(script);
                 }
             }
         }
     }
 });
 
 function rulerModeToggle (ele)
 {
     autoHideSetting = !ele.checked;
     var obj = imgAreaSelect.data('imgAreaSelect');
     obj.setOptions({autoHide : autoHideSetting});
 }
 
 function makeMapItem(id)
 {
     // Create a dummy mapItem on the fly (for objects that don't have corresponding entry in the map).
-    if(typeof(trackDbJson) != "undefined" && trackDbJson != null) {
+    if(typeof(hgTracks.trackDb) != "undefined" && hgTracks.trackDb != null) {
         var title;
-        var rec = trackDbJson[id];
+        var rec = hgTracks.trackDb[id];
         if(rec) {
             title = rec.shortLabel;
         } else {
             title = id;
         }
         return {id: id, title: "configure " + title};
     } else {
         return null;
     }
 }
 
 function mapItemMouseOver(obj)
 {
     // Record data for current map area item
     currentMapItem = makeMapItem(obj.id);
@@ -1762,31 +1762,31 @@
                        url: "../cgi-bin/hgApi",
                        data: "db=" + getDb() +  "&cmd=" + ajaxCmd + "&num=" + results + "&table=" + args.table + "&name=" + args.name,
                        trueSuccess: handleZoomCodon,
                        success: catchErrorOrDispatch,
                        error: errorHandler,
                        cache: true
                    });
                  });
     } else if (cmd == 'hgTrackUi_popup') {
 
         hgTrackUiPopUp( selectedMenuItem.id, false );  // Launches the popup but shields the ajax with a waitOnFunction
 
     } else if (cmd == 'hgTrackUi_follow') {
 
         var url = "hgTrackUi?hgsid=" + getHgsid() + "&g=";
-        var rec = trackDbJson[id];
+        var rec = hgTracks.trackDb[id];
         if (tdbHasParent(rec) && tdbIsLeaf(rec))
             url += rec.parentTrack
         else {
             var link = $( 'td#td_btn_'+ selectedMenuItem.id ).children('a'); // The button already has the ref
             if( $(link) != undefined)
                 url = $(link).attr('href');
             else
                 url += selectedMenuItem.id;
         }
         location.assign(url);
 
     } else if (cmd == 'dragZoomMode') {
         autoHideSetting = true;
         var obj = imgAreaSelect.data('imgAreaSelect');
         obj.setOptions({autoHide : true, movable: false});
@@ -1844,65 +1844,65 @@
                 // This does work
                 $.floatMgr.FOArray = new Array();
             }
             floatingMenuItem = id;
             reloadFloatingItem();
             updateTrackImg(id, "hgt.transparentImage=0", "");
         }
     } else if (cmd == 'hideSet') {
         var row = $( 'tr#tr_' + id );
         var rows = imgTblContiguousRowSet(row);
         if (rows && rows.length > 0) {
             var vars = new Array();
             var vals = new Array();
             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);
-                //if (tdbIsSubtrack(trackDbJson[rowId]) == false)
+                //if (tdbIsSubtrack(hgTracks.trackDb[rowId]) == false)
                 //    warn('What went wrong?');
 
                 vars.push(rowId, rowId+'_sel'); // Remove subtrack level vis and explicitly uncheck.
                 vals.push('[]', 0);
                 $(rows[ix]).remove();
             }
             if (vars.length > 0) {
                 setCartVars( vars, vals );
                 initImgTblButtons();
                 loadImgAreaSelect(false);
             }
         }
     } else if (cmd == 'hideComposite') {
-        var rec = trackDbJson[id];
+        var rec = hgTracks.trackDb[id];
         if (tdbIsSubtrack(rec)) {
             var row = $( 'tr#tr_' + id );
             var rows = imgTblCompositeSet(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 = updateVisibility(rec.parentTrack, 'hide');
             setCartVar(rec.parentTrack, 'hide' );
             initImgTblButtons();
             loadImgAreaSelect(false);
             }
         }
         //else
         //    warn('What went wrong?');
     } else {   // if( cmd in 'hide','dense','squish','pack','full','show' )
         // Change visibility settings:
         //
         // First change the select on our form:
-        var rec = trackDbJson[id];
+        var rec = hgTracks.trackDb[id];
         var selectUpdated = updateVisibility(id, cmd);
 
         // Now change the track image
         if(imageV2 && 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))
                 setCartVars( [ id, id+"_sel" ], [ '[]', 0 ] ); // Remove subtrack level vis and explicitly uncheck.
             else if(tdbIsFolderContent(rec))
                 setCartVars( [ id, id+"_sel" ], [ 'hide', 0 ] ); // supertrack children need to have _sel set to trigger superttrack reshaping
             else
                 setCartVar(id, 'hide' );
             $('#tr_' + id).remove();
             initImgTblButtons();
@@ -1985,31 +1985,31 @@
         function() {
             popUpBoxCleanup();   // Popup box is not getting closed properly so must do it here
 
             var menu = [];
             var selectedImg = makeImgTag("greenChecksm.png");
             var blankImg    = makeImgTag("invisible16.png");
             var done = false;
             if(selectedMenuItem && selectedMenuItem.id != null) {
                 var href = selectedMenuItem.href;
                 var isHgc, isGene;
                 if(href) {
                     isGene = href.match("hgGene");
                     isHgc = href.match("hgc");
                 }
                 var id = selectedMenuItem.id;
-                var rec = trackDbJson[id];
+                var 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) {
                         var compositeSet = imgTblCompositeSet(row);
                         if (compositeSet && compositeSet.length > 0) {  // There is a composite set
                             offerHideComposite = true;
                             $( compositeSet ).find('p.btn').addClass('blueButtons');  // blue persists
 
                             var subSet = imgTblContiguousRowSet(row);
                             if (subSet && subSet.length > 1) {
                                 offerSingles = false;
@@ -2287,61 +2287,61 @@
         $('#hgTrackUiDialog').html("");  // clear out html after close to prevent problems caused by duplicate html elements
         popUpTrackName = ""; //set to defaults
         popUpTrackDescriptionOnly = false;
         popSaveAllVars = null;
     }
 }
 
 function _hgTrackUiPopUp(trackName,descriptionOnly)
 { // popup cfg dialog
     popUpTrackName = trackName;
     var myLink = "../cgi-bin/hgTrackUi?g=" + trackName + "&hgsid=" + getHgsid() + "&db=" + getDb();
     popUpTrackDescriptionOnly = descriptionOnly;
     if(popUpTrackDescriptionOnly)
         myLink += "&descriptionOnly=1";
 
-    var rec = trackDbJson[trackName];
+    var rec = hgTracks.trackDb[trackName];
     if(!descriptionOnly && rec != null && rec["configureBy"] != null) {
         if (rec["configureBy"] == 'none')
             return;
         else if (rec["configureBy"] == 'clickThrough') {
             jQuery('body').css('cursor', 'wait');
             window.location = myLink;
             return;
         }  // default falls through to configureBy popup
     }
     myLink += "&ajax=1";
     $.ajax({
                 type: "GET",
                 url: myLink,
                 dataType: "html",
                 trueSuccess: handleTrackUi,
                 success: catchErrorOrDispatch,
                 error: errorHandler,
                 cmd: selectedMenuItem,
                 cache: false
             });
 }
 
 function hgTrackUiPopUp(trackName,descriptionOnly)
 {
     waitOnFunction( _hgTrackUiPopUp, trackName, descriptionOnly );  // Launches the popup but shields the ajax with a waitOnFunction
 }
 
 function hgTrackUiPopCfgOk(popObj, trackName)
 { // When hgTrackUi Cfg popup closes with ok, then update cart and refresh parts of page
-    var rec = trackDbJson[trackName];
+    var rec = hgTracks.trackDb[trackName];
     var subtrack = tdbIsSubtrack(rec) ? trackName :undefined;  // If subtrack then vis rules differ
     var allVars = getAllVars($('#pop'), subtrack );
     var changedVars = varHashChanges(allVars,popSaveAllVars);
     //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
         setVarsFromHash(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) {
             setVarsFromHash(changedVars);
             $('#tr_' + trackName).remove();
             initImgTblButtons();
@@ -2398,31 +2398,31 @@
     $(cssFiles).each(function (i) {
         bix = "<LINK rel='STYLESHEET' href='".length;
         eix = this.lastIndexOf("' TYPE='text/css' />");
         file = this.substring(bix,eix);
         $.getScript(file); // Should protect against already loaded files.
     }); */
     /* //in open ?  Loads fine, but then dialog gets confused
     $(jsFiles).each(function (i) {
         bix = "<script type='text/javascript' SRC='".length;
         eix = this.lastIndexOf("'></script>");
         file = this.substring(bix,eix);
         //$.getScript(file,function(data) { warn(data.substring(0,20) + " loaded")});
     });*/
 
     if( ! popUpTrackDescriptionOnly ) {
-        var subtrack = tdbIsSubtrack(trackDbJson[popUpTrackName]) ? popUpTrackName :"";  // If subtrack then vis rules differ
+        var subtrack = tdbIsSubtrack(hgTracks.trackDb[popUpTrackName]) ? popUpTrackName :"";  // If subtrack then vis rules differ
         popSaveAllVars = 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!
         if (!newJQuery) {
             $('#hgTrackUiDialog').find('.filterComp').each( function(i) { // Do this by 'each' to set noneIsAll individually
                 $(this).dropdownchecklist({ firstItemChecksAll: true,
                         noneIsAll: $(this).hasClass('filterBy'),
                         maxDropHeight: filterByMaxHeight(this),
                         emptyText: "Please select ...",
                         textFormatFunction: ddclTextFormatter });
             });
         }
     }
 
     // Searching for some selblance of size suitability
@@ -2442,63 +2442,63 @@
                                width: popWidth,
                                minHeight: 200,
                                minWidth: 700,
                                maxHeight: popMaxHeight,
                                maxWidth: popMaxWidth,
                                modal: true,
                                closeOnEscape: true,
                                autoOpen: false,
                                buttons: { "OK": function() {
                                     if( ! popUpTrackDescriptionOnly )
                                         hgTrackUiPopCfgOk($('#pop'), popUpTrackName);
                                     $(this).dialog("close");
                                }},
                                // popup.ready() doesn't seem to work in open.  So there is no need for open at this time.
                                //open: function() {
-                               //     var subtrack = tdbIsSubtrack(trackDbJson[popUpTrackName]) ? popUpTrackName :"";  // If subtrack then vis rules differ
+                               //     var subtrack = tdbIsSubtrack(hgTracks.trackDb[popUpTrackName]) ? popUpTrackName :"";  // If subtrack then vis rules differ
                                //     popSaveAllVars = getAllVars( $('#pop'), subtrack );
                                //},
                                open: function () {
                                     if (newJQuery) {
                                         if( ! popUpTrackDescriptionOnly ) {
                                             $('#hgTrackUiDialog').find('.filterBy,.filterComp').each( function(i) {
                                                 if ($(this).hasClass('filterComp'))
                                                     ddcl.setup(this);
                                                 else
                                                     ddcl.setup(this, 'noneIsAll');
                                             });
                                         }
                                     }
                                },
                                close: function() {
                                    popUpBoxCleanup();
                                }
                            });
     // FIXME: Why are open and close no longer working!!!
     if(popUpTrackDescriptionOnly) {
         var myWidth =  $(window).width() - 300;
         if(myWidth > 900)
             myWidth = 900;
         $('#hgTrackUiDialog').dialog("option", "maxWidth", myWidth);
         $('#hgTrackUiDialog').dialog("option", "width", myWidth);
-        $('#hgTrackUiDialog').dialog('option' , 'title' , trackDbJson[popUpTrackName].shortLabel + " Track Description");
+        $('#hgTrackUiDialog').dialog('option' , 'title' , hgTracks.trackDb[popUpTrackName].shortLabel + " Track Description");
         $('#hgTrackUiDialog').dialog('open');
         var buttOk = $('button.ui-state-default');
         if($(buttOk).length == 1)
             $(buttOk).focus();
     } else {
-        $('#hgTrackUiDialog').dialog('option' , 'title' , trackDbJson[popUpTrackName].shortLabel + " Track Settings");
+        $('#hgTrackUiDialog').dialog('option' , 'title' , hgTracks.trackDb[popUpTrackName].shortLabel + " Track Settings");
         $('#hgTrackUiDialog').dialog('open');
     }
 }
 
 function afterImgTblReload()
 {
 // Reload various UI widgets after updating imgTbl map.
     parseMap(null, true);
     $("map[name!=ideoMap]").each( function(t) { parseMap($(this, false));});
     initImgTblButtons();
     loadImgAreaSelect(false);
     // Do NOT reload context menu (otherwise we get the "context menu sticks" problem).
     // loadContextMenu($('#tr_' + id));
     if(trackImgTbl.tableDnDUpdate)
         trackImgTbl.tableDnDUpdate();
@@ -2518,92 +2518,88 @@
         //var img = $('#tr_' + id).find("img[id^='img_data_']").attr('src');
         //warn("Just parsed image:<BR>"+img);
         return true;
     } else {
         return false;
     }
 }
 
 function handleUpdateTrackMap(response, status)
 {
 // Handle ajax response with an updated trackMap image (gif or png) and map.
 //
 // 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.
 
-    // update local trackDbJson to reflect possible side-effects of ajax request.
-    var json = scrapeVariable(response, "trackDbJson");
-    if(json == null) {
-        showWarning("trackDbJson is missing from the response");
+    // update local hgTracks.trackDb to reflect possible side-effects of ajax request.
+    var json = scrapeVariable(response, "hgTracks");
+    if(json == undefined) {
+        showWarning("hgTracks object is missing from the response");
     } else {
         if(this.id != null) {
-            if(json[this.id]) {
-                var visibility = visibilityStrsOrder[json[this.id].visibility];
+            if(json.trackDb[this.id]) {
+                var visibility = visibilityStrsOrder[json.trackDb[this.id].visibility];
                 var limitedVis;
-                if(json[this.id].limitedVis)
-                    limitedVis = visibilityStrsOrder[json[this.id].limitedVis];
+                if(json.trackDb[this.id].limitedVis)
+                    limitedVis = visibilityStrsOrder[json.trackDb[this.id].limitedVis];
                 if(this.newVisibility && limitedVis && this.newVisibility != limitedVis)
                     alert("There are too many items to display the track in " + this.newVisibility + " mode.");
-                var rec = trackDbJson[this.id];
-                rec.limitedVis = json[this.id].limitedVis;
+                var rec = hgTracks.trackDb[this.id];
+                rec.limitedVis = json.trackDb[this.id].limitedVis;
                 updateVisibility(this.id, visibility);
             } else {
-                showWarning("Invalid trackDbJson received from the server");
+                showWarning("Invalid hgTracks.trackDb received from the server");
             }
         } else {
-            trackDbJson = json;
+            hgTracks.trackDb = json.trackDb;
         }
     }
     if(this.loadingId) {
         hideLoadingImage(this.loadingId);
     }
     if(imageV2 && this.id && this.cmd && 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(updateTrackImgForId(response, id)) {
                afterImgTblReload();
           } else {
                showWarning("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) {
             // Implement in-place updating of hgTracks image
             //
             // We update rows one at a time (updating the whole imgTable at one time doesn't work in IE).
-            for (id in trackDbJson) {
+            for (id in hgTracks.trackDb) {
                 if(!updateTrackImgForId(response, id)) {
                     showWarning("Couldn't parse out new image for id: " + id);
                     //alert("Couldn't parse out new image for id: " + id+"BR"+response);  // Very helpful
                 }
             }
-            var json = scrapeVariable(response, "hgTracks");
-            if(json != undefined) {
+            // update hgTracks as appropriate (XXXX should we just copy over the whole thing rather than just specific keys?)
                 hgTracks.chromName = json.chromName;
                 hgTracks.winStart = json.winStart;
                 hgTracks.winEnd = json.winEnd;
                 $("input[name='c']").val(json.chromName);
                 $("input[name='l']").val(json.winStart);
                 $("input[name='r']").val(json.winEnd);
                 hgTracks.newWinWidth = json.newWinWidth;
                 setPositionByCoordinates(hgTracks.chromName, hgTracks.winStart + 1, hgTracks.winEnd);
                 originalPosition = undefined;
                 initVars();
-            } else {
-                showWarning("Couldn't parse out new position info");
-            }
             afterImgTblReload();
         } else {
             a= /<IMG([^>]+SRC[^>]+id='trackMap[^>]*)>/.exec(response);
             // Deal with a is null
             if(a[1]) {
                     var b = /WIDTH\s*=\s*['"]?(\d+)['"]?/.exec(a[1]);
                     var width = b[1];
                     b = /HEIGHT\s*=\s*['"]?(\d+)['"]?/.exec(a[1]);
                     var height = b[1];
                     b = /SRC\s*=\s*"([^")]+)"/.exec(a[1]);
                     var src = b[1];
                     $('#trackMap').attr('src', src);
                     var obj = imgAreaSelect.data('imgAreaSelect');
                     if(width) {
                         trackImg.attr('width', width);
@@ -2715,49 +2711,49 @@
         // 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();
     }
 }
 
 function windowOpenFailedMsg()
 {
     alert("Your web browser prevented us from opening a new window.\n\nPlease change your browser settings to allow pop-up windows from " + document.domain + ".");
 }
 
 function updateVisibility(track, visibility)
 {
-// Updates visibility state in trackDbJson and any visible elements on the page.
+// 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 = trackDbJson[track];
+    var rec = hgTracks.trackDb[track];
     var selectUpdated = false;
     $("select[name=" + track + "]").each(function(t) {
                                           $(this).attr('class', visibility == 'hide' ? 'hiddenText' : 'normalText');
                                           $(this).val(visibility);
                                           selectUpdated = true;
                                       });
     if(rec) {
         rec.localVisibility = visibility;
     }
     return selectUpdated;
 }
 
 function getVisibility(track)
 {
 // return current visibility for given track
-    var rec = trackDbJson[track];
+    var rec = hgTracks.trackDb[track];
     if(rec) {
         if(rec.localVisibility) {
             return rec.localVisibility;
         } else {
             return visibilityStrsOrder[rec.visibility];
         }
     } else {
         return null;
     }
 }
 
 function makeSureSuggestTrackIsVisible()
 {
 // make sure to show knownGene/refGene track is in at least pack (redmine #3484).
     var track = $("#suggestTrack").val();