0d3b8feb6074f6caccc2d4aadd020961fbd7eb82
chmalee
  Wed Jun 10 14:39:38 2020 -0700
Add drag reorder of VCF samples to VCF trio display. Also fixes bug in haplotype sort that I didn't discover until adding drag reorder. Sometimes when sorting haplotypes it is the case that the initial best match to a child allele is the same for each parent. Previously I would just advance the first drawn parent to the next best match but now I also check whether advancing the first drawn is actually the best idea and potentially advance the other parent instead, refs #25582

diff --git src/hg/js/hgTracks.js src/hg/js/hgTracks.js
index 5484ad2..1af1af1 100644
--- src/hg/js/hgTracks.js
+++ src/hg/js/hgTracks.js
@@ -645,63 +645,30 @@
             autoHide: true, movable: false}));
         }
     },
 
     load: function ()
     {
         for (var id in hgTracks.trackDb) {
             var rec = hgTracks.trackDb[id];
             if (rec && rec.type && rec.type.indexOf("makeItems") === 0) {
                 this.init(id);
             }
         }
     }
 };
 
-  ///////////////////
- /////  mouse  /////
-///////////////////
-var mouse = {
-
-    savedOffset: {x:0, y:0},
-
-    saveOffset: function (ev)
-    {   // Save the mouse offset associated with this event
-        mouse.savedOffset = {x: ev.clientX, y: ev.clientY};
-    },
-
-    hasMoved: function (ev)
-    {   // return true if mouse has moved a significant amount
-        var minPixels = 10;
-        var movedX = ev.clientX - mouse.savedOffset.x;
-        var movedY = ev.clientY - mouse.savedOffset.y;
-        if (arguments.length === 2) {
-            var num = Number(arguments[1]);
-            if (isNaN(num)) {
-                if ( arguments[1].toLowerCase() === "x" )
-                    return (movedX > minPixels || movedX < (minPixels * -1));
-                if ( arguments[1].toLowerCase() === "y" )
-                    return (movedY > minPixels || movedY < (minPixels * -1));
-            }
-            else
-                minPixels = num;
-        }
-        return (   movedX > minPixels || movedX < (minPixels * -1)
-                || movedY > minPixels || movedY < (minPixels * -1));
-    }
-};
-
   /////////////////
  //// posting ////
 /////////////////
 var posting = {
 
     blockUseMap: false,
 
     blockMapClicks: function () 
     // Blocks clicking on map items when in effect. Drag opperations frequently call this.
     { 
         posting.blockUseMap=true;  
     },
     
     allowMapClicks:function ()  
     // reallows map clicks.  Called after operations that compete with clicks (e.g. dragging) 
@@ -1732,394 +1699,30 @@
         img.left = Math.round(offs.left);
         img.scrolledTop  = img.top  - $("body").scrollTop();
         img.scrolledLeft = img.left - $("body").scrollLeft();
         if (theClient.isIePre11()) {
             img.height = $(chrImg).outerHeight();
             img.width  = $(chrImg).outerWidth();
         } else {
             img.height = $(chrImg).height();
             img.width  = $(chrImg).width();
         }
         return img;
     }
 });
 };
 
-  ///////////////////////////
- //// 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 (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)
-            tbody = table;
-        
-        // Do we need to sort?
-        var trs = tbody.rows;
-        var needToSort = false;
-        $(trs).each(function(ix) {
-            if ($(this).attr('abbr') !== $(this).attr('rowIndex').toString()) {
-                needToSort = true;
-                return false;  // break for each() loops
-            }
-        });
-        if (!needToSort)
-            return false;
-            
-        // Create array of tr holders to sort
-        var ary = [];
-        $(trs).each(function(ix) {  // using sortTable found in utils.js
-            ary.push(new sortTable.field(parseInt($(this).attr('abbr')),false,this));
-        });
-
-        // Sort the array
-        ary.sort(sortTable.fieldCmp);
-
-        // most efficient reload of sorted rows I have found
-        var sortedRows = jQuery.map(ary, function(ary, i) { return ary.row; });
-        $(tbody).append( sortedRows ); // removes tr from current position and adds to end.
-        return true;
-    },
-
-    showCenterLabel: function (tr, show)
-    {   // Will show or hide centerlabel as requested
-        // adjust button, sideLabel height, sideLabelOffset and centerlabel display
-
-        if (!$(tr).hasClass('clOpt'))
-            return;
-        var center = normed($(tr).find(".sliceDiv.cntrLab"));
-        if (!center)
-            return;
-        var seen = ($(center).css('display') !== 'none');
-        if (show === seen)
-            return;
-
-        var centerHeight = $(center).height();
-
-        var btn = normed($(tr).find("p.btn"));
-        var side = normed($(tr).find(".sliceDiv.sideLab"));
-        if (btn && side) {
-            var sideImg = normed($(side).find("img"));
-            if (sideImg) {
-                var top = parseInt($(sideImg).css('top'));
-                if (show) {
-                    $(btn).css('height',$(btn).height() + centerHeight);
-                    $(side).css('height',$(side).height() + centerHeight);
-                    top += centerHeight; // top is a negative number
-                    $(sideImg).css( {'top': top.toString() + "px" });
-                    $( center ).show();
-                } else if (!show) {
-                    $(btn).css('height',$(btn).height() - centerHeight);
-                    $(side).css('height',$(side).height() - centerHeight);
-                    top -= centerHeight; // top is a negative number
-                    $(sideImg).css( {'top': top.toString() + "px" });
-                    $( center ).hide();
-                }
-            }
-        }
-    },
-
-    getContiguousRowSet: function (row)
-    {   // Returns the set of rows that are of the same class and contiguous
-        if (!row)
-            return null;
-        var btn = $( row ).find("p.btn");
-        if (btn.length === 0)
-            return null;
-        var classList = $( btn ).attr("class").split(" ");
-        var matchClass = classList[0];
-        var table = $(row).parents('table#imgTbl')[0];
-        var rows = $(table).find('tr');
-
-        // Find start index
-        var startIndex = $(row).attr('rowIndex');
-        var endIndex = startIndex;
-        for (var ix=startIndex-1; ix >= 0; ix--) {
-            btn = $( rows[ix] ).find("p.btn");
-            if (btn.length === 0)
-                break;
-            classList = $( btn ).attr("class").split(" ");
-            if (classList[0] !== matchClass)
-                break;
-            startIndex = ix;
-        }
-
-        // Find end index
-        for (var rIx=endIndex; rIx<rows.length; rIx++) {
-            btn = $( rows[rIx] ).find("p.btn");
-            if (btn.length === 0)
-                break;
-            classList = $( btn ).attr("class").split(" ");
-            if (classList[0] !== matchClass)
-                break;
-            endIndex = rIx;
-        }
-        return rows.slice(startIndex,endIndex+1); // endIndex is 1 based!
-    },
-
-    getCompositeSet: function (row)
-    {   // Returns the set of rows that are of the same class and contiguous
-        if (!row)
-            return null;
-        var rowId = $(row).attr('id').substring('tr_'.length);
-        var rec = hgTracks.trackDb[rowId];
-        if (tdbIsSubtrack(rec) === false)
-            return null;
-
-        var rows = $('tr.trDraggable:has(p.' + rec.parentTrack+')');
-        return rows;
-    },
-
-    zipButtons: function (table)
-    {   // Goes through the image and binds composite track buttons when adjacent
-        var rows = $(table).find('tr');
-        var lastClass="";
-        var lastBtn = null;
-        var lastSide = null;
-        var lastMatchesLast=false;
-        var lastBlue=true;
-        var altColors=false;
-        var count=0;
-        var countN=0;
-        for (var ix=0; ix<rows.length; ix++) {    // Need to have buttons in order
-            var btn = $( rows[ix] ).find("p.btn");
-            var side = $( rows[ix] ).find(".sliceDiv.sideLab"); // added by GALT
-            if (btn.length === 0)
-                continue;
-            var classList = $( btn ).attr("class").split(" ");
-            var curMatchesLast=(classList[0] === lastClass);
-
-            // centerLabels may be conditionally seen
-            if ($( rows[ix] ).hasClass('clOpt')) {
-                // if same composite and previous also centerLabel optional then hide center label
-                if (curMatchesLast && $( rows[ix - 1] ).hasClass('clOpt'))
-                    dragReorder.showCenterLabel(rows[ix],false);
-                else
-                    dragReorder.showCenterLabel(rows[ix],true);
-            }
-
-            // On with buttons
-            if (lastBtn) {
-                $( lastBtn ).removeClass('btnN btnU btnL btnD');
-                if (curMatchesLast && lastMatchesLast) {
-                    $( lastBtn ).addClass('btnL');
-                    $( lastBtn ).css('height', $( lastSide ).height() - 0);  // added by GALT
-                } else if (lastMatchesLast) {
-                    $( lastBtn ).addClass('btnU');
-                    $( lastBtn ).css('height', $( lastSide ).height() - 1);  // added by GALT
-                } else if (curMatchesLast) {
-                    $( lastBtn ).addClass('btnD');
-                    $( lastBtn ).css('height', $( lastSide ).height() - 2);  // added by GALT
-                } else {
-                    $( lastBtn ).addClass('btnN');
-                    $( lastBtn ).css('height', $( lastSide ).height() - 3);  // added by GALT
-                    countN++;
-                }
-                count++;
-                if (altColors) {
-                    // lastMatch and lastBlue or not lastMatch and notLastBlue
-                    lastBlue = (lastMatchesLast === lastBlue);
-                    if (lastBlue)    // Too  smart by 1/3rd
-                        $( lastBtn ).addClass(    'btnBlue' );
-                    else
-                        $( lastBtn ).removeClass( 'btnBlue' );
-                }
-            }
-            lastMatchesLast = curMatchesLast;
-            lastClass = classList[0];
-            lastBtn = btn;
-            lastSide = side;
-        }
-        if (lastBtn) {
-            $( lastBtn ).removeClass('btnN btnU btnL btnD');
-            if (lastMatchesLast) {
-                $( lastBtn ).addClass('btnU');
-                $( lastBtn ).css('height', $( lastSide ).height() - 1);  // added by GALT
-            } else {
-                $( lastBtn ).addClass('btnN');
-                $( lastBtn ).css('height', $( lastSide ).height() - 3);  // added by GALT
-                countN++;
-            }
-            if (altColors) {
-                // lastMatch and lastBlue or not lastMatch and notLastBlue
-                lastBlue = (lastMatchesLast === lastBlue); 
-                if (lastBlue)    // Too  smart by 1/3rd
-                    $( lastBtn ).addClass(    'btnBlue' );
-                else
-                    $( lastBtn ).removeClass( 'btnBlue' );
-            }
-            count++;
-        }
-        //warn("Zipped "+count+" buttons "+countN+" are independent.");
-    },
-
-    dragHandleMouseOver: function ()
-    {   // Highlights a single row when mouse over a dragHandle column (sideLabel and buttons)
-        if ( ! jQuery.tableDnD ) {
-            //var handle = $("td.dragHandle");
-            //$(handle)
-            //    .unbind('mouseenter')//, jQuery.tableDnD.mousemove);
-            //    .unbind('mouseleave');//, jQuery.tableDnD.mouseup);
-            return;
-        }
-        if ( ! jQuery.tableDnD.dragObject ) {
-            $( this ).parents("tr.trDraggable").addClass("trDrag");
-        }
-    },
-
-    dragHandleMouseOut: function ()
-    {   // Ends row highlighting by mouse over
-        $( this ).parents("tr.trDraggable").removeClass("trDrag");
-    },
-
-    buttonMouseOver: function ()
-    {   // Highlights a composite set of buttons, regarless of whether tracks are adjacent
-        if ( ! jQuery.tableDnD || ! jQuery.tableDnD.dragObject ) {
-            var classList = $( this ).attr("class").split(" ");
-            var btns = $( "p." + classList[0] );
-            $( btns ).removeClass('btnGrey');
-            $( btns ).addClass('btnBlue');
-            if (jQuery.tableDnD) {
-                var rows = dragReorder.getContiguousRowSet($(this).parents('tr.trDraggable')[0]);
-                if (rows)
-                    $( rows ).addClass("trDrag");
-            }
-        }
-    },
-
-    buttonMouseOut: function ()
-    {   // Ends composite highlighting by mouse over
-        var classList = $( this ).attr("class").split(" ");
-        var btns = $( "p." + classList[0] );
-        $( btns ).removeClass('btnBlue');
-        $( btns ).addClass('btnGrey');
-        if (jQuery.tableDnD) {
-            var rows = dragReorder.getContiguousRowSet($(this).parents('tr.trDraggable')[0]);
-            if (rows)
-            $( rows ).removeClass("trDrag");
-        }
-    },
-
-    trMouseOver: function (e)
-    {   // Trying to make sure there is always a imageV2.lastTrack so that we know where we are
-        var id = '';
-        var a = /tr_(.*)/.exec($(this).attr('id'));  // voodoo
-        if (a && a[1]) {
-            id = a[1];
-        }
-        if (id.length > 0) {
-            if ( ! imageV2.lastTrack || imageV2.lastTrack.id !== id)
-                imageV2.lastTrack = rightClick.makeMapItem(id); 
-                // currentMapItem gets set by mapItemMapOver.   This is just backup
-        }
-    },
-
-    mapItemMouseOver: function ()
-    {
-        // Record data for current map area item
-        var id = this.id;
-        if (!id || id.length === 0) {
-            id = '';
-            var tr = $( this ).parents('tr.imgOrd');
-            if ( $(tr).length === 1 ) {
-                var a = /tr_(.*)/.exec($(tr).attr('id'));  // voodoo
-                if (a && a[1]) {
-                    id = a[1];
-                }
-            }
-        }
-        if (id.length > 0) {
-            rightClick.currentMapItem = rightClick.makeMapItem(id);
-            if (rightClick.currentMapItem) {
-                rightClick.currentMapItem.href = this.href;
-                rightClick.currentMapItem.title = this.title;
-
-                // Handle linked features with separate clickmaps for each exon/intron 
-                if ((this.title.indexOf('Exon ') === 0) || (this.title.indexOf('Intron ') === 0)) {
-                    // if the title is Exon ... or Intron ... 
-                    // then search for the sibling with the same href
-                    // that has the real title item label
-                    var elem = this.parentNode.firstChild;
-                    while (elem) {
-                        if ((elem.href === this.href)
-                            && !((elem.title.indexOf('Exon ') === 0) || (elem.title.indexOf('Intron ') === 0))) {
-                            rightClick.currentMapItem.title = elem.title;
-                            break;
-                        }
-                        elem = elem.nextSibling;
-                    }
-                }
-
-            }
-        }
-    },
-
-    mapItemMouseOut: function ()
-    {
-        imageV2.lastTrack = rightClick.currentMapItem; // Just a backup
-        rightClick.currentMapItem = null;
-    },
-
-    init: function ()
-    {   // Make side buttons visible (must also be called when updating rows in the imgTbl).
-        var btns = $("p.btn");
-        if (btns.length > 0) {
-            dragReorder.zipButtons($('#imgTbl'));
-            $(btns).mouseenter( dragReorder.buttonMouseOver );
-            $(btns).mouseleave( dragReorder.buttonMouseOut  );
-            $(btns).show();
-        }
-        var handle = $("td.dragHandle");
-        if (handle.length > 0) {
-            $(handle).mouseenter( dragReorder.dragHandleMouseOver );
-            $(handle).mouseleave( dragReorder.dragHandleMouseOut  );
-        }
-
-        // setup mouse callbacks for the area tags
-        $(imageV2.imgTbl).find("tr").mouseover( dragReorder.trMouseOver );
-
-        // ensure clicks into hgTrackUi save the cart state
-        $("td a").each( function (tda) {
-            this.onclick = posting.saveSettings;
-        });
-
-        $(".area").each( function(t) {
-                            this.onmouseover = dragReorder.mapItemMouseOver;
-                            this.onmouseout = dragReorder.mapItemMouseOut;
-                            this.onclick = posting.mapClk;
-                        });
-    }
-};
 
 
   //////////////////////////
  //// Drag Scroll code ////
 //////////////////////////
 jQuery.fn.panImages = function(){
     // globals across all panImages
     genomePos.original = genomePos.getOriginalPos(); // redundant but makes certain original is set.
     var leftLimit   = hgTracks.imgBoxLeftLabel * -1;
     var rightLimit  = (hgTracks.imgBoxPortalWidth - hgTracks.imgBoxWidth + leftLimit);
     var only1xScrolling = ((hgTracks.imgBoxWidth - hgTracks.imgBoxPortalWidth) === 0);
     var prevX       = (hgTracks.imgBoxPortalOffsetX + hgTracks.imgBoxLeftLabel) * -1;
     var portalWidth = 0;
     var portalAbsoluteX = 0;
     var savedPosition;
@@ -4999,16 +4602,21 @@
 
         if ($('#hgTrackUiDialog'))
             $('#hgTrackUiDialog').hide();
 
         // Don't load contextMenu if jquery.contextmenu.js hasn't been loaded
         if (jQuery.fn.contextMenu) {
             rightClick.load(imageV2.imgTbl);
         }
     }
 
     // jquery.history.js Back-button support
     if (imageV2.enabled && imageV2.backSupport) {
         imageV2.setupHistory();
     }
 
+    // ensure clicks into hgTrackUi save the cart state
+    $("td a").each( function (tda) {
+        this.onclick = posting.saveSettings;
+    });
+
 });