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 = "↓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 ? "↓":"↑"); - 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(); });