edbd78ba2667d41249ee0c521d49304c038ffeb1 galt Fri Feb 19 17:27:19 2021 -0800 Added counts to hgTrackUi facets. refs #25321 diff --git src/hg/js/hui.js src/hg/js/hui.js index 4255b3e..56db978 100644 --- src/hg/js/hui.js +++ src/hg/js/hui.js @@ -30,44 +30,46 @@ // 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 matCBs = $("input.matCB:checked"); if (matCBs.length > 0) { // Get list of all checked abc classes first var classesAbcChecked = []; matCBs.filter(".abc").each( function (i) { var classList = $( this ).attr("class").split(" "); classesAbcChecked.push( aryRemove(classList,["matCB","changed","disabled","abc"]) ); }); - // Walk through checked non-ABC matCBs and sheck related subCBs - var subCBs = $("input.subCB").filter("."+view).not(":checked"); + // Walk through checked non-ABC matCBs and check related subCBs + var subCbsSelected = filterCompSubCBsSurviving(); + var subCBs = $(subCbsSelected).filter("."+view).not(":checked"); matCBs.not(".abc").each( function (i) { var classList = $( this ).attr("class").split(" "); classList = aryRemove(classList,["matCB","changed","disabled"]); var subCBsMatching = objsFilterByClasses(subCBs,"and",classList); if (classesAbcChecked.length>0) subCBsMatching = objsFilterByClasses(subCBsMatching,"or",classesAbcChecked); // Check the subCBs that belong to this view and checked matCBs subCBsMatching.each( function (i) { this.checked = true; matSubCBsetShadow(this,true); // will update "subCfg" if needed hideOrShowSubtrack(this); }); + }); } // If no matrix, then enabling is all that was needed. // fix 3-way which may need to go from unchecked to .disabled matCBs = $("input.matCB").not(".abc").not(".disabled").not(":checked"); if (matCBs.length > 0) { $( matCBs ).each( function (i) { matChkBoxNormalize( this, classesHidden ); }); } } } // fix 3-way matCBs which may need to go from disabled to checked or unchecked depending matCBs = matCBsWhichAreComplete(false); if (matCBs.length > 0) { if ($("select.viewDD").not("[selectedIndex=0]").length === 0) { // No views visible so $( matCBs ).each( function (i) { matCbComplete( this, true ); });// nothing inconsistent @@ -158,64 +160,65 @@ 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 + var matCBs = $("input.matCB").not(".abc"); for (var vIx=1;vIx<arguments.length;vIx++) { matCBs = $( matCBs ).filter("."+arguments[vIx]); // Successively limit list } $( matCBs ).each( function (i) { this.checked = state; matCbComplete(this,true); }); var subCbs = $("input.subCB"); for (var sIx=1;sIx<arguments.length;sIx++) { subCbs = $( subCbs ).filter("."+arguments[sIx]); // Successively limit list } if (state) { // If clicking [+], further limit to only checked ABCs var classes = matAbcCBclasses(false); subCbs = objsFilterByClasses(subCbs,"not",classes); // remove unchecked abcCB classes } $( subCbs ).each( function (i) { if (this.checked !== state) { this.checked = state; matSubCBsetShadow(this,false); $(this).change(); // NOTE: if "subCfg" then 'change' event will update it } }); if (state) exposeAll(); // Unhide composite vis? showOrHideSelectedSubtracks(); matSubCBsSelected(); - //jQuery(this).css('cursor', ''); - var tbody = normed($(subCbs[0]).parents('tbody.sorting')); + var tbody = normed($('tbody.sortable')); if (tbody) $(tbody).removeClass('sorting'); return true; } + function matSetMatrixCheckBoxes(state) { // Called exclusively by matrix [+][-] buttons on click var tbody = normed($('tbody.sortable')); if (tbody) $(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]); @@ -485,30 +488,35 @@ } else { // No abcCBs so look for filterBox classes return filterCompositeClasses(wantSelected); } return classes; } function matSubCBsSelected() { // Displays visible and checked track count var counter = normed($('.subCBcount')); if (counter) { var subCBs = $("input.subCB"); // subCfg uses fauxDisabled $(counter).text($(subCBs).filter(":enabled:checked").not('.disabled').length + " of " +$(subCBs).length+ " selected"); } + + if (typeof(ddcl) === "object") { + setTimeout(function(){ ddcl.reinitFacetCounts(); }, 50); + } + } /////////////////// subtrack configuration support //////////////// function compositeCfgUpdateSubtrackCfgs(inp) { // Updates all subtrack configuration values when the composite cfg is changed // If view association then find it: var view = ""; var list = null; var daddy = normed($(inp).parents(".blueBox")); if (daddy) { var classList = $(daddy).attr("class").split(" "); if (classList.length === 2) { view = classList[1]; } @@ -878,117 +886,203 @@ { // 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); }); // check: if (subCbsSelected.length > 0) $(subCbsSelected).each( function (i) { matSubCBcheckOne(this,true); }); // Update count matSubCBsSelected(); - var tbody = normed($(subCbsSelected[0]).parents('tbody.sorting')); + var tbody = normed($('tbody.sortable')); if (tbody) $(tbody).removeClass('sorting'); } function filterCompositeTrigger() { // Called when filterComp selection changes. Will check/uncheck subtracks var tbody = normed($('tbody.sortable')); if (tbody) $(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) { $(obj).one('done',filterCompositeDone); return; } else filterCompositeTrigger(); + } +function filterCountFacets(possibleClasses, hiddenViewClasses, possibleSelections) +{ + + possibleClasses = aryRemove(possibleClasses,[ "subCB","changed","disabled" ]); + + if ($(possibleClasses).length > 0) { + + if (aryFind(hiddenViewClasses, possibleClasses[possibleClasses.length-1])=== -1) { + + for (var vIx=0; vIx < possibleClasses.length; vIx++) { + var onePoss = possibleClasses[vIx]; + if (possibleSelections[onePoss] === undefined) { + possibleSelections[onePoss] = 1; + } else { + ++possibleSelections[onePoss]; + } + } + + } + } +} + +function filterCompositeExcludeOptionsQuick(multiSelect, possibleSelections) +{ // Will mark all options in one filterComposite boxes that are inconsistent with the current + // selections in other filterComposite boxes. Mark is class ".excluded" + + var magic = "Magic23541236746574569670787890877563457346846578452346457435645t794312"; + + if (possibleSelections[magic] === undefined) { + + var allSubCBs = $("input.subCB"); + if (allSubCBs.length === 0) { + return false; + } + + // IE takes tooo long, so this should be called only when leaving the filterBy box + if (theClient.isIePre11() && $(allSubCBs).filter(":checked").length > 300) + return false; + + // Walk through all subCBs to get other related tags + $( allSubCBs ).each( function (i) { + // is it viz? + if (this.checked && isFauxDisabled(this,true) === false) { + var possibleClasses = $( this ).attr("class").split(" "); + // [] because it does not need view filtering + filterCountFacets(possibleClasses, [], possibleSelections); + } + }); + possibleSelections[magic] = 1; // mark that it has been initialized + } + + + // Walk through all options in this filterBox to set excluded class + var opts = $(multiSelect).children("option"); + for (var ix = 1;ix < opts.length;ix++) { // All is always allowed + var count = possibleSelections[opts[ix].value]; + if (count === undefined) { + count = 0; + } + opts[ix].facetCount = count; + } + + return true; + +} + + 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) + if (allSubCBs.length === 0) { return false; + } // IE takes tooo long, so this should be called only when leaving the filterBy box if (theClient.isIePre11() && $(allSubCBs).filter(":checked").length > 300) return false; - var filterClass = filterCompFilterVar(multiSelect); - if (!filterClass || filterClass.length === 0) + var filterClass = filterCompFilterVar(multiSelect); // returns facet name e.g. sample_source + if (!filterClass || filterClass.length === 0) { return false; + } + var updated = 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; + var subCbsSelected = filterCompSubCBsSurviving(filterClass); // apply facet filters for all columns except this one. + if (subCbsSelected.length === 0) { + updated = true; + } if (allSubCBs.length === subCbsSelected.length) { $(multiSelect).children('option.excluded').removeClass('excluded'); - return true; + updated = true; } + // Walk through all selected subCBs to get other related tags - var possibleSelections = []; // empty array - $( subCbsSelected ).each( function (i) { + var possibleSelections = {}; // empty object acting as hash for selected tracks + var possibleSelectionsX = {}; // for non-selected tracks, used for not selected but choosable facet values. + + hiddenViewClasses=matViewClasses('hidden'); + $( subCbsSelected ).each( function (i) { var possibleClasses = $( this ).attr("class").split(" "); - if ($(possibleClasses).length > 0) - possibleClasses = aryRemove(possibleClasses,[ "subCB","changed","disabled" ]); - if ($(possibleClasses).length > 0) - possibleSelections = possibleSelections.concat(possibleClasses); + // is subtrack selected and viz? + if (this.checked && isFauxDisabled(this,true) === false) { + filterCountFacets(possibleClasses, hiddenViewClasses, possibleSelections); + } else { + filterCountFacets(possibleClasses, hiddenViewClasses, possibleSelectionsX); + } }); // Walk through all options in this filterBox to set excluded class - var updated = false; - 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) { + var count = possibleSelections[opts[ix].value]; + if (count === undefined) { + count = possibleSelectionsX[opts[ix].value]; + if (count === undefined) { + count = 0; + } + } + opts[ix].facetCount = count; + if (count === 0) { if ($(opts[ix]).hasClass('excluded') === false) { $(opts[ix]).addClass('excluded'); updated = true; } - } else if ($(opts[ix]).hasClass('excluded')) { + } 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 = []; 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;