d3ed4e62c1515da4f6c9417545b657a412a8d0df
tdreszer
  Fri Feb 25 12:05:08 2011 -0800
Moved code from 'hgTracks.js' to common 'utils.js' and added support for multi-selects in file and track search
diff --git src/hg/js/utils.js src/hg/js/utils.js
index 869d6ba..e6a7efe 100644
--- src/hg/js/utils.js
+++ src/hg/js/utils.js
@@ -1658,15 +1658,481 @@
 // return appropriate width for hgTracks image given users current window width
     return $(window).width() - 20;
 }
 
 function hgTracksSetWidth()
 {
     var winWidth = calculateHgTracksWidth();
     if($("#imgTbl").length == 0) {
         // XXXX what's this code for?
         $("#TrackForm").append('<input type="hidden" name="pix" value="' + winWidth + '"/>');
         //$("#TrackForm").submit();
     } else {
         $("input[name=pix]").val(winWidth);
     }
 }
+
+/////////////////////////////////////////////////////
+// findTracks functions
+
+function updateMetaDataHelpLinks(index)
+{
+// update the metadata help links based on currently selected values.
+// If index == 0 we update all help items, otherwise we only update the one == index.
+    var db = getDb();
+    var disabled = {  // blackList
+        'accession': 1, 'dataType':        1, 'dataVersion': 1, 'geoSample':    1, 'grant':     1,
+        'lab':       1, 'labExpId':        1, 'labVersion':  1, 'origAssembly': 1, 'replicate': 1,
+        'setType':   1, 'softwareVersion': 1, 'subId':       1, 'view':         1
+    }
+    var expected = $('tr.mdbSelect').length;
+    var ix=1;
+    if (index!=0) {
+        ix=index;
+        expected=index;
+    }
+    for(;ix <= expected;ix++) {
+        var helpLink = $("span#helpLink" + ix);
+        if (helpLink.length > 0) {
+            var val = $("select[name='hgt_mdbVar" + ix + "']").val();  // NOTE must match METADATA_NAME_PREFIX in hg/hgTracks/searchTracks.c
+            var text = $("select[name='hgt_mdbVar" + ix + "'] option:selected").text();
+            helpLink.html("&nbsp;"); // Do not want this with length == 0 later!
+            if (typeof(disabled[val]) == 'undefined') {
+                var str;
+                if (val == 'cell') {
+                    if (db.substr(0, 2) == "mm") {
+                        str = "../ENCODE/cellTypesMouse.html";
+                    } else {
+                        str = "../ENCODE/cellTypes.html";
+                    }
+                } else if (val.toLowerCase() == 'antibody') {
+                    str = "../ENCODE/antibodies.html";
+                } else {
+                    str = "../ENCODE/otherTerms.html#" + val;
+                }
+                helpLink.html("<a target='_blank' title='detailed descriptions of terms' href='" + str + "'>" + text + "</a>");
+            }
+        }
+    }
+}
+
+function findTracksMdbVarChanged(obj)
+{ // Ajax call to repopulate a metadata vals select when mdb var changes
+  // This handles the currnet case when 2 vars have the same name (e.g. advanced, files tabs)
+
+    findTracksClearFound();  // Changing values so abandon what has been found
+
+    var newVar = $(obj).val();
+    var a = /hgt_mdbVar(\d+)/.exec(obj.name); // NOTE must match METADATA_NAME_PREFIX in hg/hgTracks/searchTracks.c
+    if(newVar != undefined && a && a[1]) {
+        var num = a[1];
+        if ($('#advancedTab').length == 1 && $('#filesTab').length == 1) {
+            $("select.mdbVar[name='hgt_mdbVar"+num+"'][value!='"+newVar+"']").val(newVar);
+        }
+        $.ajax({
+                   type: "GET",
+                   url: "../cgi-bin/hgApi",
+                   data: "db=" + getDb() +  "&cmd=hgt_mdbVal" + num + "&var=" + newVar,
+                   trueSuccess: findTracksHandleNewMdbVals,
+                   success: catchErrorOrDispatch,
+                   error: errorHandler,
+                   cache: true,
+                   cmd: "hgt_mdbVal" + num, // NOTE must match METADATA_VALUE_PREFIX in hg/hgTracks/searchTracks.c
+                   num: num
+               });
+    }
+    //findTracksSearchButtonsEnable(true);
+}
+
+function findTracksHandleNewMdbVals(response, status)
+{ // Handle ajax response (repopulate a metadata val select)
+  // This handles the currnet case when 2 vars have the same name (e.g. advanced, files tabs)
+
+    var td = $('td#' + this.cmd );
+    if (td != undefined) {
+        var usesFilterBy = ($("select.mdbVar[name='hgt_mdbVar"+this.num+"']").hasClass('noMulti') == false);
+        td.empty();
+        td.append(response);
+        var inp = $(td).find('.mdbVal');
+        var tdIsLike = $('td#isLike'+this.num);
+        if (inp != undefined && tdIsLike != undefined) {
+            if ($(inp).hasClass('freeText')) {
+                $(tdIsLike).text('contains');
+            } else if (usesFilterBy && $(inp).hasClass('filterBy')) {
+                $(tdIsLike).text('is (any of)');
+            } else {
+                $(tdIsLike).text('is');
+            }
+        }
+        $(td).find('.filterBy').each( function(i) { // Do this by 'each' to set noneIsAll individually
+            if (usesFilterBy) {
+                $(this).dropdownchecklist({ firstItemChecksAll: true, noneIsAll: true });
+            } else {
+                $(this).attr("multiple",false);
+                $(this).removeClass('filterBy');
+                $(this).show();
+            }
+        });
+    }
+    updateMetaDataHelpLinks(this.num);
+}
+
+function findTracksMdbValChanged(obj)
+{ // Keep all tabs with same selects in sync  TODO: Change from name to id based identification and only have one set of inputs in form
+  // This handles the currnet case when 2 vars have the same name (e.g. advanced, files tabs)
+
+    findTracksClearFound();  // Changing values so abandon what has been found
+
+    if ($('#advancedTab').length == 1 && $('#filesTab').length == 1) {
+        var newVal = $(obj).val();
+        var a = /hgt_mdbVal(\d+)/.exec(obj.name); // NOTE must match METADATA_NAME_PREFIX in hg/hgTracks/searchTracks.c
+        if(newVal != undefined && a && a[1]) {
+            var num = a[1];
+            $("input.mdbVal[name='hgt_mdbVal"+num+"'][value!='"+newVal+"']").val(newVal);
+            $("select.mdbVal[name='hgt_mdbVal"+num+"'][value!='"+newVal+"']").each( function (i) {
+                $(this).val(newVal);
+                if ($(this).hasClass('filterBy')) {
+                    //$(this).dropdownchecklist("refresh");  // requires v1.1
+                    $(this).dropdownchecklist("destroy");
+                    $(this).dropdownchecklist({ firstItemChecksAll: true, noneIsAll: true });
+                }
+            });
+        }
+    }
+    //findTracksSearchButtonsEnable(true);
+}
+
+function findTracksChangeVis(seenVis)
+{ // called by onchange of vis
+    var visName = $(seenVis).attr('id');
+    var trackName = visName.substring(0,visName.length - "_id".length)
+    var hiddenVis = $("input[name='"+trackName+"']");
+    var tdb = tdbGetJsonRecord(trackName);
+    if($(seenVis).val() != "hide")
+        $(hiddenVis).val($(seenVis).val());
+    else {
+        var selCb = $("input#"+trackName+"_sel_id");
+        $(selCb).attr('checked',false);  // Can't set it to [] because that means default setting is used.  However, we are explicitly hiding this!
+        $(seenVis).attr('disabled',true);  // Can't set it to [] because that means default setting is used.  However, we are explicitly hiding this!
+        var needSel = (tdb.parentTrack != undefined);
+        if (needSel) {
+            var hiddenSel = $("input[name='"+trackName+"_sel']");
+            $(hiddenSel).val('0');  // Can't set it to [] because that means default setting is used.  However, we are explicitly hiding this!
+            $(hiddenSel).attr('disabled',false);
+        }
+        if(tdbIsSubtrack(tdb))
+            $(hiddenVis).val("[]");
+        else
+            $(hiddenVis).val("hide");
+    }
+    $(hiddenVis).attr('disabled',false);
+
+    $('input.viewBtn').val('View in Browser');
+    //warn("Changed "+trackName+" to "+$(hiddenVis).val())
+}
+
+function findTracksClickedOne(selCb,justClicked)
+{ // called by on click of CB and findTracksCheckAll()
+    var selName = $(selCb).attr('id');
+    var trackName = selName.substring(0,selName.length - "_sel_id".length)
+    var hiddenSel = $("input[name='"+trackName+"_sel']");
+    var seenVis = $('select#' + trackName + "_id");
+    var hiddenVis = $("input[name='"+trackName+"']");
+    var tr = $(selCb).parents('tr.found');
+    var tdb = tdbGetJsonRecord(trackName);
+    var needSel = (tdb.parentTrack != undefined);
+    var shouldPack = tdb.canPack && tdb.kindOfParent == 0; // If parent then not pack but full
+    if (shouldPack && tdb.shouldPack != undefined && !tdb.shouldPack)
+        shouldPack = false;
+    var checked = $(selCb).attr('checked');
+    //warn(trackName +" selName:"+selName +" justClicked:"+justClicked +" hiddenSel:"+$(hiddenSel).attr('name') +" seenVis:"+$(seenVis).attr('id') +" hiddenVis:"+$(hiddenVis).attr('name') +" needSel:"+needSel +" shouldPack:"+shouldPack);
+
+    // First deal with seenVis control
+    if(checked) {
+        $(seenVis).attr('disabled', false);
+        if($(seenVis).attr('selectedIndex') == 0) {
+            if(shouldPack)
+                $(seenVis).attr('selectedIndex',3);  // packed
+            else
+                $(seenVis).attr('selectedIndex',$(seenVis).attr('length') - 1);
+        }
+    } else {
+        $(seenVis).attr('selectedIndex',0);  // hide
+        $(seenVis).attr('disabled', true );
+    }
+
+    // Deal with hiddenSel and hiddenVis so that submit does the right thing
+    // Setting these requires justClicked OR seen vs. hidden to be different
+    var setHiddenInputs = justClicked;
+    if(!justClicked) {
+        if(needSel)
+            setHiddenInputs = (checked != ($(hiddenSel).val() == '1'));
+        else if (checked)
+            setHiddenInputs = ($(seenVis).val() != $(hiddenVis).val());
+        else
+            setHiddenInputs = ($(hiddenVis).val() != "hide" && $(hiddenVis).val() != "[]");
+    }
+    if(setHiddenInputs) {
+        if(checked)
+            $(hiddenVis).val($(seenVis).val());
+        else if(tdbIsSubtrack(tdb))
+            $(hiddenVis).val("[]");
+        else
+            $(hiddenVis).val("hide");
+        $(hiddenVis).attr('disabled',false);
+
+        if(needSel) {
+            if(checked)
+                $(hiddenSel).val('1');
+            else
+                $(hiddenSel).val('0');  // Can't set it to [] because that means default setting is used.  However, we are explicitly hiding this!
+            $(hiddenSel).attr('disabled',false);
+        }
+    }
+
+    // The "view in browser" button should be enabled/disabled
+    if(justClicked) {
+        $('input.viewBtn').val('View in Browser');
+        findTracksCounts();
+    }
+}
+
+
+function findTracksNormalize()
+{ // Normalize the page based upon current state of all found tracks
+    $('div#found').show()
+    var selCbs = $('input.selCb');
+
+    // All should have their vis enabled/disabled appropriately (false means don't update cart)
+    $(selCbs).each( function(i) { findTracksClickedOne(this,false); });
+
+    findTracksCounts();
+}
+
+function findTracksNormalizeWaitOn()
+{ // Put up wait mask then Normalize the page based upon current state of all found tracks
+    waitOnFunction( findTracksNormalize );
+}
+
+function findTracksCheckAll(check)
+{ // Checks/unchecks all found tracks.
+    var selCbs = $('input.selCb');
+    $(selCbs).attr('checked',check);
+
+    // All should have their vis enabled/disabled appropriately (false means don't update cart)
+    $(selCbs).each( function(i) { findTracksClickedOne(this,false); });
+
+    $('input.viewBtn').val('View in Browser');
+    findTracksCounts();
+    return false;  // Pressing button does nothing more
+}
+
+function findTracksCheckAllWithWait(check)
+{
+    waitOnFunction( findTracksCheckAll, check);
+}
+
+function findTracksSearchButtonsEnable(enable)
+{ // Displays visible and checked track count
+    var searchButton = $('input[name="hgt_tSearch"]'); // NOTE: must match TRACK_SEARCH in hg/inc/searchTracks.h
+    var clearButton  = $('input.clear');
+    if(enable) {
+        $(searchButton).attr('disabled',false);
+        $(clearButton).attr('disabled',false);
+    } else {
+        $(searchButton).attr('disabled',true);
+        $(clearButton).attr('disabled',true);
+    }
+}
+
+function findTracksCounts()
+{// Displays visible and checked track count
+    var counter = $('.selCbCount');
+    if(counter != undefined) {
+        var selCbs =  $("input.selCb");
+        $(counter).text("("+$(selCbs).filter(":enabled:checked").length + " of " +$(selCbs).length+ " selected)");
+    }
+}
+
+function findTracksClearFound()
+{// Clear found tracks and all input controls
+    var found = $('div#found');
+    if(found != undefined)
+        $(found).remove();
+    found = $('div#filesFound');
+    if(found != undefined)
+        $(found).remove();
+    return false;
+}
+
+function findTracksClear()
+{// Clear found tracks and all input controls
+    findTracksClearFound();
+    $('input[type="text"]').val(''); // This will always be found
+    //$('select.mdbVar').attr('selectedIndex',0); // Do we want to set the first two to cell/antibody?
+    $('select.mdbVal').attr('selectedIndex',0); // Should be 'Any'
+    $('select.filterBy').each( function(i) { // Do this by 'each' to set noneIsAll individually
+          //$(this).dropdownchecklist("refresh");  // requires v1.1
+          $(this).dropdownchecklist("destroy");
+          $(this).dropdownchecklist({ firstItemChecksAll: true, noneIsAll: true });
+    });
+
+    $('select.groupSearch').attr('selectedIndex',0);
+    $('select.typeSearch').attr('selectedIndex',0);
+    //findTracksSearchButtonsEnable(false);
+    return false;
+}
+
+function findTracksSortNow(obj)
+{// Called by radio button to sort tracks
+    if( $('#sortIt').length == 0 )
+        $('form#trackSearch').append("<input TYPE=HIDDEN id='sortIt' name='"+$(obj).attr('name')+"' value='"+$(obj).val()+"'>");
+    else
+        $('#sortIt').val($(obj).val());
+
+    // How to hold onto selected tracks?
+    // There are 2 separate forms.  Scrape named inputs from searchResults form and dup them on trackSearch?
+    var inp = $('form#searchResults').find('input:hidden').not(':disabled').not("[name='hgsid']");
+    if($(inp).length > 0) {
+        $(inp).appendTo('form#trackSearch');
+        $('form#trackSearch').attr('method','POST'); // Must be post to avoid url too long  NOTE: probably needs to be post anyway
+    }
+
+    $('#searchSubmit').click();
+    return true;
+}
+
+function findTracksPage(pageVar,startAt)
+{// Called by radio button to sort tracks
+    var pager = $("input[name='"+pageVar+"']");
+    if( $(pager).length == 1)
+        $(pager).val(startAt);
+
+    // How to hold onto selected tracks?
+    // There are 2 separate forms.  Scrape named inputs from searchResults form and dup them on trackSearch?
+    var inp = $('form#searchResults').find('input:hidden').not(':disabled').not("[name='hgsid']");
+    if($(inp).length > 0) {
+        $(inp).appendTo('form#trackSearch');
+        $('form#trackSearch').attr('method','POST'); // Must be post to avoid url too long  NOTE: probably needs to be post anyway
+    }
+
+    $('#searchSubmit').click();
+    return false;
+}
+
+function findTracksConfigureSet(name)
+{// Called when configuring a composite or superTrack
+    var thisForm =  $('form#searchResults');
+    $(thisForm).attr('action',"../cgi-bin/hgTrackUi?hgt_tSearch=Search&g="+name);
+    $(thisForm).find('input.viewBtn').click();
+}
+
+function findTracksMdbSelectPlusMinus(obj, rowNum)
+{ // Now [+][-] mdb var rows with javascript rather than cgi roundtrip
+  // Will remove row or clone new one.  Complication is that 'advanced' and 'files' tab duplicate the tables!
+
+    var objId = $(obj).attr('id');
+    rowNum = objId.substring(objId.length - 1);
+    if ($(obj).val() == '+') {
+        var buttons = $("input#plusButton"+rowNum);  // Two tabs may have the exact same buttons!
+        if (buttons.length > 0) {
+            $(buttons).each(function (i) {
+                var tr = $(this).parents('tr.mdbSelect')[0];
+                if (tr != undefined)
+                    $(tr).after( $(tr).clone() );
+                findTracksMdbSelectRowsNormalize($(tr).parents('table')[0]); // magic is in this function
+            });
+            return false;
+        }
+    } else { // == '-'
+        var buttons = $("input#minusButton"+rowNum);  // Two tabs may have the exact same buttons!
+        if (buttons.length > 0) {
+            var remaining = 0;
+            $(buttons).each(function (i) {
+                var tr = $(this).parents('tr')[0];
+                var table = $(tr).parents('table')[0];
+                if (tr != undefined)
+                    $(tr).remove();
+                remaining = findTracksMdbSelectRowsNormalize(table);  // Must renormalize since 2nd of 3 rows may have been removed
+            });
+            if (remaining > 0) {
+                removeNum = remaining + 1;  // Got to remove the cart vars, though it doesn't matter which as count must not be too many.
+                setCartVars( [ "hgt_mdbVar"+removeNum, "hgt_mdbVal"+removeNum ], [ "[]","[]" ] );
+            }
+
+            findTracksClearFound();  // Changing values so abandon what has been found
+            return false;
+        }
+    }
+    return true;
+}
+
+function findTracksMdbSelectRowsNormalize(table)
+{ // Called when [-][+] buttons changed the number of mdbSelects in findTracks\
+  // Will walk through each row and get the numberings of addressable elements correct.
+    if (table != undefined) {
+        var mdbSelectRows = $(table).find('tr.mdbSelect');
+        var needMinus = (mdbSelectRows.length > 2);
+        $(table).find('tr.mdbSelect').each( function (ix) {
+            var rowNum = ix + 1;  // Each [-][+] and mdb var=val pair of selects must be numbered
+
+            // First the [-][+] buttons
+            var plusButton = $(this).find("input[value='+']")[0];
+            if (plusButton != undefined) {
+                $(plusButton).attr('id',"plusButton"+rowNum);
+                $(plusButton).unbind('click')
+                $(plusButton).click(function() { return findTracksMdbSelectPlusMinus($(plusButton), rowNum); });
+                var minusButton = $(this).find("input[value='-']")[0];
+                if (needMinus) {
+                    if (minusButton == undefined) {
+                        $(plusButton).before("<input type='button' id='minusButton"+rowNum+"' value='-' style='font-size:.7em;' title='delete this row' onclick='return findTracksMdbSelectPlusMinus(this,"+rowNum+");'>");
+                        minusButton = $(this).find("input[value='-']")[0];
+                    } else {
+                        $(minusButton).attr('id',"minusButton"+rowNum);
+                        $(minusButton).unbind('click');
+                        $(minusButton).click(function() { return findTracksMdbSelectPlusMinus($(minusButton), rowNum); });
+                    }
+                } else if (minusButton != undefined)
+                    $(minusButton).remove();
+            }
+            // Now the mdb var=val pair of selects
+            var element = $(this).find("select[name^='hgt_mdbVar']")[0];
+            if (element != undefined)
+                $(element).attr('name','hgt_mdbVar' + rowNum);
+
+            element = $(this).find("select[name^='hgt_mdbVal']")[0];
+            if (element != undefined)
+                $(element).attr('name','hgt_mdbVal' + rowNum);
+
+            // A couple more things
+            element = $(this).find("td[id^='isLike']")[0];
+            if (element != undefined)
+                $(element).attr('id','isLike' + rowNum);
+            element = $(this).find("td[id^='hgt_mdbVal']")[0];
+            if (element != undefined)
+                $(element).attr('id','hgt_mdbVal' + rowNum);
+        });
+        return mdbSelectRows.length;
+    }
+    return 0;
+}
+
+function findTracksSwitchTabs(ui)
+{ // switching tabs on findTracks page
+
+    if( ui.panel.id == 'simpleTab' && $('div#found').length < 1) {
+        setTimeout("$('input#simpleSearch').focus();",20); // delay necessary, since select event not afterSelect event
+    }
+    if( $('div#filesFound').length == 1) {
+        if( ui.panel.id == 'filesTab')
+            $('div#filesFound').show();
+        else
+            $('div#filesFound').hide();
+    }
+    if( $('div#found').length == 1) {
+        if( ui.panel.id != 'filesTab')
+            $('div#found').show();
+        else
+            $('div#found').hide();
+    }
+}
+