4c15f3e254d1e9c7cb3c4dca17f2808c07dbdb4f tdreszer Thu Jul 7 17:52:25 2011 -0700 Moved all ddcl extension code into a ddcl object in ddcl.js. Reworked filterComp code to be more like filterTable code since IE was getting timeouts on HAIB TFBS. diff --git src/hg/js/hui.js src/hg/js/hui.js index 7581a9c..3aeee27 100644 --- src/hg/js/hui.js +++ src/hg/js/hui.js @@ -155,129 +155,82 @@ $( matCBs ).each( function (i) { matCbComplete( this, true ); }); else { var classes = matViewClasses('hidden'); classes = classes.concat( matAbcCBclasses(false) ); $( matCBs ).each( function (i) { matChkBoxNormalize( this, classes ); }); } } } } if(matCB.checked) exposeAll(); // Unhide composite vis? matSubCBsSelected(); } -function matSetMatrixCheckBoxes(state) +function _matSetMatrixCheckBoxes(state) { // matButtons:onclick Set all Matrix checkboxes to state. If additional arguments are passed in, the list of CBs will be narrowed by the classes //jQuery(this).css('cursor', 'wait'); var matCBs = $("input.matCB").not(".abc"); for(var vIx=1;vIx<arguments.length;vIx++) { matCBs = $( matCBs ).filter("."+arguments[vIx]); // Successively limit list by additional classes. } $( matCBs ).each( function (i) { this.checked = state; matCbComplete(this,true); }); - subCDs = $("input.subCB"); + subCbs = $("input.subCB"); for(var vIx=1;vIx<arguments.length;vIx++) { - subCDs = $( subCDs ).filter("."+arguments[vIx]); // Successively limit list by additional classes. + subCbs = $( subCbs ).filter("."+arguments[vIx]); // Successively limit list by additional classes. } if(state) { // If clicking [+], further limit to only checked ABCs var classes = matAbcCBclasses(false); - subCDs = objsFilterByClasses(subCDs,"not",classes); // remove unchecked abcCB classes + subCbs = objsFilterByClasses(subCbs,"not",classes); // remove unchecked abcCB classes } - $( subCDs ).each( function (i) { + $( subCbs ).each( function (i) { this.checked = state; matSubCBsetShadow(this); }); if(state) exposeAll(); // Unhide composite vis? showOrHideSelectedSubtracks(); matSubCBsSelected(); //jQuery(this).css('cursor', ''); - return true; -} - -function filterCompositeSelectionChanged(obj) -{ // filterComposite:onchange Set subtrack selection based upon the changed filter [Not called for filterBy] - if($(obj).val() != undefined - && $(obj).val().toString().indexOf("All,") != -1) { - $(obj).val("All"); - $(obj).attr('selectedIndex',0); - } - // Get list of values which should match classes of subtracks - var classes = $(obj).val(); // It is already an array! - if(classes == null) { // Nothing is selected. Mark with "[empty]" - classes = ""; - setCartVar($(obj).attr('name'),"[empty]"); // FIXME: setCartVar conflicts with "submit" button paradigm - } - - // For all subtracks that DO NOT match selected classes AND are checked: uncheck - var subCBs = $("input.subCB"); - var subCBsToUnselect = subCBs; - if (classes.length > 0 && classes[0] != "All") - subCBsToUnselect = objsFilterByClasses(subCBsToUnselect,"not",classes); // remove unchecked classes - if (subCBsToUnselect.length > 0) - subCBsToUnselect = $(subCBsToUnselect).filter(":checked"); - if (subCBsToUnselect.length > 0) - subCBsToUnselect.each( function (i) { matSubCBcheckOne(this,false); }); - - // For all subtracks that DO match a selected class AND are NOT checked: - // Figure out if other selection criteria match. If so: check - //var subCBs = $("input.subCB"); - var subCBsToSelect = subCBs; - if(classes.length > 0) { - if(classes.length > 0 && classes[0] != "All") - subCBsToSelect = objsFilterByClasses(subCBsToSelect,"or",classes); // Keep any that should be selected - // Now deal with all the others - if (subCBsToSelect.length > 0) { - var filterComp = $("select.filterComp").not("[name='"+obj.name+"']"); // Exclude self from list - for(var ix=0;ix<filterComp.length && subCBsToSelect.length > 0;ix++) { - var filterClasses = $(filterComp[ix]).val(); - if(filterClasses.length > 0 && filterClasses[0] != "All") - subCBsToSelect = objsFilterByClasses(subCBsToSelect,"or",filterClasses); // Keep any that should be selected - else if(filterClasses.length == 0) - subCBsToSelect.length = 0; - } - } - // Filter for Matrix CBs too - if (subCBsToSelect.length > 0) { - var matCb = $("input.matCB").filter(":checked"); - if (matCb.length > 0) { - var matchClasses = ""; - $( matCb ).each( function(i) { - var filterClasses = $( this ).attr("class").split(" "); - filterClasses = aryRemove(filterClasses,"matCB","halfVis","abc"); - matchClasses = matchClasses + ",." + filterClasses.join('.'); - }); - if (matchClasses.length > 0) { - matchClasses = matchClasses.substring(1); // Skip past leading comma: ",.HepG2.ZBTB33,.GM12878.CTCF" - subCBsToSelect = $(subCBsToSelect).filter(matchClasses); // Keep any that should be selected - } - } + var tbody = $( subCbs[0] ).parents('tbody.sorting'); + if (tbody != undefined) + $(tbody).removeClass('sorting'); + return true; } +function matSetMatrixCheckBoxes(state) +{ + var tbody = $( 'tbody.sortable'); + if (tbody != undefined) + $(tbody).addClass('sorting'); + + if (arguments.length >= 5) + waitOnFunction(_matSetMatrixCheckBoxes,state,arguments[1],arguments[2],arguments[3],arguments[4]); + else if (arguments.length >= 4) + waitOnFunction(_matSetMatrixCheckBoxes,state,arguments[1],arguments[2],arguments[3]); + else if (arguments.length >= 3) + waitOnFunction(_matSetMatrixCheckBoxes,state,arguments[1],arguments[2]); + else if (arguments.length >= 2) + waitOnFunction(_matSetMatrixCheckBoxes,state,arguments[1]); + else + waitOnFunction(_matSetMatrixCheckBoxes,state); - // Now we have subCBs that should be checked. Exclude already checked, then do it - if (subCBsToSelect.length > 0) - subCBsToSelect = $(subCBsToSelect).not(":checked"); - if (subCBsToSelect.length > 0) - subCBsToSelect.each( function (i) { matSubCBcheckOne(this,true); }); - } - matSubCBsSelected(); } ///////////// CB support routines /////////////// // Terms: // viewDD - view drop-down control // matButton: the [+][-] button controls associated with the matrix // matCB - matrix dimX and dimY CB controls (in some cases this set contains abcCBs as well because they are part of the matrix) // abcCB - matrix dim (ABC) CB controls // subCB - subtrack CB controls // What does work // 1) 4 state subCBs: checked/unchecked enabled/disabled (which is visible/hidden) // 2) 3 state matCBs for dimX and Y but not for Z (checked,unchecked,indeterminate (incomplete set of subCBs for this matCB)) // 3) cart vars for viewDD, abcCBs and subCBs but matCBs set by the state of those 3 // What is awkward or does not work // A) Awkward: matCB could be 5 state (all,none,subset,superset,excusive non-matching set) @@ -862,145 +815,256 @@ obj.selectedIndex = ix; obj.size=1; $(obj).trigger('change'); break; } } }*/ } function filterCompositeSet(obj,all) { // Will set all filter composites via [+] or [-] buttons matSubCBsCheck(all); var vars = []; var vals = []; - var filterComp = $("select.filterComp").not(".filterBy"); + var filterComp = $("select.filterComp"); if(all) { $(filterComp).each(function(i) { $(this).trigger("checkAll"); $(this).val("All"); //vars.push($(this).attr('name')); // Don't bother ajaxing this over //vals.push($(this).val()); }); } else { $(filterComp).each(function(i) { $(this).trigger("uncheckAll"); $(this).val(""); vars.push($(this).attr('name')); vals.push("[empty]"); }); } if(vars.length > 0) { setCartVars(vars,vals);// FIXME: setCartVar conflicts with "submit" button paradigm } matSubCBsSelected(); // Be sure to update the counts! } -function filterCompositeExcludeOptions(obj) -{ // Will mark all options in one filterComposite boxes that are inconsistent with the current - // selections in other filterComposite boxes. Mark is class ".excluded" +function matCbFilterClasses(matCb,joinThem) +{ // returns the var associated with a filterComp - if($(obj).hasClass('filterBy')) - return false; + var classes = $( matCb ).attr("class").split(" "); + classes = aryRemove(classes,"matCB","halfVis","abc"); + if (joinThem) + return '.' + classes.join('.'); + return classes; +} - // Walk through all other dimensions and narrow list of subCBs that are selected - // NOTE: narrowing the list should by each dimension other than current one is the same as - // getting the selected CB list if the current dimension selected all - var allSelectedTags = [ ]; // empty array - var oneEmpty = false; - var subCBs = $("input.subCB"); - var filterComp = $("select.filterComp").not("#"+$(obj).attr('id')); // Exclude self from list - $( filterComp ).each( function (i) { - if( $( subCBs ).length > 0 ) { - var selectedTags = $( this ).val(); - if( !selectedTags || selectedTags.length == 0) - oneEmpty = true; - else if( selectedTags && selectedTags.length > 0 && selectedTags[0] != "All" ) { - subCBs = objsFilterByClasses(subCBs,"or",selectedTags); // must belong to one or more - allSelectedTags = allSelectedTags.concat(selectedTags); +function filterCompFilterVar(filter) +{ // returns the var associated with a filterComp + + if($(filter).hasClass('filterComp') == false) + return undefined; + + // Find the var for this filter + var parts = $(filter).attr("name").split('.'); + return parts[parts.length - 1]; } + +function filterCompApplyOneFilter(filter,subCbsRemaining) +{ // Applies a single filter to a filterTables TRs + var classes = $(filter).val(); + if (classes == null || classes.length == 0) + return []; // Nothing selected so exclude all rows + + if(classes[0] == 'All') + return subCbsRemaining; // nothing excluded by this filter + + var subCbsAccumulating = []; + for(var ix =0;ix<classes.length;ix++) { + var subCBOneFIlter = $(subCbsRemaining).filter('.' + classes[ix]); + if (subCBOneFIlter.length > 0) + subCbsAccumulating = jQuery.merge( subCbsAccumulating, subCBOneFIlter ); } - }); - // Matrix CBs need to be considered too - if (subCBs.length > 0) { - var matCb = $("input.matCB").filter(":checked"); + //warnSince('filterCompApplyOneFilter('+filterCompFilterVar(filter)+','+subCbsRemaining.length+')'); + return subCbsAccumulating; +} + +function filterCompApplyOneMatCB(matCB,remainingCBs) +{ // Applies a single filter to a filterTables TRs + var classes = matCbFilterClasses(matCB,true); + if (classes == null || classes.length == 0) + return []; // Nothing selected so exclude all rows + + //warnSince('filterCompApplyOneMatCB('+classes+','+remainingCBs.length+'); + return $(remainingCBs).filter(classes); +} + +function filterCompSubCBsSurviving(filterClass) +// returns a list of trs that satisfy all filters +// If defined, will exclude filter identified by filterClass +{ + // find all filterable table rows + var subCbsFiltered = $("input.subCB");// Default all + if (subCbsFiltered.length == 0) + return []; + + //warnSince('filterCompSubCBsSurviving() start: '+ subCbsFiltered.length); + + // Find all filters + var filters = $("select.filterComp"); + if (filters.length == 0) + return []; + + // Exclude one if requested. + if (filterClass != undefined && filterClass.length > 0) + filters = $(filters).not("[name$='" + filterClass + "']"); + + for(var ix =0;subCbsFiltered.length > 0 && ix < filters.length;ix++) { + subCbsFiltered = filterCompApplyOneFilter(filters[ix],subCbsFiltered); // successively reduces + } + + // Filter for Matrix CBs too + if (subCbsFiltered.length > 0) { + var matCbAll = $("input.matCB"); + var matCb = $(matCbAll).filter(":checked"); + if (matCbAll.length > matCb.length) { if (matCb.length == 0) - oneEmpty = true; - else {//if (matCb.length > 0) { - // If all selected, no additional filtering needed. - if (matCb.length < $("input.matCB").length) { - var matchClasses = ""; - $( matCb ).each( function(i) { - var filterClasses = $( this ).attr("class").split(" "); - filterClasses = aryRemove(filterClasses,"matCB","halfVis","abc"); - matchClasses = matchClasses + ",." + filterClasses.join('.'); - }); - if (matchClasses.length > 0) { - matchClasses = matchClasses.substring(1); // Skip past leading comma: ",.HepG2.ZBTB33,.GM12878.CTCF" - if ($.browser.msie) { // IE was hanging on .filter(matchClasses), so do this ourselves - var matchSets = matchClasses.split(','); - var subsAccumulating = null; - while(matchSets.length > 0) { - var matchThis = matchSets.pop(); - var subBatch = $(subCBs).filter(matchThis); - if (subBatch != undefined && subBatch.length > 0) { - //subCBs = $(subCBs).not(matchThis); // Would be nice to split the subCBs - if (subsAccumulating == null || subsAccumulating.length == 0) - subsAccumulating = subBatch; - else - subsAccumulating = jQuery.merge(subsAccumulating,subBatch); + subCbsFiltered = []; + else { + var subCbsAccumulating = []; + for(var ix =0;ix<matCb.length;ix++) { + var subCBOneFIlter = filterCompApplyOneMatCB(matCb[ix],subCbsFiltered); + if (subCBOneFIlter.length > 0) + filteredCBs = jQuery.merge( subCbsAccumulating, subCBOneFIlter ); } + subCbsFiltered = subCbsAccumulating; } - subCBs = subsAccumulating; - } else - subCBs = $(subCBs).filter(matchClasses); } } + //warnSince('filterCompSubCBsSurviving() matrix: '+subCbsFiltered.length); + return subCbsFiltered; +} + +function _filterComposite() +{ // Called when filterComp selection changes. Will check/uncheck subtracks + var subCbsSelected = filterCompSubCBsSurviving(); + + // Uncheck: + var subCbsToUnselect = $("input.subCB:checked");// Default all + if (subCbsToUnselect.length > 0) + $(subCbsToUnselect).each( function (i) { matSubCBcheckOne(this,false); }); + //warnSince('done with uncheck'); + + // check: + if (subCbsSelected.length > 0) + $(subCbsSelected).each( function (i) { matSubCBcheckOne(this,true); }); + //warnSince('done with check'); + + // Update count + matSubCBsSelected(); + //warnSince('done'); + + var tbody = $( subCbsSelected[0] ).parents('tbody.sorting'); + if (tbody != undefined) + $(tbody).removeClass('sorting'); +} + +function filterCompositeTrigger() +{ // Called when filterComp selection changes. Will check/uncheck subtracks + var tbody = $( 'tbody.sortable'); + if (tbody != undefined) + $(tbody).addClass('sorting'); + + waitOnFunction(_filterComposite); +} + +function filterCompositeDone(event) +{ // Called by custom 'done' event + event.stopImmediatePropagation(); + $(this).unbind( event ); + filterCompositeTrigger(); + //waitOnFunction(filterCompositeTrigger,$(this)); +} + +function filterCompositeSelectionChanged(obj) +{ // filterComposite:onchange Set subtrack selection based upon the changed filter [Not called for filterBy] + + var subCBs = $("input.subCB"); + if ( subCBs.length > 300) { + //if ($.browser.msie) { // IE takes tooo long, so this should be called only when leaving the filterBy box + $(obj).one('done',filterCompositeDone); + return; + //} + } else + filterCompositeTrigger(); } + +function filterCompositeExcludeOptions(multiSelect) +{ // Will mark all options in one filterComposite boxes that are inconsistent with the current + // selections in other filterComposite boxes. Mark is class ".excluded" + // Compare to the list of all trs + var allSubCBs = $("input.subCB"); + if (allSubCBs.length == 0) + return false; + + if ($.browser.msie && $(allSubCBs).filter(":checked") > 300) // IE takes tooo long, so this should be called only when leaving the filterBy box + return false; + + var filterClass = filterCompFilterVar(multiSelect); + if (filterClass == undefined) + return false; + + // Look at list of CBs that would be selected if all were selected for this filter + var subCbsSelected = filterCompSubCBsSurviving(filterClass); + if (subCbsSelected.length == 0) + return false; + + if (allSubCBs.length == subCbsSelected.length) { + $(multiSelect).children('option.excluded').removeClass('excluded'); // remove .excluded" from all + return true; } + //warnSince('filterCompositeExcludeOptions('+filterClass+'): subCbsSelected: '+subCbsSelected.length); // Walk through all selected subCBs to get other related tags var possibleSelections = [ ]; // empty array - if(!oneEmpty) { - $( subCBs ).each( function (i) { + $( subCbsSelected ).each( function (i) { var possibleClasses = $( this ).attr("class").split(" "); if( $(possibleClasses).length > 0) possibleClasses = aryRemoveVals(possibleClasses,[ "subCB" ]); if( $(possibleClasses).length > 0) possibleSelections = possibleSelections.concat(possibleClasses); }); - if( $ (possibleSelections).length > 0) // clean out tags from other dimensions - possibleSelections = aryRemoveVals(possibleSelections,allSelectedTags); - } + //warnSince('filterCompositeExcludeOptions('+filterClass+'): possibleSelections: '+possibleSelections.length); // Walk through all options in this filterBox to set excluded class - //warn(possibleSelections,toString()); var updated = false; - var opts = $(obj).children("option"); - for(var ix = 1;ix < $(opts).length;ix++) { // All is always allowwed - if(!oneEmpty && possibleSelections.length > 0 && aryFind(possibleSelections,opts[ix].value) == -1) { + if(possibleSelections.length > 0) { + var opts = $(multiSelect).children("option"); + for(var ix = 1;ix < $(opts).length;ix++) { // All is always allowed + if(aryFind(possibleSelections,opts[ix].value) == -1) { if($(opts[ix]).hasClass('excluded') == false) { $(opts[ix]).addClass('excluded'); updated = true; } } else if($(opts[ix]).hasClass('excluded')) { $(opts[ix]).removeClass('excluded'); updated = true; } } + } return updated; } function filterCompositeClasses(wantSelected) {// returns an array of classes from the dim ABC filterComp classes: converts "matCB abc rep1"[]s to "rep1","rep2" var classes = new Array; var abcFBs = $("select.filterComp"); if(abcFBs.length > 0) { $(abcFBs).each( function(i) { // Need to walk through list of options var ix=0; var allAreSelected = false; if (this.options[ix].value == "All") { allAreSelected = this.options[ix].selected; ix++; @@ -1086,27 +1150,22 @@ $(document).ready(function() { // Initialize sortable tables $('table.sortable').each(function (ix) { sortTableInitialize(this,true,true); }); // Register tables with drag and drop $("table.tableWithDragAndDrop").each(function (ix) { tableDragAndDropRegister(this); }); $('.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 - if (newJQuery) { - if ($(this).hasClass('filterBy')) - ddclSetup(this, 'noneIsAll'); - else - ddclSetup(this); - } else + if (newJQuery == false) $(this).dropdownchecklist({ firstItemChecksAll: true, noneIsAll: $(this).hasClass('filterBy'), maxDropHeight: filterByMaxHeight(this) }); }); // Put navigation links in top corner navigationLinksSetup(); });