d5a899c5160879ab7198e4d8a468d0771349fb86
tdreszer
  Fri Dec 10 09:27:35 2010 -0800
Moved sort routines from hui.js to utils.js and rewrote them so they are not hgTrackUi subtrack list specific.  Use table.sortable to make almost any table sortable
diff --git src/hg/js/hui.js src/hg/js/hui.js
index dea5442..2589e18 100644
--- src/hg/js/hui.js
+++ src/hg/js/hui.js
@@ -624,30 +624,32 @@
     var visible = (obj.selectedIndex != 0);
     if (visible) {
         updateOrMakeNamedVariable(theForm,trackName_Sel,"1");
     } else
         disableNamedVariable(theForm,trackName_Sel);
     return true;
 }
 
 function subtrackCfgHideAll(table)
 {
 // hide all the subtrack configuration stuff
     $("div[id $= '_cfg']").each( function (i) {
         $( this ).css('display','none');
         $( this ).children("input[name$='.childShowCfg']").val("off");
     });
+    // Hide all "..." metadata displayed
+    $("div[id $= '_meta']:visible").toggle();
 }
 
 var popUpTrackName;
 var popUpTitle = "";
 var popSaveAllVars = null;
 function popUpCfgOk(popObj, trackName)
 { // Kicks off a Modal Dialog for the provided content.
     var allVars = getAllVars(popObj, trackName );   // always subtrack cfg
     var changedVars = varHashChanges(allVars,popSaveAllVars);
     //warn("cfgVars:"+varHashToQueryString(changedVars));
     setVarsFromHash(changedVars);
     var newVis = changedVars[trackName];
     if(newVis != null) {
         var sel = $('input[name="'+trackName+'_sel"]:checkbox');
         var checked = (newVis != 'hide' && newVis != '[]');  // subtracks do not have "hide", thus '[]'
@@ -757,424 +759,53 @@
 // Will show configuration controls for name= {tableName}.{view}
 // Config controls not matching name will be hidden
     var trs  = $("tr[id^='tr_cfg_']")
     $("input[name$='.showCfg']").val("off"); // Turn all off
     $( trs ).each( function (i) {
         if( this.id == 'tr_cfg_'+name && this.style.display == 'none') {
             $( this ).css('display','');
 	    $("input[name$='."+name+".showCfg']").val("on");
         }
         else if( this.style.display == '') {
             $( this ).css('display','none');
         }
     });
 
     // Close the cfg controls in the subtracks
-    $("table[id^='subtracks.']").each( function (i) { subtrackCfgHideAll(this);} );
+    $("table.subtracks").each( function (i) { subtrackCfgHideAll(this);} );
     return true;
 }
 
-function trAlternateColors(table,cellIx)
-{
-// Will alternate colors each time the contents of the column(s) change
-    var lastContent = "not";
-    var bgColor1 = "#FFFEE8";
-    var bgColor2 = "#FFF9D2";
-    var curColor = bgColor1;
-    var lastContent = "start";
-    var cIxs = new Array();
-
-    for(var aIx=1;aIx<arguments.length;aIx++) {   // multiple columns
-        cIxs[aIx-1] = arguments[aIx];
-    }
-    if (document.getElementsByTagName)
-    {
-        for (var trIx=0;trIx<table.rows.length;trIx++) {
-            var curContent = "";
-            if(table.rows[trIx].style.display == 'none')
-                continue;
-            for(var ix=0;ix<cIxs.length;ix++) {
-                if(table.rows[trIx].cells[cIxs[ix]]) {
-                    curContent = (table.rows[trIx].cells[cIxs[ix]].abbr != "" ?
-                                  table.rows[trIx].cells[cIxs[ix]].abbr       :
-                                  table.rows[trIx].cells[cIxs[ix]].innerHTML  );
-                }
-            }
-            if( lastContent != curContent ) {
-                lastContent  = curContent;
-                if( curColor == bgColor1)
-                    curColor =  bgColor2;
-                else
-                    curColor =  bgColor1;
-            }
-            table.rows[trIx].bgColor = curColor;
-        }
-    }
-}
-
-//////////// Sorting ////////////
-
-function tableSort(table,fnCompare)
-{
-// Sorts table based upon rules passed in by function reference
-    //alert("tableSort("+table.id+") is beginning.");
-    subtrackCfgHideAll(table);
-    var trs=0,moves=0;
-    var colOrder = new Array();
-    var cIx=0;
-    var trTopIx,trCurIx,trBottomIx=table.rows.length - 1;
-    for(trTopIx=0;trTopIx < trBottomIx;trTopIx++) {
-        trs++;
-        var topRow = table.rows[trTopIx];
-        for(trCurIx = trTopIx + 1; trCurIx <= trBottomIx; trCurIx++) {
-            var curRow = table.rows[trCurIx];
-            var compared = fnCompare(topRow,curRow,arguments[2]);
-            if(compared < 0) {
-                table.insertBefore(table.removeChild(curRow), topRow);
-                topRow = curRow; // New top!
-                moves++;
-            }
-        }
-    }
-    if(fnCompare != trComparePriority)
-        tableSetPositions(table);
-    //alert("tableSort("+table.id+") examined "+trs+" rows and made "+moves+" moves.");
-}
-
-// Sorting a table by columns relies upon the sortColumns structure
-// The sortColumns structure looks like:
-//{
-//    char *  tags[];     // a list of trackDb.subGroupN tags in sort order
-//    boolean reverse[];  // the sort direction for that subGroup
-//    int     cellIxs[];  // The indexes of the columns in the table to be sorted
-//}
-///// Following functions are for Sorting by columns:
-function trCompareColumnAbbr(tr1,tr2,sortColumns)
-{
-// Compares a set of columns based upon the contents of their abbr
-    for(var ix=0;ix < sortColumns.cellIxs.length;ix++) {
-        //if(tr1.cells[sortColumns.cellIxs[ix]].abbr == undefined) {
-        //    if(tr1.cells[sortColumns.cellIxs[ix]].value < tr2.cells[sortColumns.cellIxs[ix]].value)
-        //        return (sortColumns.reverse[ix] ? -1: 1);
-        //    else if(tr1.cells[sortColumns.cellIxs[ix]].value > tr2.cells[sortColumns.cellIxs[ix]].value)
-        //        return (sortColumns.reverse[ix] ? 1: -1);
-        //} else {
-            if(tr1.cells[sortColumns.cellIxs[ix]].abbr < tr2.cells[sortColumns.cellIxs[ix]].abbr)
-                return (sortColumns.reverse[ix] ? -1: 1);
-            else if(tr1.cells[sortColumns.cellIxs[ix]].abbr > tr2.cells[sortColumns.cellIxs[ix]].abbr)
-                return (sortColumns.reverse[ix] ? 1: -1);
-        //}
-    }
-    return 0;
-}
-
-
-function tableSortByColumns(table,sortColumns)
-{
-// Will sort the table based on the abbr values on a et of <TH> colIds
-    if (document.getElementsByTagName)
-    {
-        tableSort(table,trCompareColumnAbbr,sortColumns);//cellIxs,columns.colRev);
-                        var columns = new sortColumnsGetFromTable(table);
-        if(sortColumns.tags.length>1)
-            trAlternateColors(table,sortColumns.cellIxs[sortColumns.tags.length-2]);
-
-    }
-}
-
-function sortOrderFromColumns(sortColumns)
-{// Creates the trackDB setting entry sortOrder subGroup1=+ ... from a sortColumns structure
-    var sortOrder ="";
-    for(ix=0;ix<sortColumns.tags.length;ix++) {
-        sortOrder += sortColumns.tags[ix] + "=" + (sortColumns.reverse[ix] ? "-":"+") + " ";
-    }
-    if(sortOrder.length > 0)
-        sortOrder = sortOrder.substr(0,sortOrder.length-1);
-    return sortOrder;
-}
-
-function sortOrderFromTr(tr)
-{// Looks up the sortOrder input value from a *.sortTr header row of a sortable table
-    var inp = tr.getElementsByTagName('input');
-    for(var ix=0;ix<inp.length;ix++) {
-        var offset = inp[ix].id.lastIndexOf(".sortOrder");
-        if(offset > 0 && offset == inp[ix].id.length - 10)
-            return inp[ix].value;
-    }
-    return "";
-}
-function sortColumnsGetFromSortOrder(sortOrder)
-{// Creates sortColumns struct (without cellIxs[]) from a trackDB.sortOrder setting string
-    this.tags = new Array();
-    this.reverse = new Array();
-    var order = sortOrder;
-    for(var ix=0;ix<12;ix++) {
-        if(order.indexOf("=") <= 0)
-            break;
-        this.tags[ix]    = order.substring(0,order.indexOf("="));
-        this.reverse[ix] = (order.substr(this.tags[ix].length+1,1) != '+');
-        if(order.length < (this.tags[ix].length+2))
-            break;
-        order = order.substring(this.tags[ix].length+3);
-    }
-}
-function sortColumnsGetFromTr(tr)
-{// Creates a sortColumns struct from the entries in the '*.sortTr' heading row of a sortable table
-    this.inheritFrom = sortColumnsGetFromSortOrder;
-    var inp = tr.getElementsByTagName('input');
-    var ix;
-    for(ix=0;ix<inp.length;ix++) {
-        var offset = inp[ix].id.lastIndexOf(".sortOrder");
-        if(offset > 0 && offset == inp[ix].id.length - 10) {
-            this.inheritFrom(inp[ix].value);
-            break;
-        }
-    }
-    if(ix == inp.length)
-        return;
-
-    // Add an additional array
-    this.cellIxs = new Array();
-    var cols = tr.getElementsByTagName('th');
-    for(var tIx=0;tIx<this.tags.length;tIx++) {
-        var colIdTag = this.tags[tIx] + ".sortTh";
-        for(ix=0; ix<cols.length; ix++) {
-            var offset = cols[ix].id.lastIndexOf(colIdTag);
-            if(offset > 0 && offset == cols[ix].id.length - colIdTag.length) {
-                this.cellIxs[tIx] = cols[ix].cellIndex;
-            }
-        }
-    }
-}
-function sortColumnsGetFromTable(table)
-{// Creates a sortColumns struct from the contents of a '*.sortable' table
-    this.inheritNow = sortColumnsGetFromTr;
-    var ix;
-    for(ix=0;ix<table.rows.length;ix++) {
-        var offset = table.rows[ix].id.lastIndexOf(".sortTr");
-        if(offset > 0 && offset == table.rows[ix].id.length - 7) {
-            this.inheritNow(table.rows[ix]);
-            break;
-        }
-    }
-}
-
-
-function tableSortUsingSortColumns(table)
-{// Sorts a table body based upon the marked columns
-    var columns = new sortColumnsGetFromTable(table);
-    tbody = table.getElementsByTagName("tbody")[0];
-    tableSortByColumns(tbody,columns);
-}
-
-function _tableSortAtButtonPressEncapsulated(anchor,tagId)
-{// Updates the sortColumns struct and sorts the table when a column header has been pressed
- // If the current primary sort column is pressed, its direction is toggled then the table is sorted
- // If a secondary sort column is pressed, it is moved to the primary spot and sorted in fwd direction
-    var th=anchor.parentNode;
-    var sup=th.getElementsByTagName("sup")[0];
-    var tr=th.parentNode;
-    var inp = tr.getElementsByTagName('input');
-    var iIx;
-    for(iIx=0;iIx<inp.length;iIx++) {
-        var offset = inp[iIx].id.lastIndexOf(".sortOrder");
-        if(offset > 0 && offset == inp[iIx].id.length - 10)
-            break;
-    }
-    var theOrder = new sortColumnsGetFromTr(tr);
-    var oIx;
-    for(oIx=0;oIx<theOrder.tags.length;oIx++) {
-        if(theOrder.tags[oIx] == tagId)
-            break;
-    }
-    if(oIx > 0) { // Need to reorder
-        var newOrder = new sortColumnsGetFromTr(tr);
-        var nIx=0;
-        newOrder.tags[nIx] = theOrder.tags[oIx];
-        newOrder.reverse[nIx] = false;  // When moving to the first position sort forward
-        newOrder.cellIxs[nIx] = theOrder.cellIxs[ oIx];
-        sups = tr.getElementsByTagName("sup");
-        sups[newOrder.cellIxs[nIx]-1].innerHTML = "&darr;1";
-        for(var ix=0;ix<theOrder.tags.length;ix++) {
-            if(ix != oIx) {
-                nIx++;
-                newOrder.tags[nIx]    = theOrder.tags[ix];
-                newOrder.reverse[nIx] = theOrder.reverse[ix];
-                newOrder.cellIxs[nIx] = theOrder.cellIxs[ix];
-                var dir = sups[newOrder.cellIxs[nIx]-1].innerHTML.substring(0,1);
-                sups[newOrder.cellIxs[nIx]-1].innerHTML = dir + (nIx+1);
-            }
-        }
-        theOrder = newOrder;
-    } else { // need to reverse directions
-        theOrder.reverse[oIx] = (theOrder.reverse[oIx] == false);
-        var ord = sup.innerHTML.substring(1);
-        sup.innerHTML = (theOrder.reverse[oIx] == false ? "&darr;":"&uarr;");
-        if(theOrder.tags.length>1)
-            sup.innerHTML += ord;
-    }
-    //alert("tableSortAtButtonPress(): count:"+theOrder.tags.length+" tag:"+theOrder.tags[0]+"="+(theOrder.reverse[0]?"-":"+"));
-    var newSortOrder = sortOrderFromColumns(theOrder);
-    inp[iIx].value = newSortOrder;
-    var thead=tr.parentNode;
-    var table=thead.parentNode;
-    tbody = table.getElementsByTagName("tbody")[0];
-    tableSortByColumns(tbody,theOrder);
-    return;
-
-}
-
-function tableSortAtButtonPress(anchor,tagId)
-{
-    waitOnFunction( _tableSortAtButtonPressEncapsulated, anchor, tagId);
-}
-
-function tableSortAtStartup()
-{
-    //alert("tableSortAtStartup() called");
-    var list = document.getElementsByTagName('table');
-    for(var ix=0;ix<list.length;ix++) {
-        var offset = list[ix].id.lastIndexOf(".sortable");  // TODO: replace with class and jQuery
-        if(offset > 0 && offset == list[ix].id.length - 9) {
-            tableSortUsingSortColumns(list[ix]);
-        }
-    }
-}
-
-function hintOverSortableColumnHeader(th)
-{// Upodates the sortColumns struct and sorts the table when a column headder has been pressed
-    //th.title = "Click to make this the primary sort column, or toggle direction";
-    //var tr=th.parentNode;
-    //th.title = "Current Sort Order: " + sortOrderFromTr(tr);
-}
-
-///// Following functions are for Sorting by priority
-function tableSetPositions(table)
-{
-// Sets the value for the *.priority input element of a table row
-// This gets called by sort or dradgndrop in order to allow the new order to affect hgTracks display
-    if (table.getElementsByTagName)
-    {
-        for(var trIx=0;trIx<table.rows.length;trIx++) {
-            if(table.rows[trIx].id.indexOf("tr_cb_") == 0) {
-                var inp = table.rows[trIx].getElementsByTagName('input');
-                for(var ix=0;ix<inp.length;ix++) {
-                    var offset = inp[ix].name.lastIndexOf(".priority");
-                    if( offset > 0 && offset == (inp[ix].name.length - 9)) {
-                        inp[ix].value = table.rows[trIx].rowIndex;
-                        break;
-                    }
-                }
-            }
-        }
-    }
-}
-function trFindPosition(tr)
-{
-// returns the position (*.priority) of a sortable table row
-    var inp = tr.getElementsByTagName('input');
-    for(var ix=0;ix<inp.length;ix++) {
-        var offset = inp[ix].name.indexOf(".priority");
-        if(offset > 0 && offset == (inp[ix].name.length - 9)) {
-            return inp[ix].value;
-        }
-    }
-    return "unknown";
-}
-
-function trComparePriority(tr1,tr2)
-{
-// Compare routine for sorting by *.priority
-    var priority1 = 999999;
-    var priority2 = 999999;
-    var inp1 = tr1.getElementsByTagName('input');
-    var inp2 = tr2.getElementsByTagName('input');
-    for(var ix=0;ix<inp1.length;ix++) { // should be same length
-        if(inp1[ix].name.indexOf(".priority") == (inp1[ix].name.length - 9))
-            priority1 = inp1[ix].value;
-        if(inp2[ix].name.indexOf(".priority") == (inp2[ix].name.length - 9))
-            priority2 = inp2[ix].value;
-        if(priority1 < 999999 && priority2 < 999999)
-            break;
-    }
-    return priority2 - priority1;
-}
-
-///// Following functions support column reorganization
-function trReOrderCells(tr,cellIxFrom,cellIxTo)
-{
-// Reorders cells in a table row: removes cell from one spot and inserts it before another
-    //alert("tableSort("+table.id+") is beginning.");
-    if(cellIxFrom == cellIxTo)
-        return;
-
-    var tdFrom = tr.cells[cellIxFrom];
-    var tdTo   = tr.cells[cellIxTo];
-    if((cellIxTo - cellIxFrom) == 1) {
-        tdFrom = tr.cells[cellIxTo];
-        tdTo   = tr.cells[cellIxFrom];
-    } else if((cellIxTo - cellIxFrom) > 1)
-        tdTo   = tr.cells[cellIxTo + 1];
-
-    tr.insertBefore(tr.removeChild(tdFrom), tdTo);
-}
-
-function tableReOrderColumns(table,cellIxFrom,cellIxTo)
-{
-// Reorders cells in all the rows of a table row, thus reordering columns
-    if (table.getElementsByTagName) {
-        for(var ix=0;ix<table.rows.length;ix++) {
-            var offset = table.rows[ix].id.lastIndexOf(".sortTr");
-            if(offset > 0 && offset == table.rows[ix].id.length - 7) {
-                trReOrderCells(table.rows[ix],cellIxFrom,cellIxTo);
-                break;
-            }
-        }
-        tbody = table.getElementsByTagName('tbody');
-        for(var ix=0;ix<tbody[0].rows.length;ix++) {
-            trReOrderCells(tbody[0].rows[ix],cellIxFrom,cellIxTo);
-        }
-    }
-}
-
 function showOrHideSelectedSubtracks(inp)
 {
 // Show or Hide subtracks based upon radio toggle
     var showHide;
     if(arguments.length > 0)
         showHide=inp;
     else {
         var onlySelected = $("input[name='displaySubtracks']");
         if(onlySelected.length > 0)
             showHide = onlySelected[0].checked;
         else
             return;
     }
     showSubTrackCheckBoxes(showHide);
-    var list = $("table.tableSortable")
-    for(var ix=0;ix<list.length;ix++) {
-        var columns = new sortColumnsGetFromTable(list[ix]);
-        var tbody = list[ix].getElementsByTagName('tbody');
-        if(columns.tags.length>1) {
-            if(columns.tags.length==2)
-                trAlternateColors(tbody[0],columns.cellIxs[0]);
-            else if(columns.tags.length==3)
-                trAlternateColors(tbody[0],columns.cellIxs[0],columns.cellIxs[1]);
-            else
-                trAlternateColors(tbody[0],columns.cellIxs[0],columns.cellIxs[1],columns.cellIxs[2]);
-        }
-    }
+
+    var tbody = $("tbody.sortable")
+    $(tbody).each(function (i) {
+        sortedTableAlternateColors(this);
+    });
 }
 
 ///// Following functions called on page load
 function matInitializeMatrix()
 {
 // Called at Onload to coordinate all subtracks with the matrix of check boxes
 //var start = startTiming();
 jQuery('body').css('cursor', 'wait');
     if (document.getElementsByTagName) {
         matSubCBsSelected();
         showOrHideSelectedSubtracks();
     }
 jQuery('body').css('cursor', '');
 //showTiming(start,"matInitializeMatrix()");
 }
@@ -1402,55 +1033,60 @@
     }
 
     // Decide if top links are needed
     var navUp = $('span.navUp');
     if($(navUp) != undefined && $(navUp).length > 0) {
         $(navUp).each(function(i) {
             var offset = $(this).parent().offset();
             if(offset.top  > $(window).height()) {
                 $(this).css({display:''});
                 $(this).show();
             }
         });
     }
 }
 
+function tableSortAtButtonPress(anchor,tagId)
+{ // Special ONLY for hgTrackUi sorting.  Others use utils.js::tableSortOnButtonPress()
+    var table = $( anchor ).parents("table.sortable");
+    if (table) {
+        subtrackCfgHideAll(table);
+        waitOnFunction( _tableSortOnButtonPressEncapsulated, anchor, tagId);
+    }
+    return false;  // called by link so return false means don't try to go anywhere
+}
+
 // The following js depends upon the jQuery library
 $(document).ready(function()
 {
     //jQuery.each(jQuery.browser, function(i, val) {
     //    if(val) {
     //        browser = i;
     //    }
     //});
-    //matInitializeMatrix();
-    //$("div.multiSelectContainer").each( function (i) {
-    //    var sel = $(this).children("select:first");
-    //    multiSelectLoad(this,sel.openSize);
-    //});
 
     // Allows rows to have their positions updated after a drag event
     var tblDnd = $(".tableWithDragAndDrop");
     if($(tblDnd).length > 0) {
         $(tblDnd).tableDnD({
             onDragClass: "trDrag",
             dragHandle: "dragHandle",
             onDrop: function(table, row, dragStartIndex) {
                     if(tableSetPositions) {
                         tableSetPositions(table);
                     }
                 }
             });
-        $(".dragHandle").hover(
-            function(){ $(this).parent('tr').addClass('trDrag'); },
-            function(){ $(this).parent('tr').removeClass('trDrag'); }
+        $("td.dragHandle").hover(
+            function(){ $(this).closest('tr').addClass('trDrag'); },
+            function(){ $(this).closest('tr').removeClass('trDrag'); }
         );
     }
     $('.halfVis').css('opacity', '0.5'); // The 1/2 opacity just doesn't get set from cgi!
 
     $('.filterComp').each( function(i) { // Do this by 'each' to set noneIsAll individually
         $(this).dropdownchecklist({ firstItemChecksAll: true, noneIsAll: $(this).hasClass('filterBy') });
     });
 
     // Put navigation links in top corner
     navigationLinksSetup();
 });