8c4510913f781693d99d967eed017e6909e13d4c
angie
  Thu Apr 28 10:42:01 2016 -0700
Make sure we support mirrors that don't have all (or any) of our popular species.  refs #15277 note 233

diff --git src/hg/js/hgGateway.js src/hg/js/hgGateway.js
index 628bbf8..5e62a4c 100644
--- src/hg/js/hgGateway.js
+++ src/hg/js/hgGateway.js
@@ -333,30 +333,33 @@
         // First see if there's already something there that we will replace:
         var oldG = svg.getElementById('hubsAndTree');
         var newG = svgCreateEl('g', { id: 'hubsAndTree' });
         // y offsets of tops of species labels (leaves of dbDbTree), filled in by drawNode.
         var leafTops = {};
         var hubBottomY, treeInfo, width, height;
         if (! checkTree(dbDbTree)) {
             console.error('dbDbTree in wrong format', dbDbTree);
             return;
         }
         _.assign(cfg, cfgOverrides);
         hubBottomY = drawHubs(newG, hubList, cfg.labelStartY);
         addDepth(dbDbTree);
         treeInfo = drawNode(newG, dbDbTree, hubBottomY, leafTops);
         width = treeInfo.x + cfg.paddingRight;
+        if (width < cfg.containerWidth) {
+            width = cfg.containerWidth;
+        }
         height = treeInfo.leafY - cfg.labelLineHeight + cfg.paddingBottom;
         if (oldG) {
             svg.removeChild(oldG);
         }
         svg.appendChild(newG);
         return { width: width, height: height,
                  yTree: hubBottomY - cfg.labelLineHeight,
                  leafTops: leafTops };
     }
 
     return { draw: draw };
 
 }()); // speciesTree
 
 
@@ -530,31 +533,30 @@
                                          style: 'fill:' + color + '; stroke:' + color });
         svg.appendChild(rect);
     }
 
     function drawStripes(svg, dbDbTree, yTop, height, leafTops) {
         var stripeCount = stripeColors.length;
         var lastStripeIx = stripeCount - 1;
         var stripeTops = [];
         var i, stripeHeight;
         findStripeTops(dbDbTree, lastStripeIx, leafTops, stripeTops, yTop);
         // Add an extra "stripe" coord so we have the coord for the bottom of the last stripe:
         stripeTops[stripeCount] = height;
         // Initialize missing stripes to 0-height (top = next stripe's top), if any:
         for (i = stripeCount - 1;  i >= 0;  i--) {
             if (stripeTops[i] === undefined) {
-                console.warn("No species found for stripe " + i + ", taxId " + stripeTaxIds[i]);
                 stripeTops[i] = stripeTops[i+1];
             }
         }
         for (i = 0;  i < stripeCount;  i++) {
             stripeHeight = stripeTops[i+1] - stripeTops[i];
             addRectFill(svg, 0, stripeTops[i], cfg.stripeWidth, stripeHeight, stripeColors[i]);
         }
         // Add stripe for hubs, if any:
         if (yTop > 0) {
             addRectFill(svg, 0, 0, cfg.stripeWidth, yTop, hubColor);
         }
         return stripeTops;
     }
 
     function drawOneIcon(svg, name, y) {
@@ -768,46 +770,58 @@
                                   'existing browser to ' +
                                   '<A HREF="https://www.mozilla.org/en-US/firefox/new/">' +
                                   ' FireFox</A> or ' +
                                   '<A HREF="https://www.google.com/chrome/browser/">' +
                                   'Chrome</A>.' +
                                   '</P>';
 
     // Globals (within this function scope)
     // Set this to true to see server requests and responses in the console.
     var debugCartJson = false;
     // This is a global (within wrapper function scope) so event handlers can use it
     // without needing to bind functions.
     var scrollbarWidth = 0;
     // This holds everything we need to know to draw the page: taxId, db, hubs, description etc.
     var uiState = {};
+    // This is used to check whether a taxId is found in activeGenomes:
+    var activeTaxIds = _.invert(activeGenomes);
     // This is dbDbTree after pruning -- null if dbDbTree has no children left
-    var prunedDbDbTree;
+    var prunedDbDbTree = null;
     // This keeps track of which gene the user has selected most recently from autocomplete.
     var selectedGene = null;
 
     function setupFavIcons() {
         // Set up onclick handlers for shortcut buttons and labels
+        var haveIcon = false;
         var i, name, taxId, onClick;
         for (i = 0;  i < favIconTaxId.length;  i++) {
             name = favIconTaxId[i][0];
             taxId = favIconTaxId[i][1];
+            if (activeTaxIds[taxId]) {
                 // When user clicks on icon, set the taxId (default database);
                 // scroll the image to that species and clear the species autocomplete input.
                 onClick = setTaxId.bind(null, taxId, null, true, true);
                 // Onclick for both the icon and its sibling label:
                 $('.jwIconSprite' + name).parent().children().click(onClick);
+                haveIcon = true;
+            } else {
+                // Inactive on this site -- hide it
+                $('.jwIconSprite' + name).parent().hide();
+            }
+        }
+        if (! haveIcon) {
+            $('#popSpeciesTitle').text('Species Search');
         }
     }
 
     function addCategory(cat, item) {
         // Clone item, add category: cat to it and return it (helper function, see below).
         var clone = {};
         _.assign(clone, item, { category: cat });
         return clone;
     }
 
     function autocompleteFromNode(node) {
         // Traverse dbDbTree to make autocomplete result lists for all non-leaf node labels.
         // Returns an object mapping each label of node and descendants to a list of
         // result objects with the same structure that we'd get from a server request.
         if (! node) {
@@ -1093,31 +1107,32 @@
         // Return true if some leaf descendant of node is in activeGenomes or activeTaxIds.
         // Remove any child that returns false.
         // If one of {genome, taxId} matches but not the other, tweak the other to match dbDb,
         // Since we'll be using the hgwdev dbDbTree on the RR which may have been tweaked.
         var genome = node[0], taxId = node[1], kids = node[3];
         var hasActiveLeaf = false, i, dbDbTaxId, dbDbGenome;
         if (!kids || kids.length === 0) {
             // leaf node: is it active?
             dbDbTaxId = activeGenomes[genome];
             if (dbDbTaxId) {
                 hasActiveLeaf = true;
                 node[1] = dbDbTaxId;
             }
             // Yet another special case for Baboon having one genome with two species...
             // maybe we should just change dbDb?
-            else if (_.startsWith(genome, 'Baboon ') && (taxId === 9555 || taxId === 9562)) {
+            else if (_.startsWith(genome, 'Baboon ') && (taxId === 9555 || taxId === 9562) &&
+                     activeGenomes.Baboon) {
                 hasActiveLeaf = true;
             } else {
                 dbDbGenome = activeTaxIds[taxId];
                 if (dbDbGenome) {
                     hasActiveLeaf = true;
                     node[0] = dbDbGenome;
                 }
             }
         } else {
             // parent node: splice out any child nodes with no active leaves
             for (i = kids.length - 1;  i >= 0;  i--) {
                 if (pruneInactive(kids[i], activeGenomes, activeTaxIds)) {
                     hasActiveLeaf = true;
                 } else {
                     kids.splice(i, 1);
@@ -1606,35 +1621,36 @@
     }
 
     function init() {
         // Boot up the page; initialize elements and install event handlers.
         var searchObj = {};
         // We need a bound function to pass into autocompleteCat.init below;
         // however, autocompleteFromTree is even slower than drawing the tree because of
         // all the copying.  So bind now, fill in searchObj later.
         var processSpeciesResults = processSpeciesAutocompleteItems.bind(null, searchObj);
         cart.setCgi('hgGateway');
         cart.debug(debugCartJson);
         // Get state from cart
         cart.send({ getUiState: {} }, handleRefreshState);
         cart.flush();
         // Prune inactive genomes from dbDbTree.
-        var activeTaxIds = _.invert(activeGenomes);
+        if (window.dbDbTree) {
             prunedDbDbTree = dbDbTree;
-        if (dbDbTree && ! pruneInactive(dbDbTree, activeGenomes, activeTaxIds)) {
+            if (! pruneInactive(dbDbTree, activeGenomes, activeTaxIds)) {
                 prunedDbDbTree = null;
             }
+        }
 
         // When page has loaded, do layout adjustments and initialize event handlers.
         $(function() {
             scrollbarWidth = findScrollbarWidth();
             setRightColumnWidth();
             setupFavIcons();
             autocompleteCat.init($('#speciesSearch'),
                                  { baseUrl: 'hgGateway?hggw_term=',
                                    watermark: speciesWatermark,
                                    onSelect: setDbFromAutocomplete,
                                    onServerReply: processSpeciesResults,
                                    enterSelectsIdentical: true });
             $('#selectAssembly').change(onChangeDbMenu);
             $('#positionDisplay').click(onClickCopyPosition);
             $('#copyPosition').click(onClickCopyPosition);