420f3d256e332531c49df90c76fd4a303d2d8137 tdreszer Mon Nov 29 14:04:39 2010 -0800 Made filterComposite work with matrix. diff --git src/hg/js/hui.js src/hg/js/hui.js index 8c6c6fd..dea5442 100644 --- src/hg/js/hui.js +++ src/hg/js/hui.js @@ -15,40 +15,40 @@ // The 'mat*' functions are especially designed to support subtrack configuration by 2D matrix of controls function _matSelectViewForSubTracks(obj,view) { // viewDD:onchange Handle any necessary changes to subtrack checkboxes when the view changes // views are "select" drop downs on a subtrack configuration page var classesHidden = ""; // Needed for later if( obj.selectedIndex == 0) { // hide matSubCBsEnable(false,view); hideConfigControls(view); // Needed for later classesHidden = matViewClasses('hidden'); - classesHidden = classesHidden.concat( matAbcCBclasses('unchecked') ); + classesHidden = classesHidden.concat( matAbcCBclasses(false) ); } else { // Make main display dropdown show full if currently hide compositeName = obj.name.substring(0,obj.name.indexOf(".")); // {trackName}.{view}.vis exposeAll(); matSubCBsEnable(true,view); // Needed for later classesHidden = matViewClasses('hidden'); - classesHidden = classesHidden.concat( matAbcCBclasses('unchecked') ); + classesHidden = classesHidden.concat( matAbcCBclasses(false) ); // If hide => show then check all subCBs matching view and matCBs // If show => show than just enable subCBs for the view. if (obj.lastIndex == 0) { // From hide to show // If there are matCBs then we will check some subCBs if we just went from hide to show var matCBs = $("input.matCB:checked"); if (matCBs.length > 0) { // Get list of all checked abc classes first var classesAbcChecked = new Array(); matCBs.filter(".abc").each( function (i) { var classList = $( this ).attr("class").split(" "); classesAbcChecked.push( aryRemove(classList,"matCB","halfVis","abc") ); }); // Walk through checked non-ABC matCBs and sheck related subCBs @@ -99,31 +99,31 @@ // Make main display dropdown show full if currently hide var visDD = $("select.visDD"); // limit to hidden if ($(visDD).length == 1 && $(visDD).attr('selectedIndex') == 0) // limit to hidden $(visDD).attr('selectedIndex',$(visDD).children('option').length - 1); } function matSubCbClick(subCB) { // subCB:onclick When a subtrack checkbox is clicked, it may result in // Clicking/unclicking the corresponding matrix CB. Also the // subtrack may be hidden as a result. matSubCBsetShadow(subCB); hideOrShowSubtrack(subCB); // When subCBs are clicked, 3-state matCBs may need to be set var classes = matViewClasses('hidden'); - classes = classes.concat( matAbcCBclasses('unchecked') ); + classes = classes.concat( matAbcCBclasses(false) ); var matCB = matCbFindFromSubCb( subCB ); if( matCB != undefined ) { matChkBoxNormalize( matCB, classes ); } //var abcCB = matAbcCbFindFromSubCb( subCB ); //if( abcCB != undefined ) { // matChkBoxNormalize( abcCB, classes ); //} if(subCB.checked) exposeAll(); // Unhide composite vis? matSubCBsSelected(); } @@ -143,157 +143,167 @@ matSubCBsCheck(matCB.checked,classList[0],classList[1]); // dimX and dimY else warn("ASSERT in matCbClick(): There should be no more than 2 entries in list:"+classList) if(!isABC) matCbComplete(matCB,true); // No longer partially checked if(isABC) { // if dim ABC then we may have just made indeterminate X and Ys determinate if(matCB.checked == false) { // checking new dim ABCs cannot change indeterminate state. IS THIS TRUE ? So far. var matCBs = matCBsWhichAreComplete(false); if(matCBs.length > 0) { if($("input.matCB.abc:checked").length == 0) // No dim ABC checked, so leave X&Y checked but determined $( matCBs ).each( function (i) { matCbComplete( this, true ); }); else { var classes = matViewClasses('hidden'); - classes = classes.concat( matAbcCBclasses('unchecked') ); + classes = classes.concat( matAbcCBclasses(false) ); $( matCBs ).each( function (i) { matChkBoxNormalize( this, classes ); }); } } } } if(matCB.checked) exposeAll(); // Unhide composite vis? matSubCBsSelected(); } 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 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 0;ix++) { var filterClasses = $(filterComp[ix]).val(); - //alert(filterClasses); 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; } - //alert("filterComp:"+filterComp.length); } - // FIXME: What about mat dimensions? + // 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 + } + } + } - // What to do now? + // 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); }); } - //alert("Subtracks:"+subCBs.length+" To be selected:"+subCBsToSelect.length+" unselected:"+subCBsToUnselect.length) matSubCBsSelected(); - //$(obj).children("option:even").disabled = true; } ///////////// 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) function matSubCBsCheck(state) { // Set all subtrack checkboxes to state. If additional arguments are passed in, the list of CBs will be narrowed by the classes // called by matCB clicks (matCbClick()) ! var subCBs = $("input.subCB"); for(var vIx=1;vIx 0) { - if(limitTo == 'unchecked') { + if (!wantSelected) { abcCBs = abcCBs.not(":checked"); - } else if(limitTo == 'checked') { + } else { abcCBs = abcCBs.filter(":checked"); } $(abcCBs).each( function (i) { var classList = $( this ).attr("class").split(" "); classList = aryRemove(classList,"matCB","abc"); classes.push( classList[0] ); }); + } else { // No abcCBs so look for filterBox classes + return filterCompositeClasses(wantSelected); } return classes; } function matSubCBsSelected() { // Displays visible and checked track count var counter = $('.subCBcount'); if(counter != undefined) { var subCBs = $("input.subCB"); $(counter).text($(subCBs).filter(":enabled:checked").length + " of " +$(subCBs).length+ " selected"); } } /////////////////// subtrack configuration support //////////////// @@ -1225,61 +1237,78 @@ $(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); + 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" if($(obj).hasClass('filterBy')) return false; // 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); } } }); - // FIXME: What about mat dimensions? + // Matrix CBs need to be considered too + if (subCBs.length > 0) { + var matCb = $("input.matCb").filter(":checked"); + if (matCb.length == 0) + oneEmpty = true; + else {//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" + subCBs = $(subCBs).filter(matchClasses); + } + } + } // Walk through all selected subCBs to get other related tags var possibleSelections = [ ]; // empty array if(!oneEmpty) { $( subCBs ).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); } @@ -1290,30 +1319,57 @@ 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($(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++; + } + for(;ix