4d5351b79fa9248f97b5ee2a2f6a8acb4b9a4e27
tdreszer
  Thu Jul 24 16:54:17 2014 -0700
Going from fauxVis to the drop-down select in one click really does a number on IE11, causing it to hang.  This fix requires IE11 users to perform 2 clicks to set subtrack visibility. Perhaps Angie can find a more graceful solution, but it probably isn't worth the time.  Redmine #13678.
diff --git src/hg/js/subCfg.js src/hg/js/subCfg.js
index dabbfe8..1221ed5 100644
--- src/hg/js/subCfg.js
+++ src/hg/js/subCfg.js
@@ -1,886 +1,890 @@
 // subCfg the subtrack Configureation module (scm) for hgTrackUi
 //
 // This module is for subtrack level config embedded dialogs in hgTrackUi.
 // Subtrack config dialogs are embedded in the subtrack table and get populated when first
 // opened.  Composite and view level controls (parents) when updated override related
 // subtrack controls (children).  Subtrack controls, when updated overide parent controls
 // for the one subtrack.  Controls wil get class 'changed' added when changes are made.
 // When the form is submitted, all controls not marked as "changed" will be unnamed and will
 // therefore not make it into the cart.
 
 // Definitions as used here:
 // obj: an input or select style html control which may be marked as "changed"
 //   parentObj: composite or view level obj which has subtrack level childObjs associated
 //   childObj: subtrack level obj that has composite and or view level parentObjs
 // cfg: subtrack level embedded dialog which can be opened or closed (hidden) and isn't
 //      populated till first opened.  Can also be a viewCfg and maybe a compositeCfg
 // populate: act of filling a subtrack cfg with controls
 // fauxVis: fake control for subtrack visDD, which will be replaced with true vis when clicked.
 //
 // NOTE:
 // Current implementation relies upon '.' delimiter in name and no '_-' in name.
 //   Nothing breaks rule yet...
 
 // Don't complain about line break before '||' etc:
 /* jshint -W014 */
 
 var subCfg = { // subtrack config module.
     //mySelf: null, // There is no need for a "mySelf" unless this object is being instantiated.
 
     // There is one instance and these vars are page wide
     compositeName: undefined,
     canPack: true,  // if composite vis is only hide,dense,full, then all children also restricted.
     visIndependent: false,
     viewTags: [],
 
     markChange: function (eventObj, obj)
     { // Marks a control as having been changed by the user.  Naming will send value to cart.
       // Note this is often called directly as the onchange event function
         if (!obj || $.type(obj) === "string")
             obj = this;
 
         $(obj).addClass('changed');
 
         // checkboxes have hidden boolshads which should be marked when unchecked
         if (obj.type === "checkbox") {
             var boolshad = normed($("input.cbShadow[name='boolshad\\." + obj.name+"']"));
             if (boolshad) {
                 $(boolshad).addClass('changed');
             }
         }
     },
 
     clearChange: function (obj)
     { // Mark as unchanged
         $(obj).removeClass('changed');
 
         // checkboxes have hidden boolshads which should be cleared in tandem
         if (obj.type === "checkbox") {
             var boolshad = normed($("input.cbShadow[name='boolshad\\." + obj.name+"']"));
             if (boolshad) {
                 $(boolshad).removeClass('changed');
             }
         }
     },
 
     hasChanged: function (obj)
     { // Is this object updated (value changed by a user)?
         return $(obj).hasClass('changed');
     },
 
     compositeCfgFind: function ()
     { // returns the cfg container for the composite controls
         // TODO: write, create a composite cfg div!
     },
 
     compositeObjFind: function (suffix)
     { // returns the composite level control for this suffix
         //var compCfg = subCfg.compositeCfgFind();  // TODO: when there is a composite cfg div!
         var compObj;
         if (suffix && suffix.length > 0) {
             compObj = normed($("[name='"+subCfg.compositeName + "\\." + suffix+"']"));
             if (!compObj) {
                 compObj = normed($("[name='"+subCfg.compositeName + "_" + suffix+"']"));
             }
         } else {
             compObj = normed($("[name='"+subCfg.compositeName+"']"));
         }
         return compObj;
     },
 
     viewTagFind: function (childObj)
     { // returns the name of the view that is a parent of this subtrack control
         var classList = null;
         var cfg = normed($(childObj).parents('div.subCfg'));
         if (!cfg) {
             // Child obj could be vis itself...
             var subCb = normed($(childObj).closest('tr').find('input.subCB'));
             if (subCb) {
                 classList = $(subCb).attr("class").split(" ");
                 classList = aryRemove(classList,["changed","disabled"]);
                 return classList[classList.length - 1];
             }
             // could be vis outside of cfg div
             warn("DEBUG: Can't find containing div.subCfg of child '"+childObj.name+"'.");
             return undefined;
         }
         classList = $( cfg ).attr("class").split(" ");
         classList = aryRemove(classList,["subCfg","filled"]);
         if (classList.length === 0) {
             warn("DEBUG: Subtrack cfg div does not have view class for child '"+childObj.name+"'.");
             return undefined;
         } else if (classList.length > 1) {
             warn("DEBUG: Subtrack cfg div for '"+childObj.name+"' has unexpected class: "+classList);
             return undefined;
         }
         if (classList[0] === 'noView') // valid case
             return undefined;
         return classList[0];
     },
 
     viewCfgFind: function (viewTag)
     { // returns the cfg container for a given view
         var viewCfg = normed($('tr#tr_cfg_'+viewTag));
         return viewCfg;
     },
 
     viewObjFind: function (viewTag,suffix)
     { // returns the control belonging to this view and suffix
         var viewObj;
         if (suffix && suffix.length > 0) {
             var viewCfg = subCfg.viewCfgFind(viewTag);
             viewObj = normed($(viewCfg).find("[name$='\\."+suffix+"']"));
             if (!viewObj)
                 viewObj = normed($(viewCfg).find("[name$='_"+suffix+"']"));
         } else
             viewObj = normed($("select.viewDD."+viewTag));
 
         return viewObj;
     },
 
     childObjsFind: function (viewTag,suffix)
     { // returns an array of objs for this view and suffix
       // Assumes composite wide if viewTag is not provided
       // Assumes vis if suffix is not provided
 
         var childCfgs = null;
         if (viewTag && viewTag.length > 0) {
             childCfgs = $('div.subCfg.filled.'+viewTag);
         } else {
             childCfgs = $('div.subCfg.filled');
         }
         if (!childCfgs)
             return [];
 
         var childObjs = [];
         if (suffix && suffix.length > 0)
             childObjs = $(childCfgs).find('select,input').filter("[name$='\\."+suffix+"']");
         else
             childObjs = $(childCfgs).find('select.visDD');
 
         if (!childObjs)
             return [];
 
         return childObjs;
     },
 
     objSuffixGet: function (obj)
     { // returns the identifying suffix of a control.  obj can be parent or child
         //var nameParts = $(obj).attr('id').split('.');
         var nameParts = obj.name.split('.');
         if (!nameParts || nameParts.length === 0) {
             warn("DEBUG: Can't resolve name for '"+obj.name+"'.");
             return undefined;
         }
         if (nameParts.length < 2)
             return undefined;
 
         nameParts.shift();
         if (subCfg.viewTags.length > 0 && nameParts.length > 1)
             nameParts.shift();
 
         return nameParts.join('.');
     },
 
     childCfgFind: function (childObj)
     { // returns the cfg wrapper for a child vis object
         var childCfg = normed($(childObj).parents('div.subCfg.filled'));
         if (!childCfg)
             warn("DEBUG: Can't find childCfg for "+childObj.name);
         return childCfg;
     },
 
     subCbFind: function (childObj)
     { // returns the subCB for a child vis object
         // Look directly first
         var subCb = normed($(childObj).closest('tr').find('input.subCB'));
         if (subCb)
             return subCb;
 
         warn("DEBUG: Failed to find subCb for "+childObj.name);
         var childCfg = subCfg.childCfgFind(childObj);
         if (!childCfg)
             return undefined;
 
         var tr = $(childCfg).parents('tr').first();
         var subtrack = childCfg.id.substring(8); // 'div_cfg_'.length
         subCb = normed($(tr).find("input[name='"+subtrack+"_sel']"));
         if (!subCb)
             warn("DEBUG: Can't find subCB for subtrack: "+subtrack);
         return subCb;
     },
 
     parentsFind: function (childObj)
     { // returns array of composite and/or view level parent controls
         var myParents = [];
         var suffix = subCfg.objSuffixGet(childObj);
         //var notRadio = (childObj.type.indexOf("radio") !== 0);
         var notRadio = (childObj.type !== "radio");
 
         // find view name
         var viewTag = subCfg.viewTagFind(childObj);
         if (viewTag && viewTag.length > 0) {
             var viewObj = subCfg.viewObjFind(viewTag,suffix);
             if (viewObj) {
                 if (notRadio)
                     myParents[0] = viewObj;
                 else {
                     $(viewObj).each(function (i) { // radios will have more than one
                         if (childObj.value === this.value) {
                             myParents[0] = this;
                             return false; // breaks each, but not parentsFind
                         }
                     });
                 }
             }
         }
 
         var compObj = subCfg.compositeObjFind(suffix);
         if (compObj) {
             if (notRadio)
                 myParents[myParents.length] = compObj;
             else {
                 $(compObj).each(function (i) { // radios will have more than one
                     if (childObj.value === this.value) {
                         myParents[myParents.length] = this;
                         return false;
                     }
                 });
             }
         }
         return myParents;
     },
 
     childrenFind: function (parentObj)
     { // returns array of all currently populated child controls related to this parent control
       // parentObj could be composite level or view level
       // parent object could be for vis which has special rules
 
         var isComposite = false;
         var isVis = false;
         var suffix = subCfg.objSuffixGet(parentObj);
         isVis = (suffix && suffix === 'vis');  // vis inside of subCfg
 
         var viewTag = null;
         if (isVis) { // This is a view control
 
             isComposite = (!suffix || suffix.length === 0);
             suffix = undefined;
             if (!isComposite) {
                 var classList = $( parentObj ).attr("class").split(" ");
                 classList = aryRemove(classList,["viewDD","normalText","changed"]);
                 if (classList.length !== 1) {
                     warn("DEBUG: Unexpected view vis class list:"+classList);
                     return [];
                 }
                 viewTag = classList[0];
             }
         } else { // normal obj
 
             var viewCfg = normed($(parentObj).parents("tr[id^='tr_cfg_']"));
             isComposite = (!viewCfg); // is composite
             if (!isComposite) {
                 viewTag = viewCfg.id.substring(7); // 'tr_cfg_'.length
             }
         }
 
         if (isComposite) {
 
             // There may be views
             if (subCfg.viewTags.length > 0) {
                 var allChildren = [];
                 for (var ix = 0;ix < subCfg.viewTags.length;ix++) {
                     viewTag = subCfg.viewTags[ix];
                     // Get any view objs first
                     var viewObj = subCfg.viewObjFind(viewTag,suffix);
                     if (viewObj)
                         allChildren[allChildren.length] = viewObj;
                     // Now get children
                     var viewChildren = subCfg.childObjsFind(viewTag,suffix);
                     if (viewChildren.length > 0) {
                         if (allChildren.length === 0)
                             allChildren = viewChildren;
                         else
                             allChildren = jQuery.merge( allChildren, viewChildren );
                     }
                 }
                 return allChildren;
             } else { // if no views then just get them all
                 return subCfg.childObjsFind(undefined,suffix);
             }
 
         } else {
             return subCfg.childObjsFind(viewTag,suffix);
         }
     },
 
     visChildrenFind: function (parentObj)
     { // returns array of all currently faux and populated vis child controls
       // (which are not in subCfg div).  parentObj could be composite level or view level
 
         var subVis = $('.subVisDD');  // select:vis or faux:div
         if ($(parentObj).hasClass('visDD')) // composite.  views have .viewDD and sub .subVisDD
             return subVis;
 
         var classList = $( parentObj ).attr("class").split(" ");
         classList = aryRemove(classList,["viewDD","normalText","changed"]);
         if (classList.length !== 1) {
             warn("DEBUG: Unexpected view vis class list:"+classList);
             return [];
         }
         return $(subVis).filter('.' + classList[0]);
     },
 
     checkOneSubtrack: function (subCb,check,enable)
     { // Handle a single check of a single subCb
       // called by changing subVis to/from 'hide'
         subCb.checked = check;
         if (enable)
             fauxDisable(subCb,false,"");
         else
             fauxDisable(subCb,true, "View is hidden");
         subCfg.markChange(null,subCb);
         subCfg.enableCfg(subCb,check);
         matSubCbClick(subCb); // needed to mark matCBs, shadow and show/hide
     },
 
     propagateSetting: function (parentObj)
     { // propagate composite/view level setting to subtrack children
         var children = subCfg.childrenFind(parentObj);
         var parentVal = null;
         if (parentObj.type === "checkbox") {
             var parentChecked = parentObj.checked;
             $(children).each(function (i) {
                 if (this.type !== 'hidden')
                     this.checked = parentObj.checked;
                 subCfg.clearChange(this);
             });
         } else if (parentObj.type === "radio") {
             parentVal = $(parentObj).val();
             $(children).each(function (i) {
                 this.checked = ($(this).val() === parentVal);
                 subCfg.clearChange(this);
             });
         } else {// selects and inputs are easy
             parentVal = $(parentObj).val();
             var updateDdcl = ($(parentObj).hasClass('filterBy'));// Should never be filterComp
             $(children).each(function (i) {
                 $(this).val(parentVal);
                 subCfg.clearChange(this);
                 if (updateDdcl)
                     ddcl.onComplete(this);
             });
         }
     },
 
     propagateViewVis: function (viewObj,compositeVis)
     { // propagate vis from a view limiting with compositeVis
         var limitedVis = Math.min(compositeVis,viewObj.selectedIndex);
         var visText = 'hide';
         if (limitedVis === 1)
             visText = 'dense';
         else if (limitedVis === 2) {
             if (subCfg.canPack)
                 visText = 'squish';
             else
                 visText = 'full';
         } else if (limitedVis === 3)
             visText = 'pack';
         else if (limitedVis === 4)
             visText = 'full';
 
         var children = subCfg.visChildrenFind(viewObj);
         $(children).each(function (i) {
             if ($(this).hasClass('fauxInput')) {
                 $(this).text(visText);
             } else {
                 $(this).attr('selectedIndex',limitedVis);
                 subCfg.clearChange(this);
             }
         });
     },
 
     propagateVis: function (parentObj,viewTag)
     { // propagate vis settings to subtrack children
         if (!viewTag || viewTag.length === 0) {
             // Walk through views and set with this
             var parentVis = parentObj.selectedIndex;
             if (subCfg.viewTags.length > 0) {
                 for (var ix=0;ix<subCfg.viewTags.length;ix++) {
                     var viewObj = subCfg.viewObjFind(subCfg.viewTags[ix]);
                     if (viewObj)
                         subCfg.propagateViewVis(viewObj,parentVis);
                 }
             } else { // No view so, simple
 
                 var visText = 'hide';
                 if (parentVis === 1)
                     visText = 'dense';
                 else if (parentVis === 2) {
                     if (subCfg.canPack)
                         visText = 'squish';
                     else
                         visText = 'full';
                 } else if (parentVis === 3)
                     visText = 'pack';
                 else if (parentVis === 4)
                     visText = 'full';
                 var children = subCfg.visChildrenFind(parentObj);
                 $(children).each(function (i) {
                     if ($(this).hasClass('fauxInput')) {
                         $(this).text(visText);
                     } else {
                         $(this).attr('selectedIndex',parentVis);
                         subCfg.clearChange(this);
                     }
                 });
             }
         } else {
             // First get composite vis to limit with
             var compObj = subCfg.compositeObjFind(undefined);
             if (!compObj) {
                 warn('DEBUG: Could not find composite vis object!');
                 return false;
             }
             subCfg.propagateViewVis(parentObj,compObj.selectedIndex);
         }
     },
 
     inheritSetting: function (childObj,force)
     { // update value if parents values override child values.
         var myParents = subCfg.parentsFind(childObj);
         if (!myParents || myParents.length === 0) {
             //warn('DEBUG: No parents were found for childObj: '+childObj.name); // Not a problem.
             return true;
         }
         var isVis = (!subCfg.objSuffixGet(childObj));
         if (isVis) {
             var subCb = subCfg.subCbFind(childObj);
             if (subCb) {
                 var limitedVis = 9;
                 if (myParents.length === 1 && (force || subCfg.hasChanged(myParents[0])))
                     limitedVis = myParents[0].selectedIndex;
                 else if (myParents.length === 2) {
                     if (force || subCfg.hasChanged(myParents[0]) || subCfg.hasChanged(myParents[1]))
                         limitedVis = Math.min(myParents[0].selectedIndex,myParents[1].selectedIndex);
                 }
                 if (limitedVis < 9)
                     $(childObj).attr('selectedIndex',limitedVis);
            }
         } else {
             var count = 0;
             if (childObj.type === "checkbox") {
                 $(myParents).each(function (i) {
                     if (force || subCfg.hasChanged(this)) {
                         childObj.checked = this.checked;
                         count++;
                     }
                 });
             } else if (childObj.type === "radio") {
                 $(myParents).each(function (i) {
                     if (force || subCfg.hasChanged(this)) {
                         childObj.checked = this.checked;
                         // parentObj is already "tuned" to the correct radio, so this works
                         count++;
                     }
                 });
             } else {// selects and inputs are easy
                 $(myParents).each(function (i) {
                     if (force || subCfg.hasChanged(this)) {
                         $(childObj).val($(this).val());
                         count++;
                     }
                 });
             }
             if (count > 1) // if hasChanged() is working, there should never be more than one
                 warn('DEBUG: Both composite and view are seen as updated!  ' +
                                                                     'Named update is not working.');
         }
     },
 
     currentCfg: undefined, // keep track of cfg while ajaxing, man
     currentSub: undefined, // keep track of subtrack while ajaxing, dude
 
     cfgFill: function (content, status)
     { // Finishes the population of a subtrack cfg.  Called by ajax return.
         var ix;
         var cfg = subCfg.currentCfg;
         subCfg.currentCfg = undefined;
         var cleanHtml = content;
         cleanHtml = stripJsFiles(cleanHtml,true);   // DEBUG msg with true
         cleanHtml = stripCssFiles(cleanHtml,true);  // DEBUG msg with true
         cleanHtml = stripJsEmbedded(cleanHtml,true);// DEBUG msg with true
         if (subCfg.visIndependent) {
             ix = cleanHtml.indexOf('</SELECT>');
             if (ix > 0)
                 cleanHtml = cleanHtml.substring(ix+'</SELECT>'.length);
             while(cleanHtml.length > 0) {
                 ix = cleanHtml.search("<");
                 cleanHtml = cleanHtml.substring(ix);
                 ix = cleanHtml.search(/<BR\>/i);
                 if (ix !== 0)
                     break; // Not found or not at start.
                 else
                     cleanHtml = cleanHtml.substring(4); // skip past <BR> and continue
             }
         } else {
             ix = cleanHtml.indexOf('<B>Display&nbsp;mode:&nbsp;</B>');
             if (ix > 0)                            // Excludes vis!
                 cleanHtml = cleanHtml.substring(ix+'<B>Display&nbsp;mode:&nbsp;</B>'.length);
         }
             //cleanHtml = cleanHtml.substring(ix);
         ix = cleanHtml.indexOf('</FORM>'); // start of form already chipped off
         if (ix > 0)
             cleanHtml = cleanHtml.substring(0,ix - 1);
 
         cleanHtml = "<div class='blueBox' style='background-color:#FFF9D2; padding:0.5em 1em 1em;'>"
                     + cleanHtml + "</div>";
         $(cfg).html(cleanHtml);
         $(cfg).addClass('filled');
         var boxWithin = $(cfg).find('.blueBox');
         if (boxWithin.length > 1)
             $(boxWithin[1]).removeClass('blueBox');
 
         //$(cfg).html("<div style='font-size:.9em;'>" + cleanHtml + "</div>");
         var subObjs = $(cfg).find('input,select').filter("[name]");
         if (subObjs.length === 0) {
             warn('DEBUG: Did not find controls for cfg: ' + cfg.id);
             return;
         }
         $(subObjs).each(function (i) {
             if (this.name) { // The filter("[name]") above didn't do it!
                 if (this.type !== 'hidden') {
                     subCfg.inheritSetting(this,false); // updates any values that have been changed
                     var suffix = subCfg.objSuffixGet(this);                         // on this page
                     if (suffix && suffix.length > 0)
                         $(this).change( subCfg.markChange );
                     else
                         warn("DEBUG: couldn't find suffix for subtrack control: "+this.name);
                 }
             }
         });
         // finally show
         $(cfg).show();
         // Tricks to get this in the size and position I want
         $(cfg).css({ position: 'absolute'});
         var myWidth = $(cfg).width();
         var shiftLeft = -1;
         if (subCfg.visIndependent) {
             shiftLeft *= ($(cfg).position().left - 125);
             var subVis = normed($('div#' + subCfg.currentSub+'_faux'));
             if (subVis)
                 subCfg.replaceWithVis(subVis,subCfg.currentSub,false);
         }
         else
             shiftLeft *= ($(cfg).position().left - 40);
         $(cfg).css({ width: myWidth+'px',position: 'relative', left: shiftLeft + 'px' });
 
         // Setting up filterBys must follow show because sizing requires visibility
         $(cfg).find('.filterBy').each( function(i) { // Should never be filterComp
             this.id = this.name.replace(/\./g,'_-'); // Must have id unique to page!
             ddcl.setup(this, 'noneIsAll');
         });
 
         // Adjust cfg box size?
         // Especially needed for filterBys, but generic in case some other overrun occurs
         var curRight = $(cfg).offset().left + $(cfg).width();
         var calcRight = curRight;
         $(cfg).find(':visible').each( function(i) { // All visible, including labels, etc.
             var childRight = $(this).offset().left + $(this).width();
             if (calcRight < childRight)
                 calcRight = childRight;
         });
         if (curRight < calcRight) {                       // clip offset but add some for border
             var cfgWidth = calcRight - $(cfg).offset().left + 16;
             $(cfg).css({ width: cfgWidth + 'px' });
 
             // Now containing tables may need adjustment
             var tables = $(cfg).parents('table');
             var maxWidth = 0;
             $(tables).each(function(i) {
                 var myWidth = $(this).width();
                 if (maxWidth < myWidth)
                     maxWidth = myWidth;
                 else if (maxWidth > myWidth)
                     $(this).css('width',maxWidth + 'px');
             });
         }
     },
 
     cfgPopulate: function (cfg,subtrack)
     { // Populates a subtrack cfg dialog via ajax and update from composite/view parents
         subCfg.currentCfg = cfg;
         subCfg.currentSub = subtrack;
 
         $.ajax({
             type: "GET",
             url: "../cgi-bin/hgTrackUi?ajax=1&g="+subtrack+"&hgsid="+getHgsid()+"&db="+getDb(),
             dataType: "html",
             trueSuccess: subCfg.cfgFill,
             success: catchErrorOrDispatch,
             error: errorHandler,
             cmd: "cfg",
             cache: false
         });
     },
 
     replaceWithVis: function (obj,subtrack,open)
     { // Replaces the current fauxVis object with a true visibility selector
 
         if ($(obj).hasClass('disabled'))
             return;
         var classList = $( obj ).attr("class").split(" ");
         classList = aryRemove(classList,["disabled"]);
         var view = classList[classList.length - 1]; // This relies on view being the last class!!!
         var selectHtml  = "<SELECT name='"+subtrack+"' class='normalText subVisDD "+view+"'";
             selectHtml += " style='width:70px;'>";
         var selected = $(obj).text();
         var visibilities = ['hide','dense','squish','pack','full'];
         if (subCfg.canPack === false)
             visibilities = ['hide','dense','full'];
         $(visibilities).each( function (ix) {
              selectHtml += "<OPTION"+(visibilities[ix] === selected ? " SELECTED":"")+">";
              selectHtml += visibilities[ix]+"</OPTION>";
         });
         selectHtml += "</SELECT>";
         $(obj).replaceWith(selectHtml);
         var newObj = $("select[name='"+subtrack+"']");
         if (open) {
             $(newObj).css({'zIndex':'2','vertical-align':'top'});
+            // For some reason IE11 will hang if the sect is opened to start with!
+            // This ungraceful fix avoids the hang, but a nicer solution would be apprciated!
+            if (theClient.isIePost11() === false) { 
                 $(newObj).attr('size',visibilities.length);
+            }
             $(newObj).one('blur',function (e) {
                 $(this).attr('size',1);
                 $(this).unbind('click');
             });
             $(newObj).one('click',function (e) {
                 $(this).attr('size',1);
                 $(this).unbind('blur');
             });
             $(newObj).focus();
         }
         $(newObj).change(function (e) {
             if ($(this).attr('size') > 1) {
                 $(this).attr('size',1);
                 $(this).unbind('blur');
                 $(this).unbind('click');
             }
             if (this.selectedIndex === 0) { // setting to hide so uncheck and disable.
                 // Easiest is to uncheck subCB and reset vis
                 //    so that the reverse action makes sense
                 var subCb = normed($("input[name='" + this.name + "_sel']"));
                 if (subCb) {
                     subCfg.checkOneSubtrack(subCb,false,true);
                     subCfg.inheritSetting(this,true);
                 } else {
                     warn('DEBUG: Cant find subCB for ' + this.name);
                 }
             } else {
                 subCfg.markChange(e,this);
                 // If made visible, be sure to make composite visible
                 // But do NOT turn composite from hide to full, since it will turn on other subs
                 // Just trigger a supertrack reshaping
                 if (this.selectedIndex > 0) {
                     //exposeAll();
                     var visDD = normed($("select.visDD"));
                     if (visDD) {
                         if ($(visDD).hasClass('superChild'))
                             visTriggersHiddenSelect(visDD);
                     }
                 }
             }
         });
     },
 
     enableCfg: function (subCb,setTo)
     { // Enables or disables subVis and wrench
         var tr = normed($(subCb).closest('tr'));
         if (!tr) {
             warn("DEBUG: subCfg.enableCfg() could not find TR for CB: "+subCb.name);
             return false;
         }
         var subFaux = normed($(tr).find('div.subVisDD'));
         if (subFaux) {
             if (setTo === true)
                 $(subFaux).removeClass('disabled');
             else
                 $(subFaux).addClass('disabled');
         } else {
             var subVis = normed($(tr).find('select.subVisDD'));
             if (subVis) {
                 $(subVis).attr('disabled',!setTo);
             }
         }
         var wrench = normed($(tr).find('span.clickable'));
         if (wrench) {
             if (setTo === true)
                 $(wrench).removeClass('disabled');
             else {
                 $(wrench).addClass('disabled');
                 var cfg = normed($(tr).find('div.subCfg'));
                 if (cfg)
                     $(cfg).hide();
             }
         }
     },
 
     cfgToggle: function (wrench,subtrack)
     { // Opens/closes subtrack cfg dialog, populating if empty
         var cfg = normed($("div#div_cfg_"+subtrack));
         if (!cfg) {
             warn("DEBUG: Can't find div_cfg_"+subtrack);
             return false;
         }
 
         if ($(cfg).css('display') === 'none') {
             if ($(wrench).hasClass('disabled'))
                 return;
             // Don't allow if this composite is not enabled!
             // find the cb
             var tr = $(cfg).parents('tr').first();
             var subCb = normed($(tr).find("input[name='"+subtrack+"_sel']"));
             if (!subCb) {
                 warn("DEBUG: Can't find subCB for "+subtrack);
                 return false;
             }
             //if (subCb.disabled === true) // || subCb.checked === false)
             if (isFauxDisabled(subCb,true))
                 return false;
 
             if (metadataIsVisible(subtrack))
                 metadataShowHide(subtrack,"","");
             if ($(cfg).hasClass('filled'))
                 $(cfg).show();
             else
                 waitOnFunction( subCfg.cfgPopulate, cfg, subtrack );
         } else
             $(cfg).hide();
         return false; // called by link!
     },
 
     viewInit: function (viewTag)
     { // sets up view controls for propagation
         var tr = normed($('tr#tr_cfg_'+viewTag));
         if (tr) {
             // iterate through all matching controls and setup for propgation and change flagging
             var viewObjs = $(tr).find('input,select');
             if (viewObjs.length > 0) {
                 $(viewObjs).each(function (i) {
                     if (this.type !== 'hidden') {
                         $(this).bind('change',function (e) {
                             subCfg.markChange(e,this);
                             subCfg.propagateSetting(this);
                         });
                     }
                 });
             }
         }
 
         // Now vis control
         var viewVis = normed($("select.viewDD."+viewTag));
         if (!viewVis) {
             warn('DEBUG: Did not find visibility control for view: ' + viewTag);
             return;
         }
         $(viewVis).bind('change',function (e) {
             subCfg.markChange(e,viewVis);
             subCfg.propagateVis(viewVis,viewTag);
         });
     },
 
     initialize: function ()
     { // sets up all composite controls and then all view controls
       // onchange gets set to mark controls as 'changed'.  Unchanged controls will
       // be disabled on 'submit'.  Disabled controls will not get to the cart!
 
         var compVis = $('.visDD');
         if (!compVis || compVis.length === 0) {
             warn('DEBUG: Did not find visibility control for composite.');
             return;
         }
         if (compVis.length > 1) {
             warn('DEBUG: Multiple visibility controls for composite???');
             return;
         }
         // Note that if composite vis has no pack then no child should have pack
         if ($(compVis).children('option').length < 5)
             subCfg.canPack = false; 
 
         subCfg.compositeName = $(compVis).attr('name');
         subCfg.visIndependent = ($('.subVisDD').length > 0);  // Can subtracks have their own vis?
 
         // Set up vis propagation and change flagging
         compVis = compVis[0];
         $(compVis).bind('change',function (e) {
             subCfg.markChange(e,compVis);
             subCfg.propagateVis(compVis,undefined);
         });
 
         // SubCBs will may enable/diable vis/wrench and will be flagged on change
         var subCbs = $('input.subCB');
         $(subCbs).change( function (e) {
             subCfg.enableCfg(this, (this.checked && !isFauxDisabled(this, true)));
             subCfg.markChange(e,this);
         });
 
         // iterate through views
         var viewVis = $('select.viewDD');
         $(viewVis).each(function (i) {
             var classList = $( this ).attr("class").split(" ");
             classList = aryRemove(classList,["viewDD","normalText","changed"]);
             if (classList.length === 0)
                 warn('DEBUG: View classlist is missing view class.');
             else if (classList.length > 1)
                 warn('DEBUG: View classlist contains unexpected classes:' + classList);
             else {
                 subCfg.viewTags[i] = classList[0];
                 subCfg.viewInit(subCfg.viewTags[i]);
             }
         });
 
         // Tricky for composite level controls.  Could wrap cfg controls in new div.
         // DO THIS AFTER Views
         // NOTE: excluding sortOrder and showCfg which are special cases we don't care about here
         // Excluding views and subCBs because a {composite}_{subtrack} naming scheme may be used
         var compObjs = $('select,input').filter("[name^='"+subCfg.compositeName+"\\.'],[name^='"+
                                                                         subCfg.compositeName+"_']");
         // viewDD, subCB already done. non-abc matCBs not needed, as they shouldn't go to the cart.!
         compObjs = $(compObjs).not(".viewDD,.subCB,.matCB:not(.abc)");
         if (compObjs.length > 0) {
             $(compObjs).each(function (i) {
                 if (this.type !== 'hidden') {
                     // DEBUG -------------
                     if (this.id && this.id.length > 0
                     && $(this).hasClass('filterBy') === false
                     && $(this).hasClass('filterComp') === false)
                         warn('DEBUG: Unexpected control with name ['+this.name + '], and id #'+
                                                                                            this.id);
                     $(this).change(function (e) {
                         subCfg.markChange(e,this);
                         subCfg.propagateSetting(this);
                     });
                 }
             });
         }
 	// Bugfix #8048: Tim suggested using a special class to handle subtrack settings
 	// that appear alongside composite settings, as in ldUi (HapMap LD).
 	var subsInComp = $('select.subtrackInCompositeUi,input.subtrackInCompositeUi');
 	$(subsInComp).each( function(ix, el) {
 				$(el).change(function(e) { subCfg.markChange(e, el); } ); });
 
         // Because of fauxDisabled subCBs, it is necessary to truly disable them before submitting.
         $("FORM").submit(function (i) {          // shadows will go to cart as they should
             $('input.subCB.changed.disabled').attr('disabled',true);
 
             // Unchanged controls will be disabled to avoid sending to the cart
             $('select,input').filter("[name]").not(".allOrOnly").not('.changed').each(function (i) {
                 if (this.type !== 'hidden' || $(this).hasClass('trPos')
                 || $(this).hasClass('cbShadow') || $(this).hasClass('sortOrder')) {
                     // hiddens except priority and boolshad are all sent to the cart
                     // disable instead of unname because unname fills cart with a lot of garbage
                     this.disabled = true;                                            // (Linux/FF)!
                 }
             });
         });
     }
 };