1a89c8e587e4cdbdb94430448caaa19247871cb8
tdreszer
  Thu Sep 22 13:01:11 2011 -0700
Big load of changes for subCfg.
diff --git src/hg/js/hui.js src/hg/js/hui.js
index 1344e76..479a773 100644
--- src/hg/js/hui.js
+++ src/hg/js/hui.js
@@ -19,31 +19,30 @@
 {
 // 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(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(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) {
@@ -85,65 +84,63 @@
             $( matCBs ).each( function (i) { matChkBoxNormalize( this, classesHidden ); });
         }
     }
     matSubCBsSelected();
     obj.lastIndex = obj.selectedIndex;
 }
 
 function matSelectViewForSubTracks(obj,view)
 {
     waitOnFunction( _matSelectViewForSubTracks, obj,view);
 }
 
 function exposeAll()
 {
     // Make main display dropdown show full if currently hide
-    var visDD = $("select.visDD"); // limit to hidden
-    if ($(visDD).length == 1) {
-        visDD = visDD[0];              // limit to hidden
+    var visDD = normed($("select.visDD")); // limit to hidden
+    if (visDD != undefined) {
         if ($(visDD).attr('selectedIndex') == 0) {
             $(visDD).attr('selectedIndex',$(visDD).children('option').length - 1);
-            scm.propagateVis(visDD);
+            $(visDD).change(); // triggers onchange code effecting inherited subtrack vis
         }
     }
 }
 
 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.
+    if (common.subCfg)
     scm.checkOneSubtrack(subCB,subCB.checked,!subCB.disabled);
     //////////matSubCBsetShadow(subCB);
     //////////hideOrShowSubtrack(subCB);
     // When subCBs are clicked, 3-state matCBs may need to be set
     var classes = matViewClasses('hidden');
     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?
 
-    ///////////scm.enableCfg(subCB,null,subCB.checked);
-
     matSubCBsSelected();
 }
 
 function matCbClick(matCB)
 {
 // matCB:onclick  When a matrix CB is clicked, the set of subtracks checked may change
 // Also called indirectly by matButton:onclick via matSetMatrixCheckBoxes
 
     var classList = $( matCB ).attr("class").split(" ");
     var isABC = (aryFind(classList,"abc") != -1);
     classList = aryRemove(classList,"matCB","halfVis","abc");
     if(classList.length == 0 )
        matSubCBsCheck(matCB.checked);
     else if(classList.length == 1 )
        matSubCBsCheck(matCB.checked,classList[0]);               // dimX or dimY or dim ABC
@@ -183,36 +180,38 @@
     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);
     });
     var subCbs = $("input.subCB");
     for(var vIx=1;vIx<arguments.length;vIx++) {
         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);
         subCbs = objsFilterByClasses(subCbs,"not",classes);  // remove unchecked abcCB classes
     }
+    if (common.subCfg) {
     $( subCbs ).each( function (i) {
         scm.checkOneSubtrack(this,state,!(this.disabled));
         /////////this.checked = state;
         /////////matSubCBsetShadow(this);
         /////////scm.enableCfg(this,null,this.checked);
     });
+    }
     if(state)
         exposeAll();  // Unhide composite vis?
     ////////showOrHideSelectedSubtracks();
     matSubCBsSelected();
     //jQuery(this).css('cursor', '');
 
     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)
@@ -290,44 +289,56 @@
             $(this).parent().attr('title','view is hidden');
             $(this).parent().attr('cursor','pointer');
         }
         this.disabled = !state;
         matSubCBsetShadow(this);
         hideOrShowSubtrack(this);
     });
 
     return true;
 }
 
 function matSubCBcheckOne(subCB,state)
 {
 // setting a single subCB may cause it to appear/disappear
     subCB.checked = state;
-    scm.enableCfg(subCB,null,state);
+    if (common.subCfg)
+       scm.checkOneSubtrack(subCB,state,!subCB.disabled);
     matSubCBsetShadow(subCB);
     hideOrShowSubtrack(subCB);
 }
 
 function matSubCBsetShadow(subCB)
 {
 // Since CBs only get into cart when enabled/checked, the shadow control enables cart to know other states
     var shadowState = 0;
     if(subCB.checked)
         shadowState = 1;
     if(subCB.disabled)
         shadowState -= 2;
-    $("#"+subCB.name+"_4way").val(shadowState);
+    var fourWay = normed($("input.fourWay#boolshad_-"+subCB.id));
+    if (fourWay == undefined && subCB.name != undefined) {
+        fourWay = normed($("input.fourWay[name='boolshad\\."+subCB.name+"']"));
+        if (fourWay == undefined)
+            fourWay = normed($("#"+subCB.name+"_4way"));  // FIXME: obsolete as soon as subCfg is working
+    }
+    if (fourWay != undefined)
+        $(fourWay).val(shadowState);
+    else
+        warn("DEBUG: Failed to find fourWay shadow for '#"+subCB.id+"' ["+subCB.name+"]");
+    if (common.subCfg)
+        scm.enableCfg(subCB,null,(shadowState == 1));
 }
 
 function matChkBoxNormalize(matCB)
 {
 // Makes sure matCBs are in one of 3 states (checked,unchecked,indeterminate) based on matching set of subCBs
     var classList = $( matCB ).attr("class").split(" ");
     var isABC = (aryFind(classList,"abc") != -1);
     if(isABC)
         alert("ASSERT: matChkBoxNormalize() called for dim ABC!");
     classList = aryRemove(classList,"matCB","halfVis");
 
     var classes = '.' + classList.join(".");// created string filter of classes converting "matCB K562 H3K4me1" as ".K562.H3K4me1"
     var subCBs = $("input.subCB").filter(classes); // All subtrack CBs that match matrix CB
 
     if(arguments.length > 1 && arguments[1].length > 0) { // dim ABC NOT classes
@@ -378,50 +389,50 @@
 
 function matCBsWhichAreComplete(complete)
 {
 // Returns a list of currently indeterminate matCBs.  This is encapsulated to keep consistent with matCbComplete()
     if(complete)
         return $("input.matCB").not(".halfVis");
     else
         return $("input.matCB.halfVis");
 }
 
 function matCbFindFromSubCb(subCB)
 {
 // returns the one matCB associated with a subCB (or undefined)
     var classList =  $( subCB ).attr("class").split(" ");
     // we need one or 2 classes, depending upon how many dimensions in matrix (e.g. "subDB GM10847 NFKB aNone IGGrab Signal")
-    classList = aryRemove(classList,"subCB");
+    classList = aryRemove(classList,"subCB","changed");
     var classes = classList.slice(0,2).join('.');   // How to get only X and Y classes?  Assume they are the first 2
     var matCB = $("input.matCB."+classes); // Note, this works for filtering multiple classes because we want AND
     if(matCB.length == 1)
         return matCB;
 
     matCB = $("input.matCB."+classList[0]); // No hit so this must be a 1D matrix
     if(matCB.length == 1)
         return matCB;
 
     return undefined;
 }
 
 function matAbcCBfindFromSubCb(subCB)
 {
 // returns the abcCBs associated with a subCB (or undefined)
     var abcCBs = $("input.matCB.abc");
     if( abcCBs.length > 0 ) {
         var classList =  $( subCB ).attr("class").split(" ");
-        classList = aryRemove(classList,"subCB");
+        classList = aryRemove(classList,"subCB","changed");
         classList.shift(); // Gets rid of X and Y associated classes (first 2 after subCB)
         classList.shift();
         classList.pop();   // gets rid of view associated class (at end)
         if(classList.length >= 1) {
             var abcCB = $(abcCBs).filter('.'+classList.join("."));
             if(abcCB.length >= 1)
                 return abcCB;
         }
     }
     return undefined;
 }
 
 function objsFilterByClasses(objs,keep,classes)
 {
 // Accepts an obj list and an array of classes, then filters successively by that list
@@ -439,31 +450,31 @@
     return objs;
 }
 
 function matViewClasses(limitTo)
 {
 // returns an array of classes from the ViewDd: converts "viewDD normalText SIG"[]s to "SIG","zRAW"
     var classes = new Array;
     var viewDDs = $("select.viewDD");//.filter("[selectedIndex='0']");
     if(limitTo == 'hidden') {
         viewDDs = $(viewDDs).filter("[selectedIndex=0]");
     } else if(limitTo == 'visible') {
         viewDDs = $(viewDDs).not("[selectedIndex=0]");
     }
     $(viewDDs).each( function (i) {
         var classList = $( this ).attr("class").split(" ");
-        classList = aryRemove(classList,"viewDD","normalText");
+        classList = aryRemove(classList,"viewDD","normalText","changed");
         classes.push( classList[0] );
     });
     return classes;
 }
 
 function matAbcCBclasses(wantSelected)
 {// returns an array of classes from the dim ABC CB classes: converts "matCB abc rep1"[]s to "rep1","rep2"
     var classes = new Array;
     var abcCBs = $("input.matCB.abc");
     if(abcCBs.length > 0) {
         if (!wantSelected) {
             abcCBs = abcCBs.not(":checked");
         } else {
             abcCBs = abcCBs.filter(":checked");
         }
@@ -482,82 +493,82 @@
 {
 // 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 ////////////////
 function compositeCfgUpdateSubtrackCfgs(inp)
 {
 // Updates all subtrack configuration values when the composite cfg is changed
     // If view association then find it:
     var view = "";
-    var daddy = $(inp).parents(".blueBox");
-    if(daddy.length == 1) {
-        var classList = $(daddy[0]).attr("class").split(" ");
+    var daddy = normed($(inp).parents(".blueBox"));
+    if(daddy != undefined) {
+        var classList = $(daddy).attr("class").split(" ");
         if(classList.length == 2) {
             view = classList[1];
         }
     }
     var suffix = inp.name.substring(inp.name.indexOf("."));  // Includes '.'
     //if(suffix.length==0)
     //    suffix = inp.name.substring(inp.name.indexOf("_"));
     if(suffix.length==0) {
         warn("Unable to parse '"+inp.name+"'");
         return true;
     }
     if(inp.type.indexOf("select") == 0) {
         var list = $("select[name$='"+suffix+"']").not("[name='"+inp.name+"']"); // Exclude self from list
-        if(view != "") { list =  $(list).filter(function(index) { return $(this).parents(".blueBox." + view).length == 1; });}
+        if(view != "") { list =  $(list).filter(function(index) { return normed($(this).parents(".blueBox." + view)) != undefined; });}
         if($(list).length>0) {
             if(inp.multiple != true)
                 $(list).attr('selectedIndex',inp.selectedIndex);
             else {
                 $(list).each(function(view) {  // for all dependent (subtrack) multi-selects
                     sel = this;
                     if(view != "") {
                         var hasClass = $(this).parents(".blueBox." + view);
                         if(hasClass.length != 0)
                             return;
                     }
                     $(this).children('option').each(function() {  // for all options of dependent mult-selects
                         $(this).attr('selected',$(inp).children('option:eq('+this.index+')').attr('selected')); // set selected state to independent (parent) selected state
                     });
                     $(this).attr('size',$(inp).attr('size'));
                 });
             }
         }
     }
     else if(inp.type.indexOf("checkbox") == 0) {
         var list = $("checkbox[name$='"+suffix+"']").not("[name='"+inp.name+"']"); // Exclude self from list
-        if(view != "") { list =  $(list).filter(function(index) { return $(this).parents(".blueBox." + view).length == 1; });}
+        if(view != "") { list =  $(list).filter(function(index) { return normed($(this).parents(".blueBox." + view)) != undefined; });}
         if($(list).length>0)
             $(list).attr("checked",$(inp).attr("checked"));
     }
     else if(inp.type.indexOf("radio") == 0) {
         var list = $("input:radio[name$='"+suffix+"']").not("[name='"+inp.name+"']");
         list = $(list).filter("[value='"+inp.value+"']")
-        if(view != "") { list =  $(list).filter(function(index) { return $(this).parents(".blueBox." + view).length == 1; });}
+        if(view != "") { list =  $(list).filter(function(index) { return normed($(this).parents(".blueBox." + view)) != undefined; });}
         if($(list).length>0)
             $(list).attr("checked",true);
     }
     else {  // Various types of inputs
         var list = $("input[name$='"+suffix+"']").not("[name='"+inp.name+"']");//.not("[name^='boolshad.']"); // Exclude self from list
-        if(view != "") { list =  $(list).filter(function(index) { return $(this).parents(".blueBox." + view).length == 1; });}
+        if(view != "") { list =  $(list).filter(function(index) { return normed($(this).parents(".blueBox." + view)) != undefined; });}
         if($(list).length>0)
             $(list).val(inp.value);
         //else {
         //    alert("Unsupported type of multi-level cfg setting type='"+inp.type+"'");
         //    return false;
         //}
     }
     return true;
 }
 
 function compositeCfgRegisterOnchangeAction(prefix)
 {
 // After composite level cfg settings written to HTML it is necessary to go back and
 // make sure that each time they change, any matching subtrack level cfg setting are changed.
     var list = $("input[name^='"+prefix+".']").not("[name$='.vis']");
@@ -936,31 +947,31 @@
     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
     $( subCbsSelected ).each( function (i)  {
 
         var possibleClasses = $( this ).attr("class").split(" ");
         if( $(possibleClasses).length > 0)
-            possibleClasses = aryRemoveVals(possibleClasses,[ "subCB" ]);
+            possibleClasses = aryRemoveVals(possibleClasses,[ "subCB","changed" ]);
         if( $(possibleClasses).length > 0)
             possibleSelections = possibleSelections.concat(possibleClasses);
     });
     //warnSince('filterCompositeExcludeOptions('+filterClass+'): possibleSelections: '+possibleSelections.length);
 
     // 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) {
                 if($(opts[ix]).hasClass('excluded') == false) {
                     $(opts[ix]).addClass('excluded');
                     updated = true;
                 }
@@ -1057,214 +1068,235 @@
 { // Special ONLY for hgTrackUi sorting.  Others use utils.js::tableSortOnButtonPress()
     var table = $( anchor ).parents("table.sortable");
     if (table) {
         subtrackCfgHideAll(table);
         waitOnFunction( _tableSortOnButtonPressEncapsulated, anchor, tagId);
     }
     return false;  // called by link so return false means don't try to go anywhere
 }
 
 var scm = { // subtrack config module.
     // 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 have no 'name' attribute until the user alters their value.
-    // Unnamed controls are not sent to the cart.
+    // Unnamed controls are not sent to the cart!!!
 
     // Definitions as used here:
     // obj: an input or select style html control which may be named or unnamed
     //   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
     // named: control with a name attribute which means it has been updated by the user.
     //        Unfortunately radio buttons are an exception, since they must keep their names.
     // unnamed: control that has not been updated by the user.  Will not be sent to cart.
 
     // TODO:
-    // 1) outside in: matrix and subtrack checkboxes to affect vis
-    // 2) Non-configurable will need to show/change vis independently! (separate vis control instead of wrench?)
-    // 3) SOLVED: Radio buttons work BUT they require name to keep unified set, so rely upon 'changed' class to detect changes.
-    // 4) SOLVED: checkboxes: working with name = boolshad.{name}   FIXME: multishad?
-    // 5) SOLVED: filterBy,filterComp working: they rely upon id, and id with '.' screwed it all up.  So replaced '.' with '_-'
-    // 6) SOLVED: subCfg not matching parent: solved.
-    // 7) SOLVED: OpenChromSynth: subtrack filterby needs to be updated by composite filterBy.
-    // 8) Remove debug code when ready
-    // - check subtrack to enable/disable fauxVis and wrench
-    // - matCB should effect subCb including enable/disable fauxVis and wrench
-    // - composite/view vis should effect subVis and enable/disable fauxVis and wrench
+    //  1) SOLVED: Radio buttons work BUT they require name to keep unified set, so rely upon 'changed' class to detect changes.
+    //  2) SOLVED: checkboxes: working with name = boolshad.{name}   FIXME: multishad?
+    //  3) SOLVED: filterBy,filterComp working: they rely upon id, and id with '.' screwed it all up.  So replaced '.' with '_-'
+    //  4) SOLVED: subCfg not matching parent: solved.
+    //  5) SOLVED: OpenChromSynth: subtrack filterby needs to be updated by composite filterBy.
+    //  6) SOLVED: check subtrack to enable/disable fauxVis and wrench
+    //  7) SOLVED: matCB should effect subCb including enable/disable fauxVis and wrench
+    //  8) SOLVED: composite/view vis should effect subVis and enable/disable fauxVis and wrench
+    //  9) SOLVED: inside out: changing subtrack vis should affect subCB and matCB
+    // 10) SOLVED: Loosing checked tracks!!!  Setting vis clears checkboxes?
+    // 11) When parent vis makes subs hidden, shouuld they go to unchecked?
+    // 12) Should user be able to click on disabled vis to check the CB?
+    // 13) Make vis changes "reshape" composite!  NOTE: Do we want to do this???
+    // 14) Non-configurable will need to show/change vis independently! (separate vis control but no wrench)
+    // - Verify all composites work (conservation and SNPs are likely failures)
+    // - Decide on a name (scm, subCfg, ? ) and then make a module file like ddcl.js.
+    // - Remove debug code when ready
     // NOTE:
     // Current implementation relies upon '.' delimiter in name and no '_-' in name.  Nothing breaks rule yet...
 
     //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
-    compositeId: null,
+    compositeId: undefined,
     visIndependent: false,
     viewIds: [],
 
     markChange: function (obj)
     { // Marks a control as having been changed by the user.  Naming will send value to cart.
         $(obj).addClass('changed');
-        if(obj.type.indexOf("radio") != 0) {   // radios must keep their names!
+
+        if(obj.type.indexOf("radio") == 0)   // radios must keep their names!
+            return;
+
             var oldName = obj.id.replace(/\_\-/g,'.');   // sanitized id replaces '.' with '_-'
             $(obj).attr('name',oldName);
+
+        // checkboxes have hidden boolshads which should be marked when unchecked
+        if(obj.type.indexOf("checkbox") == 0) {
+            var boolshad = normed($('input#boolshad_-' + obj.id));
+            if (boolshad != undefined) {
+                if(obj.checked == false) {
+                    var oldName = boolshad.id.replace(/\_\-/g,'.');   // sanitized id replaces '.' with '_-'
+                    $(obj).addClass('changed');
+                    $(boolshad).attr('name',oldName);
+                }
+                else
+                    scm.clearChange(boolshad);
+            }
         }
     },
 
     clearChange: function (obj)
     { // Mark as unchanged
         $(obj).removeClass('changed');
-        if(obj.type.indexOf("radio") != 0)   // radios must keep their names!
+
+        if(obj.type.indexOf("radio") == 0)    // radios must keep their names!
+            return;
+
             $(obj).removeAttr('name');
-    },
 
-    markCheckboxChange: function (obj)
-    { // Marks a checkbox as having changed and the boolshad too if there is one
-        scm.markChange(obj);
-
-        //var safeId = obj.id.replace(/\./g,"\\.");
-        //var boolshad = $('input#boolshad\\.' + safeId);
-        var boolshad = $('input#boolshad_-' + obj.id);
-        if (boolshad != undefined && boolshad.length > 0) {
-            if (boolshad.length == 1)
-                boolshad = boolshad[0];
-            if(obj.checked == false)
-                scm.markChange(boolshad);
-            else
-                scm.clearChange(boolshad);
+        // checkboxes have hidden boolshads which should be cleared in tandem
+        if(obj.type.indexOf("checkbox") == 0) {
+            var boolshad = normed($('input#boolshad_-' + obj.id));
+            if (boolshad != undefined) {
+                $(boolshad).removeClass('changed');
+                $(boolshad).removeAttr('name');
+            }
         }
     },
 
     hasChanged: function (obj)
     { // Is this object updated (value changed by a user)?
         return $(obj).hasClass('changed');
     },
 
     unnameIt: function (obj,setId)
     { // removes a control's name so that it will not be updated to the cart upon submit
       // If setId and obj has a name, will set id to current name
-        if (setId) {
             var myName = $(obj).attr('name');
             if (myName && myName.length > 0) {
+
+            // checkboxes have hidden boolshads which should be unamed in tandem
+            if(obj.type.indexOf("checkbox") == 0) {
+                var boolshad = normed( $("input[name='boolshad\\."+myName+"']") );  // Not yet sanitized name
+                if (boolshad != undefined) {
+                    scm.unnameIt(boolshad,setId);  // self referencing but boolshad not(':checkbox')
+                }
+            }
+
+            if (setId) {
                 // DEBUG -------------
                 if (myName.indexOf('_-') >= 0)
-                    warn("Found control with '_-' in name: "+myName + "<BR>This violates the naming rules and will break javascript code.");
+                    warn("DEBUG: Found control with '_-' in name: "+myName + "<BR>This violates the naming rules and will break javascript code.");
+                // DEBUG -------------
+                var newId = myName.replace(/\./g,'_-');   // sanitized id replaces '.' with '_-'
+
+                // DEBUG -------------
+                if (obj.id && obj.id.length > 0 && obj.id != myName)
+                    warn("DEBUG: Obj is being re-ID'd but it already has an ID.  Old:'"+obj.id+"'  New:'"+newId+"'");
                 // DEBUG -------------
-                myName = myName.replace(/\./g,'_-');   // sanitized id replaces '.' with '_-'
-                $(obj).attr('id',myName);
+                $(obj).attr('id',newId);
             }
         }
-        scm.clearChange(obj);
+
+        scm.clearChange(obj);  // actually removes the name!
     },
 
     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 = scm.compositeCfgFind();
-        var compObj = undefined;
+        //var compCfg = scm.compositeCfgFind();  // TODO: when there is a composite cfg div!
+        var compObj;
         if (suffix != undefined) {
             //compObj = $('#'+ scm.compositeId + '\\.' + suffix);
-            compObj = $('#'+ scm.compositeId + '_-' + suffix);
-            if (compObj == undefined || compObj.length == 0) {
-                compObj = $('#'+ scm.compositeId + '_' + suffix);
+            compObj = normed($('#'+ scm.compositeId + '_-' + suffix));
+            if (compObj == undefined) {
+                compObj = normed($('#'+ scm.compositeId + '_' + suffix));
             }
         } else {
-            compObj = $("#"+scm.compositeId);
+            compObj = normed($("#"+scm.compositeId));
         }
-        if (compObj == undefined || compObj.length == 0) {
-            //warn('Could not find viewObj for '+suffix);
-            return undefined;
-        }
-        if (compObj.length == 1)
-            compObj = compObj[0];
         return compObj;
     },
 
     viewIdFind: function (childObj)
     { // returns the name of the view that is a parent of this subtrack control
-        var cfg = $(childObj).parents('div.subCfg');
-        if (cfg == undefined || cfg.length == 0) {
+        var cfg = normed($(childObj).parents('div.subCfg'));
+        if (cfg == undefined) {
+            // could be vis outside of cfg div
+            var subCb = normed($(childObj).closest('tr').find('input.subCB'));
+            if (subCb != undefined) {
+                var classList = $(subCb).attr("class").split(" ");
+                classList = aryRemove(classList,"changed");
+                return classList[classList.length - 1];
+            }
             warn("Can't find containing div.subCfg of child '"+$(childObj).attr('id')+"'.");
             return undefined;
         }
-        var classList = $( cfg[0] ).attr("class").split(" ");
+        var classList = $( cfg ).attr("class").split(" ");
         classList = aryRemove(classList,"subCfg","filled");
         if (classList.length == 0) {
             warn("Subtrack cfg div does not have view class for child '"+$(childObj).attr('id')+"'.");
             return undefined;
         } else if (classList.length > 1) {
             warn("Subtrack cfg div for '"+$(childObj).attr('id')+"' has unexpected class: "+classList);
             return undefined;
         }
         if (classList[0] == 'noView') // valid case
             return undefined;
         return classList[0];
     },
 
     viewCfgFind: function (viewId)
     { // returns the cfg container for a given view
-        var viewCfg = $('tr#tr_cfg_'+viewId);
-        if (viewCfg == undefined || viewCfg.length == 0) {
+        var viewCfg = normed($('tr#tr_cfg_'+viewId));
+        if (viewCfg == undefined) {
             warn('Could not find viewCfg for '+viewId);
         }
-        if (viewCfg.length == 1)
-            viewCfg = viewCfg[0];
         return viewCfg;
     },
 
     viewObjFind: function (viewId,suffix)
     { // returns the control belonging to this view and suffix
-        var viewObj = undefined;
+        var viewObj;
         if (suffix != undefined) {
             var viewCfg = scm.viewCfgFind(viewId);
-            //viewObj = $(viewCfg).find("[id$='\\."+suffix+"']");
-            viewObj = $(viewCfg).find("[id$='_-"+suffix+"']");
-            if (viewObj == undefined || viewObj.length == 0) {
-                viewObj = $(viewCfg).find("[id$='_"+suffix+"']");
-            }
-        } else {
-            //viewObj = $("#"+scm.compositeId+"\\."+viewId+"\\.vis");
-            viewObj = $("#"+scm.compositeId+"_-"+viewId+"_-vis");
-        }
-        if (viewObj == undefined || viewObj.length == 0) {
-            // Okay not to find a view for this composite level obj
-            //warn('Could not find viewObj for '+viewId+'.'+suffix);
-            return undefined;
-        }
-        if (viewObj.length == 1)
-            viewObj = viewObj[0];
+            viewObj = normed($(viewCfg).find("[id$='_-"+suffix+"']"));
+            if (viewObj == undefined)
+                viewObj = normed($(viewCfg).find("[id$='_"+suffix+"']"));
+        } else
+            viewObj = normed($("#"+scm.compositeId+"_-"+viewId+"_-vis"));
+
         return viewObj;
     },
 
     childObjsFind: function (viewId,suffix)
     { // returns an array of objs for this view and suffix
       // Assumes composite wide if viewId is not provided
       // Assumes vis if suffix is not provided
 
         if (viewId != undefined) {
             var childCfgs = $('div.subCfg.filled.'+viewId);
         } else {
             var childCfgs = $('div.subCfg.filled');
         }
-        if (childCfgs == undefined || childCfgs.length == 0)
+        if (childCfgs == undefined)
             return [];
 
         var childObjs = [];
         if (suffix != undefined)
             childObjs = $(childCfgs).find('select,input').filter("[id$='_-"+suffix+"']");
         else
             childObjs = $(childCfgs).find('select.visDD');
 
         if (childObjs == undefined)
             return [];
 
         return childObjs;
     },
 
     objSuffixGet: function (obj)
@@ -1275,55 +1307,53 @@
             warn("Can't resolve id for '"+$(obj).attr('id')+"'.");
             return undefined;
         }
         if (nameParts.length < 2)
             return undefined;
 
         nameParts.shift();
         if (scm.viewIds.length > 0 && nameParts.length > 1) // FIXME: I expect more problems with this!
             nameParts.shift();
 
         return nameParts.join('_-');
     },
 
     childCfgFind: function (childObj)
     { // returns the cfg wrapper for a child vis object
-        var childCfg = $(childObj).parents('div.subCfg.filled');
-        if (childCfg == undefined || childCfg.length == 0) {
+        var childCfg = normed($(childObj).parents('div.subCfg.filled'));
+        if (childCfg == undefined)
             warn("Can't find childCfg for "+childObj.id);
-            return false;
-        }
-        if (childCfg.length == 1)
-            childCfg = childCfg[0];
         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 != undefined)
+            return subCb;
+
+        warn("DEBUG: Failed to find subCb for "+childObj.id);
         var childCfg = scm.childCfgFind(childObj);
         if (childCfg == undefined)
             return undefined;
 
         var tr = $(childCfg).parents('tr').first();
         var subtrack = childCfg.id.substring(8); // 'div_cfg_'.length
-        var subCb = $(tr).find("input[name='"+subtrack+"_sel']");
-        if (subCb == undefined || subCb.length == 0) {
+        var subCb = normed($(tr).find("input[name='"+subtrack+"_sel']"));
+        if (subCb == undefined)
             warn("Can't find subCB for subtrack: "+subtrack);
-            return undefined;
-        }
-        if (subCb.length == 1)
-            subCb = subCb[0];
         return subCb;
     },
 
     visChanged: function (childObj)
     { // called on change for a child vis control
         var subCb = scm.subCbFind(childObj);
         if (subCb != undefined) {
             if (childObj.selectedIndex > 0)
                 subCb.checked = true;
                 matSubCbClick(subCb);
         }
         $(childObj).attr('name',childObj.id);
     },
 
     parentsFind: function (childObj)
@@ -1371,44 +1401,42 @@
       // 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 = scm.objSuffixGet(parentObj);
         isVis = (suffix != undefined && suffix == 'vis');  // vis inside of subCfg
 
         var viewId = undefined;
         if (isVis) { // This is a view control
 
             isComposite = (suffix == undefined);
             suffix = undefined;
             if (!isComposite) {
                 var classList = $( parentObj ).attr("class").split(" ");
-                classList = aryRemove(classList,"viewDD","normalText");
+                classList = aryRemove(classList,"viewDD","normalText","changed");
                 if (classList.length != 1) {
                     warn("Unexpected view vis class list:"+classList);
                     return [];
                 }
                 viewId = classList[0];
             }
         } else { // normal obj
 
-            var viewCfg = $(parentObj).parents("tr[id^='tr_cfg_']");
-            isComposite = (viewCfg == undefined || viewCfg.length == 0); // is composite
+            var viewCfg = normed($(parentObj).parents("tr[id^='tr_cfg_']"));
+            isComposite = (viewCfg == undefined); // is composite
             if (!isComposite) {
-                if (viewCfg.length == 1)
-                    viewCfg = viewCfg[0];
                 viewId = viewCfg.id.substring(7); // 'tr_cfg_'.length
             }
         }
 
         if (isComposite) {
 
             // There may be views
             if (scm.viewIds.length > 0) {
                 var allChildren = [];
                 for (var ix = 0;ix < scm.viewIds.length;ix++) {
                     viewId = scm.viewIds[ix];
                     // Get any view objs first
                     var viewObj = scm.viewObjFind(viewId,suffix);
                     if (viewObj != undefined)
                         allChildren[allChildren.length] = viewObj;
@@ -1435,242 +1463,207 @@
     { // 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 isVis = false;
         var suffix = scm.objSuffixGet(parentObj);
         isVis = (suffix == undefined || suffix == 'vis');
         var isComposite = (suffix == undefined);
 
         var subVis = $('.subVisDD');  // select:vis or faux:div
         if (isComposite) {
 
             return subVis;
 
         } else {
             var classList = $( parentObj ).attr("class").split(" ");
-            classList = aryRemove(classList,"viewDD","normalText");
+            classList = aryRemove(classList,"viewDD","normalText","changed");
             if (classList.length != 1) {
                 warn("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
         subCb.checked = check;
         subCb.dsabled = enable;
+        scm.markChange(subCb);
         matSubCBsetShadow(subCb);
         hideOrShowSubtrack(subCb);
-        scm.enableCfg(subCb,null,check);
+        scm.enableCfg(subCb,undefined,check);
     },
 
     propagateSetting: function (parentObj)
     { // propagate composite/view level setting to subtrack children
         var children = scm.childrenFind(parentObj);
         if(parentObj.type.indexOf("checkbox") == 0) {
             var parentChecked = parentObj.checked;
             $(children).each(function (i) {
                 // Note checkbox and boolshad are children.
                 if (this.type != 'hidden')
                     this.checked = parentObj.checked;
                 scm.clearChange(this);
             });
-            // deal with hidden boolshads!
-            //var parentIdSafe = parentObj.id.replace(/\./g,"\\.");
-            //var boolshad = $('input#boolshad\\.'+parentIdSafe);
-            var boolshad = $('input#boolshad_-'+parentObj.id);
-            if (boolshad != undefined && boolshad.length > 0) {
-                if (boolshad.length == 1)
-                    boolshad = boolshad[0];
-                if (parentObj.checked == false)
-                    scm.markChange(boolshad);
-                else
-                    scm.clearChange(boolshad);
-            }
         } else if(parentObj.type.indexOf("radio") == 0) {
-            var parentChecked = parentObj.checked;
             var parentVal = $(parentObj).val();
             $(children).each(function (i) {
-                if ($(this).val() == parentVal)
-                    this.checked = parentObj.checked;
+                this.checked = ($(this).val() == parentVal);
                 scm.clearChange(this);
             });
         } else {// selects and inputs are easy
             var parentVal = $(parentObj).val();
             var updateDdcl = ($(parentObj).hasClass('filterBy') || $(parentObj).hasClass('filterComp'));
             $(children).each(function (i) {
                 $(this).val(parentVal);
                 scm.clearChange(this);
                 if (updateDdcl)
                     ddcl.onComplete(this);
             });
         }
         scm.markChange(parentObj);
     },
 
     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)
             visText = 'squish';
         else if (limitedVis == 3)
             visText = 'pack';
         else if (limitedVis == 4)
             visText = 'full';
-        // vis outside of subCfg
+
         var children = scm.visChildrenFind(viewObj);
         $(children).each(function (i) {
             if ($(this).hasClass('fauxInput')) {
                 $(this).text(visText);
             } else {
                 $(this).attr('selectedIndex',limitedVis);
                 scm.clearChange(this);
             }
         });
-        // vis inside of subCfg
-        //var children = scm.childrenFind(viewObj);
-        //$(children).each(function (i) {
-        //    // TODO: only set if selected?
-        //    $(this).attr('selectedIndex',limitedVis);
-        //    scm.clearChange(this);
-        //});
     },
 
     propagateVis: function (parentObj,viewId)
     { // propagate vis settings to subtrack children
-        if (viewId == null) {
+        if (viewId == undefined) {
             // Walk through views and set with this
             var parentVis = parentObj.selectedIndex;
             if (scm.viewIds.length > 0) {
                 for (var ix=0;ix<scm.viewIds.length;ix++) {
                     var viewObj = scm.viewObjFind(scm.viewIds[ix]);//,undefined);
                     if (viewObj != undefined)
                         scm.propagateViewVis(viewObj,parentVis);
                 }
             } else { // No view so, simple
-                // vis outside of subCfg
+
                 var visText = 'hide';
                 if (parentVis == 1)
                     visText = 'dense';
                 else if (parentVis == 2)
                     visText = 'squish';
                 else if (parentVis == 3)
                     visText = 'pack';
                 else if (parentVis == 4)
                     visText = 'full';
                 var children = scm.visChildrenFind(parentObj);
                 $(children).each(function (i) {
                     if ($(this).hasClass('fauxInput')) {
                         $(this).text(visText);
                     } else {
                         $(this).attr('selectedIndex',parentVis);
                         scm.clearChange(this);
                     }
                 });
-                // vis inside of subCfg
-                //var children = scm.childrenFind(parentObj);
-                //$(children).each(function (i) {
-                //    var subCb = scm.subCbFind(this);
-                //    if (subCb != undefined) {
-                //        if (subCb.disabled != true && subCb.checked) {  // TODO: Integrate with things that enable/check!
-                //            $(this).attr('selectedIndex',parentVis);
-                //            scm.clearChange(this);
-                //        }
-                //    }
-                //});
             }
         } else {
             // First get composite vis to limit with
             var compObj = scm.compositeObjFind(undefined);
             if (compObj == undefined) {
                 warn('Could not find composite vis object!');
                 return false;
             }
             scm.propagateViewVis(parentObj,compObj.selectedIndex);
         }
     },
 
-    inheritSetting: function (childObj)
+    inheritSetting: function (childObj,force)
     { // update value if parents values override child values.
         var myParents = scm.parentsFind(childObj);
         if (myParents == undefined || myParents.length < 1) {
             // DEBUG -------------  It is probably okay to subCfg without parent cfg, but we need to be sure
-            warn('No parents were found for childObj: '+childObj.id);
+            warn('DEBUG No parents were found for childObj: '+childObj.id);
             // DEBUG -------------
             return true;
         }
         var isVis = (undefined == scm.objSuffixGet(childObj));
         if (isVis) {
             var subCb = scm.subCbFind(childObj);
             if (subCb != undefined) {
-                if (subCb.disabled == true || subCb.checked == false)   // TODO: Integrate with _sel subCbs and matCbs
-                    $(childObj).attr('selectedIndex',0);
-                else {
                     var limitedVis = 9;
-                    if (myParents.length == 1 && scm.hasChanged(myParents[0]))
+                if (myParents.length == 1 && (force || scm.hasChanged(myParents[0])))
                         limitedVis = myParents[0].selectedIndex;
                     else if (myParents.length == 2) {
-                        if (scm.hasChanged(myParents[0]) || scm.hasChanged(myParents[1]))
+                    if (force || scm.hasChanged(myParents[0]) || scm.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.indexOf("checkbox") == 0) {
                 $(myParents).each(function (i) {
-                    if (scm.hasChanged(this)) {
+                    if (force || scm.hasChanged(this)) {
                         childObj.checked = this.checked;
                         // can ignore boolshad because this does not change
                         count++;
                     }
                 });
             } else if(childObj.type.indexOf("radio") == 0) {
                 $(myParents).each(function (i) {
-                    if (scm.hasChanged(this)) {
+                    if (force || scm.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 (scm.hasChanged(this)) {
+                    if (force || scm.hasChanged(this)) {
                         $(childObj).val($(this).val());
                         count++;
                     }
                 });
             }
             if (count > 1) // if hasChanged() is working, there should never be more than one
                 warn('Both composite and view are seen as updated!  Named update is not working.');
         }
     },
 
-    currentCfg: null, // keep track of cfg while ajaxing, man
-    currentSub: null, // keep track of subtrack while ajaxing, dude
+    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 cfg = scm.currentCfg;
-        scm.currentCfg = null;
+        scm.currentCfg = undefined;
         var cleanHtml = content;
         var shlurpPattern=/\<script type=\'text\/javascript\' SRC\=\'.*\'\>\<\/script\>/gi;
         // DEBUG -------------
             var jsFiles = cleanHtml.match(shlurpPattern);
             if (jsFiles && jsFiles.length > 0)
                 alert("jsFiles:'"+jsFiles+"'\n---------------\n"+cleanHtml); // warn() interprets html, etc.
         // DEBUG -------------
         cleanHtml = cleanHtml.replace(shlurpPattern,"");
         shlurpPattern=/\<script type=\'text\/javascript\'>.*\<\/script\>/gi;
         // DEBUG -------------
             var jsEmbeded = cleanHtml.match(shlurpPattern);
             if (jsEmbeded && jsEmbeded.length > 0)
                 alert("jsEmbeded:'"+jsEmbeded+"'\n---------------\n"+cleanHtml);
         // DEBUG -------------
         cleanHtml = cleanHtml.replace(shlurpPattern,"");
@@ -1711,374 +1704,356 @@
         $(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('Did not find controls for cfg: ' + cfg.id);
             return;
         }
         $(subObjs).each(function (i) {
             if (this.name != undefined) { // The filter("[name]") above didn't do it!
                 if (this.type != 'hidden') {
                     scm.unnameIt(this,true);
-                    scm.inheritSetting(this); // updates any values that have been changed on this page
+                    scm.inheritSetting(this,false); // updates any values that have been changed on this page
                     // if view vis do more than just name it on change
                     var suffix = scm.objSuffixGet(this);
                     if (suffix == undefined) // vis
                         $(this).bind('change',function (e) {
                             scm.visChanged(this);
                         });
                     else {
                         $(this).bind('change',function (e) {
-                            if(this.type.indexOf("checkbox") == 0)
-                                scm.markCheckboxChange(this);
-                            else
                                 scm.markChange(this);
                         });
                     }
-                } else {//if (this.type == 'hidden') {
-                    // Special for checkboixes with name = boolshad.{name}.
-                    if ("boolshad." == this.name.substring(0,9)) {
-                        scm.unnameIt(this,true);
-                    }
                 }
             }
         });
         // 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 (scm.visIndependent) {
             shiftLeft *= ($(cfg).position().left - 125);
-            var subVis = $('div#' + scm.currentSub+'_faux');
-            if (subVis != undefined && subVis.length == 1) {
-                // SHOULD NOT NEED $(subVis[0]).removeClass('disabled');
-                scm.replaceWithVis(subVis[0],scm.currentSub,false);
-            }
+            var subVis = normed($('div#' + scm.currentSub+'_faux'));
+            if (subVis != undefined)
+                scm.replaceWithVis(subVis,scm.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
-        if (newJQuery) {
             $(cfg).find('.filterBy,.filterComp').each( function(i) {
                 if ($(this).hasClass('filterComp'))
                     ddcl.setup(this);
                 else
                     ddcl.setup(this, 'noneIsAll');
             });
-        }
     },
 
     cfgPopulate: function (cfg,subtrack)
     { // Populates a subtrack cfg dialog via ajax and update from composite/view parents
         scm.currentCfg = cfg;
         scm.currentSub = subtrack;
 
         $.ajax({
             type: "GET",
             url: "../cgi-bin/hgTrackUi?ajax=1&g=" + subtrack + "&hgsid=" + getHgsid() + "&db=" + getDb(),
             dataType: "html",
             trueSuccess: scm.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(" ");
         var view = classList[classList.length - 1];
         var classList = $(obj).attr('class').split(' '); // This relies on view being the last class!!!
-        var selectHtml = "<SELECT id='"+subtrack+"' class='normalText subVisDD "+view+"' style='width: 70px'";
-        if (open)
-            selectHtml += " size=5";
+        var selectHtml = "<SELECT id='"+subtrack+"' class='normalText subVisDD "+view+"' style='width:70px;'";
         selectHtml += ">";
         var selected = $(obj).text();
-        if (selected == 'hide')
-            selectHtml += "<OPTION SELECTED>hide</OPTION><OPTION>dense</OPTION><OPTION>squish</OPTION><OPTION>pack</OPTION><OPTION>full</OPTION>";
-        else if (selected == 'dense')
-            selectHtml += "<OPTION>hide</OPTION><OPTION SELECTED>dense</OPTION><OPTION>squish</OPTION><OPTION>pack</OPTION><OPTION>full</OPTION>";
-        else if (selected == 'squish')
-            selectHtml += "<OPTION>hide</OPTION><OPTION>dense</OPTION><OPTION SELECTED>squish</OPTION><OPTION>pack</OPTION><OPTION>full</OPTION>";
-        else if (selected == 'full')
-            selectHtml += "<OPTION>hide</OPTION><OPTION>dense</OPTION><OPTION>squish</OPTION><OPTION>pack</OPTION><OPTION SELECTED>full</OPTION>";
-        else
-            selectHtml += "<OPTION>hide</OPTION><OPTION>dense</OPTION><OPTION>squish</OPTION><OPTION>pack</OPTION><OPTION>full</OPTION>";
+        var visibilities = ['hide','dense','squish','pack','full'];
+        $(visibilities).each( function (ix) {
+             selectHtml += "<OPTION" + (visibilities[ix] == selected ? " SELECTED":"") + ">"+visibilities[ix]+"</OPTION>";
+        });
         selectHtml += "</SELECT>";
         $(obj).replaceWith(selectHtml);
         if (open) {
             var newObj = $('select#'+subtrack);
-            //$(newObj).attr('size',5)
+            $(newObj).css({'zIndex':'2','vertical-align':'top'});
+            $(newObj).attr('size',5);
             $(newObj).one('blur',function (e) {
                 $(this).attr('size',1);
-                $(this).unbind()
+                $(this).unbind('blur');
             });
-            $(newObj).one('change',function (e) {
+            $(newObj).change(function (e) {
+                if ($(this).attr('size') > 1)
                 $(this).attr('size',1);
+                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#' + this.id + '_sel'));
+                    if (subCb != undefined) {
+                        scm.checkOneSubtrack(subCb,false,true);
+                        matSubCbClick(subCb);
+                        scm.inheritSetting(this,true);
+                        scm.unnameIt(this);
+                    // DEBUG -------------
+                    } else {
+                        warn('DEBUG: Cant find subCB for ' + this.id);
+                    // DEBUG -------------
+                    }
+                } else
+                    scm.markChange(this);
             });
-            // Doesn't work!
-            //$(newObj).parents('td').first().attr('valign','top');
             $(newObj).focus();
         }
     },
 
     enableCfg: function (subCb,subtrack,setTo)
     { // Enables or disables subVis and wrench
-        if (subCb == null || subCb == undefined) {
-            if (subtrack == null || subtrack.length == 0) {
-                warn("scm.enableCfg() called without CB or subtrack.");
+        if (subCb == undefined) {
+            if (subtrack == undefined || subtrack.length == 0) {
+                warn("DEBUG: scm.enableCfg() called without CB or subtrack.");
                 return false;
             }
-            subCb = $("input[name='"+subtrack+"'_sel]");
-            if (subCb == undefined || subCb.length == 0) {
-                warn("scm.enableCfg() could not find CB for subtrack: "+subtrack);
+            subCb = normed($("input[name='"+subtrack+"'_sel]"));
+            if (subCb == undefined) {
+                warn("DEBUG: scm.enableCfg() could not find CB for subtrack: "+subtrack);
                 return false;
             }
         }
-        if (subCb.length == 1)
-            subCb = subCb[0];
 
-        var td = $(subCb).parent('td');
-        if (td == undefined || td.length == 0) {
-            warn("scm.enableCfg() could not find TD for CB: "+subCb.name);
+        var td = normed($(subCb).parent('td'));
+        if (td == undefined) {
+            warn("DEBUG: scm.enableCfg() could not find TD for CB: "+subCb.name);
             return false;
         }
-        if (td.length == 1)
-            td = td[0];
-        var subFaux = $(td).find('div.subVisDD');
-        if (subFaux != undefined && subFaux.length > 0) {
+        var subFaux = normed($(td).find('div.subVisDD'));
+        if (subFaux != undefined) {
             if (setTo == true)
                 $(subFaux).removeClass('disabled');
             else
                 $(subFaux).addClass('disabled');
         } else {
-            var subVis = $(td).find('select.subVisDD');
-            if (subVis != undefined && subVis.length > 0) {
-                $(subVis).attr('disable',!setTo);
+            var subVis = normed($(td).find('select.subVisDD'));
+            if (subVis != undefined) {
+                $(subVis).attr('disabled',!setTo);
             }
         }
-        var wrench = $(td).find('span.clickable'); // TODO tighten this
-        if (wrench != undefined && wrench.length > 0) {
+        var wrench = normed($(td).find('span.clickable')); // TODO tighten this
+        if (wrench != undefined) {
             if (setTo == true)
                 $(wrench).removeClass('halfVis');
             else
                 $(wrench).addClass('halfVis');
         }
     },
 
     cfgToggle: function (wrench,subtrack)
     { // Opens/closes subtrack cfg dialog, populating if empty
-        var cfg = $("div#div_cfg_"+subtrack);
-        if (cfg == undefined || cfg.length == 0) {
-            warn("Can't find div_cfg_"+subtrack);
+        var cfg = normed($("div#div_cfg_"+subtrack));
+        if (cfg == undefined) {
+            warn("DEBUG: Can't find div_cfg_"+subtrack);
             return false;
         }
-        if (cfg.length == 1)
-            cfg = cfg[0];
 
         if ($(cfg).css('display') == 'none') {
             if ($(wrench).hasClass('halfVis'))
                 return;
             // Don't allow if this composite is not enabled!
             // find the cb
             var tr = $(cfg).parents('tr').first();
-            var subCb = $(tr).find("input[name='"+subtrack+"_sel']");
-            if (subCb == undefined || subCb.length == 0) {
+            var subCb = normed($(tr).find("#"+subtrack+"_sel"));
+            if (subCb == undefined) {
                 warn("Can't find subCB for "+subtrack);
                 return false;
             }
-            if (subCb.length == 1)
-                subCb = subCb[0];
             if (subCb.disabled == true) // || subCb.checked == false)
                 return false;
 
             if(metadataIsVisible(subtrack))
                 metadataShowHide(subtrack,"","");
             if ($(cfg).hasClass('filled'))
                 $(cfg).show();
             else
                 waitOnFunction( scm.cfgPopulate, cfg, subtrack );
         } else
             $(cfg).hide();
         return false; // called by link!
     },
 
     subCbInit: function (subCb)
     { // unnames the subCb control and sets up on change envent
         scm.unnameIt(subCb,true);
-        var boolshad = $('input#boolshad_-'+subCb.id);
-        if (boolshad != undefined && boolshad.length == 1) {
-            scm.unnameIt(boolshad[0],false);
+
+        var boolshad = normed( $("input[name='boolshad\\."+subCb.id+"']") );  // Not yet sanitized name
+        if (boolshad != undefined) {
+            scm.unnameIt(boolshad,true);
         }
         $(subCb).bind('click',function (e) {
-            // deal with hidden boolshads!
-            var boolshad = $('input#boolshad_-'+subCb.id);
-            if (boolshad != undefined && boolshad.length == 1) {
-                if (subCb.checked == false)
-                    scm.markChange(boolshad[0]);
-                else
-                    scm.clearChange(boolshad[0]);
-            }
             scm.markChange(subCb);
         });
     },
 
     viewInit: function (viewId)
     { // unnames all view controls
         // iterate through all matching controls and unname
-        var tr = $('tr#tr_cfg_'+viewId);
-        if (tr == undefined || tr.length == 0) {
-            warn('Did not find view: ' + viewId);
+        var tr = normed($('tr#tr_cfg_'+viewId));
+        if (tr == undefined) {
+            warn('DEBUG: Did not find view: ' + viewId);
             return;
         }
-        if (tr.length == 1)
-            tr = tr[0];
         var viewAllObjs = $(tr).find('input,select')
         var viewObjs = $(viewAllObjs).not("input[type='hidden']");
         if (viewObjs.length > 0) {
             $(viewObjs).each(function (i) {
                 scm.unnameIt(this,true);
                 $(this).bind('change',function (e) {
                     scm.propagateSetting(this);
                 });
             });
         }
         // Special for checkboxes: boolshad
         var boolObjs = $(viewAllObjs).filter("input[type='hidden']").filter("[name^='boolshad\\.']");
         $(boolObjs).each(function (i) {
             scm.unnameIt(this,true);
         });
 
         // Now vis control
-        var visObj = $("select[name='"+scm.compositeId+"\\."+viewId+"\\.vis']");
-        if (visObj == undefined || visObj.length == 0) {
-            warn('Did not find visibility control for view: ' + viewId);
+        var visObj = normed($("select[name='"+scm.compositeId+"\\."+viewId+"\\.vis']"));
+        if (visObj == undefined) {
+            warn('DEBUG: Did not find visibility control for view: ' + viewId);
             return;
         }
-        if (visObj.length == 1)
-            visObj = visObj[0];
         scm.unnameIt(visObj,true);
         $(visObj).bind('change',function (e) {
             scm.propagateVis(visObj,viewId);
+            scm.markChange(visObj);
         });
     },
 
     initialize: function ()
     { // unnames all composite controls and then all view controls
+      // names will be added back in onchange events
         // mySelf = this; // There is no need for a "mySelf" unless this object is being instantiated.
-        scm.compositeId = $('.visDD').first().attr('name');
-        scm.visIndependent = ($('.subVisDD').length > 0);
+
+        var visObj = $('.visDD');
+        if (visObj == undefined || visObj.length < 1) {
+            warn('DEBUG: Did not find visibility control for composite.');
+            return;
+        }
+        if (visObj.length > 1) {
+            warn('DEBUG: Multiple visibility controls for composite???');
+            return;
+        }
+
+        scm.compositeId = $(visObj).attr('name');
+        scm.visIndependent = ($('.subVisDD').length > 0);  // Can subtracks have their own vis?
+
+        // Unname and set up vis propagation
+        visObj = visObj[0];
+        scm.unnameIt(visObj,true);
+        $(visObj).bind('change',function (e) {
+            scm.propagateVis(visObj,undefined);
+            scm.markChange(visObj);
+        });
 
         // Find all appropriate controls and unname
 
         // matCBs are easy, they never get named again
         var matCbs = $('input.matCB');
         $(matCbs).each(function (i) {
             scm.unnameIt(this,false);
         });
 
         // SubCBs will get renamed and on change will name them back.
         var subCbs = $('input.subCB');
         $(subCbs).each(function (i) {
             scm.subCbInit(this);
         });
 
-        // Now vis control
-        var visObj = $("select[name='"+scm.compositeId+"']");
-        if (visObj == undefined || visObj.length == 0) {
-            warn('Did not find visibility control for composite.');
-            return;
-        }
-        if (visObj.length == 1)
-            visObj = visObj[0];
-        scm.unnameIt(visObj,true);
-        $(visObj).bind('change',function (e) {
-            scm.propagateVis(visObj,null);
-        });
-
         // iterate through views
         var viewVis = $('select.viewDD');
         $(viewVis).each(function (i) {
             var classList = $( this ).attr("class").split(" ");
-            classList = aryRemove(classList,"viewDD","normalText");
+            classList = aryRemove(classList,"viewDD","normalText","changed");
             if (classList.length == 0)
-                warn('View classlist is missing view class.');
+                warn('DEBUG: View classlist is missing view class.');
             else if (classList.length > 1)
-                warn('View classlist contains unexpected classes:' + classList);
+                warn('DEBUG: View classlist contains unexpected classes:' + classList);
             else {
-                scm.viewIds[scm.viewIds.length] = classList[0];
-                scm.viewInit(classList[0]);
+                scm.viewIds[i] = classList[0];
+                scm.viewInit(scm.viewIds[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 in scm
         var compObjs = $('select,input').filter("[name^='"+scm.compositeId+"\\.'],[name^='"+scm.compositeId+"_']");
         if (compObjs != undefined && compObjs.length > 0) {
             compObjs = $(compObjs).not("[name$='showCfg']");
             $(compObjs).each(function (i) {
                 // DEBUG -------------
                 if (this.id != undefined
                 && this.id.length > 0
                 && $(this).hasClass('filterBy') == false
                 && $(this).hasClass('filterComp') == false)
-                    warn('['+this.name + ']  #'+this.id);
+                    warn('DEBUG: Not expected control with name ['+this.name + '], and id #'+this.id);
                 // DEBUG -------------
                 scm.unnameIt(this,true);
                 $(this).bind('change',function (e) {
                     scm.propagateSetting(this);
                 });
             });
         }
         // Special for checkboxes: boolshad
         var boolObjs = $("input[type='hidden']");
         var boolObjs = $(boolObjs).filter("[name^='boolshad\\."+scm.compositeId+"\\.'],[name^='boolshad\\."+scm.compositeId+"_']");
         $(boolObjs).each(function (i) {
             scm.unnameIt(this,true);
         });
 
     }
 };
 
 // The following js depends upon the jQuery library
 $(document).ready(function()
 {
     // If divs with class 'subCfg' then initialize the subtrack cfg code
     // NOTE: must be before any ddcl setup
+    if (common.subCfg) {
     var divs = $("div.subCfg");
     if (divs != undefined && divs.length > 0) {
         scm.initialize();
     }
+    }
 
     // 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 == false)
-            $(this).dropdownchecklist({ firstItemChecksAll: true, noneIsAll: $(this).hasClass('filterBy'), maxDropHeight: filterByMaxHeight(this) });
-    });
-
     // Put navigation links in top corner
     navigationLinksSetup();
 });