4c15f3e254d1e9c7cb3c4dca17f2808c07dbdb4f
tdreszer
  Thu Jul 7 17:52:25 2011 -0700
Moved all ddcl extension code into a ddcl object in ddcl.js.  Reworked filterComp code to be more like filterTable code since IE was getting timeouts on HAIB TFBS.
diff --git src/hg/js/utils.js src/hg/js/utils.js
index da31e3d..a9b5f34 100644
--- src/hg/js/utils.js
+++ src/hg/js/utils.js
@@ -988,46 +988,46 @@
     // Now we can get rid of the wait cursor
     waitMaskClear();
 }
 
 function waitOnFunction(func)
 { // sets the waitMask (wait cursor and no clicking), then launches the function with up to 5 arguments
     if(!jQuery.isFunction(func)) {
         warn("waitOnFunction called without a function");
         return false;
     }
     if(arguments.length > 6) {
         warn("waitOnFunction called with " + arguments.length - 1 + " arguments.  Only 5 are supported.");
         return false;
     }
 
-    waitMaskSetup(5000);  // Find or create the waitMask (which masks the whole page) but gives up after 5sec
+    waitMaskSetup(0);  // Find or create the waitMask (which masks the whole page) but gives up after 5sec
 
     // Special if the first var is a button that can visually be inset
     if(arguments.length > 1 && arguments[1].type != undefined) {
         if(arguments[1].type == 'button' && $(arguments[1]).hasClass('inOutButton')) {
             $(arguments[1]).css( 'borderStyle',"inset");
         }
     }
 
     // Build up the aruments array
     for(var aIx=1;aIx<arguments.length;aIx++) {
         gWaitFuncArgs.push(arguments[aIx])
     }
     gWaitFunc = func;
 
-    setTimeout('_launchWaitOnFunction();',50);
+    setTimeout('_launchWaitOnFunction();',10);
 
 }
 
 // --- yielding iterator ---
 function _yieldingIteratorObject(yieldingFunc)
 { // This is the "recusive object" or ro which is instantiated in waitOnIteratingFunction
   // yieldingFunc is passed in from waitOnIteratingFunction
   // and will recurse which recursively calls an iterator
     this.step = function(msecs,args) {
         setTimeout(function() { yieldingFunc(args); }, msecs); // recursive timeouts
         return;
     }
 }
 
 function yieldingIterator(interatingFunc,continuingFunc,args)
@@ -1841,61 +1841,61 @@
         td.append(response);
         var inp = $(td).find('.mdbVal');
         var tdIsLike = $('td#isLike'+this.num);
         if (inp != undefined && tdIsLike != undefined) {
             if ($(inp).hasClass('freeText')) {
                 $(tdIsLike).text('contains');
             } else if (usesFilterBy && $(inp).hasClass('filterBy')) {
                 $(tdIsLike).text('is among');
             } else {
                 $(tdIsLike).text('is');
             }
         }
         $(td).find('.filterBy').each( function(i) { // Do this by 'each' to set noneIsAll individually
             if (usesFilterBy) {
                 if (newJQuery)
-                    ddclSetup(this,'noneIsAll');
+                    ddcl.setup(this,'noneIsAll');
                 else
                     $(this).dropdownchecklist({ firstItemChecksAll: true, noneIsAll: true, maxDropHeight: filterByMaxHeight(this) });
             } else {
                 $(this).attr("multiple",false);
                 $(this).removeClass('filterBy');
                 $(this).show();
             }
         });
     }
     updateMetaDataHelpLinks(this.num);
 }
 
 function findTracksMdbValChanged(obj)
 { // Keep all tabs with same selects in sync  TODO: Change from name to id based identification and only have one set of inputs in form
   // This handles the currnet case when 2 vars have the same name (e.g. advanced, files tabs)
 
     findTracksClearFound();  // Changing values so abandon what has been found
 
     if ($('#advancedTab').length == 1 && $('#filesTab').length == 1) {
         var newVal = $(obj).val();
         var a = /hgt_mdbVal(\d+)/.exec(obj.name); // NOTE must match METADATA_NAME_PREFIX in hg/hgTracks/searchTracks.c
         if(newVal != undefined && a && a[1]) {
             var num = a[1];
             $("input.mdbVal[name='hgt_mdbVal"+num+"'][value!='"+newVal+"']").val(newVal);
             $("select.mdbVal[name='hgt_mdbVal"+num+"'][value!='"+newVal+"']").each( function (i) {
                 $(this).val(newVal);
                 if ($(this).hasClass('filterBy')) {
                     $(this).dropdownchecklist("destroy");
                     if (newJQuery)
-                        ddclSetup(this,'noneIsAll');
+                        ddcl.setup(this,'noneIsAll');
                     else
                         $(this).dropdownchecklist({ firstItemChecksAll: true, noneIsAll: true, maxDropHeight: filterByMaxHeight(this) });
                 }
             });
         }
     }
     //findTracksSearchButtonsEnable(true);
 }
 
 function findTracksChangeVis(seenVis)
 { // called by onchange of vis
     var visName = $(seenVis).attr('id');
     var trackName = visName.substring(0,visName.length - "_id".length)
     var hiddenVis = $("input[name='"+trackName+"']");
     var tdb = tdbGetJsonRecord(trackName);
@@ -2080,31 +2080,31 @@
 
     return maxHeight;
 }
 
 function findTracksClear()
 {// Clear found tracks and all input controls
     findTracksClearFound();
     $('input[type="text"]').val(''); // This will always be found
     //$('select.mdbVar').attr('selectedIndex',0); // Do we want to set the first two to cell/antibody?
     $('select.mdbVal').attr('selectedIndex',0); // Should be 'Any'
     $('select.filterBy').each( function(i) { // Do this by 'each' to set noneIsAll individually
         //$(this).dropdownchecklist("refresh");  // requires v1.1
         $(this).dropdownchecklist("destroy");
         $(this).show();
         if (newJQuery)
-            ddclSetup(this,'noneIsAll');
+            ddcl.setup(this,'noneIsAll');
         else
             $(this).dropdownchecklist({ firstItemChecksAll: true, noneIsAll: true, maxDropHeight: filterByMaxHeight(this) });
     });
 
     $('select.groupSearch').attr('selectedIndex',0);
     $('select.typeSearch').attr('selectedIndex',0);
     //findTracksSearchButtonsEnable(false);
     return false;
 }
 
 function findTracksSortNow(obj)
 {// Called by radio button to sort tracks
     if( $('#sortIt').length == 0 )
         $('form#trackSearch').append("<input TYPE=HIDDEN id='sortIt' name='"+$(obj).attr('name')+"' value='"+$(obj).val()+"'>");
     else
@@ -2253,31 +2253,31 @@
                 $(element).attr('id','hgt_mdbVal' + rowNum);
         });
         return mdbSelectRows.length;
     }
     return 0;
 }
 
 function findTracksSwitchTabs(ui)
 { // switching tabs on findTracks page
 
     if( ui.panel.id == 'simpleTab' && $('div#found').length < 1) {
         setTimeout("$('input#simpleSearch').focus();",20); // delay necessary, since select event not afterSelect event
     } else if( ui.panel.id == 'advancedTab') {
         // Advanced tab has DDCL wigets which were sized badly because the hidden width was unknown
         // delay necessary, since select event not afterSelect event
-        setTimeout("ddclReinit($('div#advancedTab').find('select.filterBy'),false);",20);
+        setTimeout("ddcl.reinit($('div#advancedTab').find('select.filterBy'),false);",20);
     }
     if( $('div#filesFound').length == 1) {
         if( ui.panel.id == 'filesTab')
             $('div#filesFound').show();
         else
             $('div#filesFound').hide();
     }
     if( $('div#found').length == 1) {
         if( ui.panel.id != 'filesTab')
             $('div#found').show();
         else
             $('div#found').hide();
     }
 }
 
@@ -2290,30 +2290,36 @@
     if($(filter).hasClass('filterBy') == false)
         return undefined;
     if($(filter).hasClass('filterTable') == false)
         return undefined;
 
     // Find the var for this filter
     var classes = $(filter).attr("class").split(' ');
     classes = aryRemove(classes,"filterBy","filterTable","noneIsAll");
     if (classes.length > 1 ) {
         warn('Too many classes for filterBy: ' + classes);
         return undefined;
     }
     return classes.pop();
 }
 
+/* // This version of filterTable() uses the yieldingIterator methods.
+   // These methods and the yieldingIterator were developed because IE was so slow.
+   // HOWEVER: IE was sped up by avoiding .add() and .parent(),
+   // so I reverted to simpler code but wish to retain this example for
+   // future reference of how to deael with slow javascript.
+
 function _filterTableByClassesIterative(args)
 { // Applies a single class filter to a filterTable TRs
   // Called via yieldingIterator
     if (args.curIx >= args.classes.length)
         return 0;
 
     var tds = $(args.tdsRemaining).filter('.' + args.classes[args.curIx]);
     if (tds.length > 0) {
         if (args.tdsFiltered == null)
             args.tdsFiltered = tds;
         else
             args.tdsFiltered = jQuery.merge( args.tdsFiltered, tds );  // This one takes too long in IE!
     }
     //warnSince("Iterating class:"+args.curIx);
     args.curIx++;
@@ -2354,57 +2360,57 @@
         return 0;
 
     var filter = args.filters[args.curIx];
 
     var classes = $(filter).val();
     if (classes == null || classes.length == 0)
         {
         args.trsRemaining = null;
         return 0; // Nothing selected so exclude all rows
         }
 
     if(classes[0] != 'All') { // nothing excluded by this filter
         // Get the filter variable
         var filterVar = filterTableFilterVar(filter);
         if (filterVar != undefined) {// No filter variable?!
-            //if ($.browser.msie) {   // Special for IE, since it takes so long
-            //    var classesStruct = new Object;
-            //    classesStruct.filtersStruct = args;
-            //    classesStruct.classes       = classes;
-            //    classesStruct.curIx         = 0;
-            //    classesStruct.tdsRemaining = $(args.trsRemaining).children('td.' + filterVar);
-            //    classesStruct.tdsFiltered = null;
-            //    yieldingIterator(_filterTableByClassesIterative,_filterTableByClassesComplete,classesStruct);
-            //    return -1; // Stops itteration now, but will be resumed in _filterTableByClassesComplete
-            //} else {
+            if ($.browser.msie) {   // Special for IE, since it takes so long
+                var classesStruct = new Object;
+                classesStruct.filtersStruct = args;
+                classesStruct.classes       = classes;
+                classesStruct.curIx         = 0;
+                classesStruct.tdsRemaining = $(args.trsRemaining).children('td.' + filterVar);
+                classesStruct.tdsFiltered = null;
+                yieldingIterator(_filterTableByClassesIterative,_filterTableByClassesComplete,classesStruct);
+                return -1; // Stops itteration now, but will be resumed in _filterTableByClassesComplete
+            } else {
                 var varTds = $(args.trsRemaining).children('td.' + filterVar);
                 var filteredTrs = null;
                 for(var ix=0;ix<classes.length;ix++) {
                     var tds = $(varTds).filter('.' + classes[ix]);
                     if (tds.length > 0) {
                         var trs = [];
                         $(tds).each(function (ix) {
                             trs[ix] = this.parentNode;
                         });
                         if (filteredTrs == null)
                             filteredTrs = trs; // $(tds).parent('tr'); // parent() takes too long in IE
                         else
                             filteredTrs = jQuery.merge( filteredTrs, trs );// $(tds).parent() );  // takes too long in IE!
                     }
                 }
                 args.trsRemaining = filteredTrs;
-            //}
+            }
         }
     }
     args.curIx++;
     if (args.curIx >= args.filters.length)
         return 0;
     return 1;
 }
 
 function _filterTableComplete(args)
 { // Continuation after all the filters have been applied
   // Called via yieldingIterator
 
     //warnSince("Completing...");
     //$('tr.filterable').hide();  // <========= This is what is taking so long!
     $('tr.filterable').css('display', 'none');
@@ -2417,74 +2423,49 @@
         var counter = $('.filesCount');
         if(counter != undefined)
             $(counter).text($(args.trsRemaining).length + " / ");
     } else {
         var counter = $('.filesCount');
         if(counter != undefined)
             $(counter).text(0 + " / ");
     }
 
     var tbody = $( $('tr.filterable')[0] ).parent('tbody.sorting');
     if (tbody != undefined)
          $(tbody).removeClass('sorting');
     //warnSince("Really complete.");
 }
 
-function _filterTableOld()
-{ // Called by filter onchange event.  Will show/hide trs based upon all filters
-    var showTrs = filterTablesTrsSurviving();
-    //$('tr.filterable').hide();  // <========= This is what is taking so long!
-    $('tr.filterable').css('display', 'none')
-
-    if (showTrs != undefined && showTrs.length > 0) {
-        //$(showTrs).show();
-        $(showTrs).css('display', '');
-
-        // Update count
-        var counter = $('.filesCount');
-        if(counter != undefined)
-            $(counter).text($(showTrs).length + " / ");
-    } else {
-        var counter = $('.filesCount');
-        if(counter != undefined)
-            $(counter).text(0 + " / ");
-    }
-
-    var tbody = $( $('tr.filterable')[0] ).parent('tbody.sorting');
-    if (tbody != undefined)
-         $(tbody).removeClass('sorting');
-}
-
-function _filterTable()
+function _filterTableYielding()
 { // Called by filter onchange event.  Will show/hide trs based upon all filters
     var trsAll = $('tr.filterable'); // Default all
     if (trsAll.length == 0)
         return undefined;
 
     // Find all filters
     var filters = $("select.filterBy");
     if (filters.length == 0)
         return undefined;
 
     var filtersStruct = new Object;
     filtersStruct.filters = filters;
     filtersStruct.curIx = 0;
     filtersStruct.trsRemaining = trsAll;
 
     yieldingIterator(_filterTableIterative,_filterTableComplete,filtersStruct);
 }
-
+*/
 
 function filterTablesApplyOneFilter(filter,remainingTrs)
 { // Applies a single filter to a filterTables TRs
     var classes = $(filter).val();
     if (classes == null || classes.length == 0)
         return null; // Nothing selected so exclude all rows
 
     if(classes[0] == 'All')
         return remainingTrs;  // nothing excluded by this filter
 
     // Get the filter variable
     var filterVar = filterTableFilterVar(filter);
     if (filterVar == undefined)
         return null;
 
@@ -2520,56 +2501,81 @@
     // Find all filters
     var filters = $("select.filterBy");
     if (filters.length == 0)
         return undefined;
 
     // Exclude one if requested.
     if (filterClass != undefined && filterClass.length > 0)
         filters = $(filters).not('.' + filterClass);
 
     for(var ix =0;showTrs != null && ix < filters.length;ix++) {
         showTrs = filterTablesApplyOneFilter(filters[ix],showTrs)
     }
     return showTrs;
 }
 
+function _filterTable()
+{ // Called by filter onchange event.  Will show/hide trs based upon all filters
+    var showTrs = filterTablesTrsSurviving();
+    //$('tr.filterable').hide();  // <========= This is what is taking so long!
+    $('tr.filterable').css('display', 'none')
+
+    if (showTrs != undefined && showTrs.length > 0) {
+        //$(showTrs).show();
+        $(showTrs).css('display', '');
+
+        // Update count
+        var counter = $('.filesCount');
+        if(counter != undefined)
+            $(counter).text($(showTrs).length + " / ");
+    } else {
+        var counter = $('.filesCount');
+        if(counter != undefined)
+            $(counter).text(0 + " / ");
+    }
+
+    var tbody = $( $('tr.filterable')[0] ).parent('tbody.sorting');
+    if (tbody != undefined)
+         $(tbody).removeClass('sorting');
+}
+
 function filterTableTrigger()
 { // Called by filter onchange event.  Will show/hide trs based upon all filters
     var tbody = $( $('tr.filterable')[0] ).parent('tbody');
     if (tbody != undefined)
          $(tbody).addClass('sorting');
 
-    setTimeout('_filterTableOld();',2); // Just in case
+    waitOnFunction(_filterTable);
 }
 
 function filterTableDone(event)
 { // Called by custom 'done' event
     event.stopImmediatePropagation();
     $(this).unbind( event );
-    waitOnFunction(filterTableTrigger);
+    filterTableTrigger();
 }
 
-function filterTable(selector)
+function filterTable(multiSelect)
 { // Called by filter onchange event.  Will show/hide trs based upon all filters
     // IE takes tooo long, so this should be called only when leaving the filterBy box
     if ( $('tr.filterable').length > 300) {
         //if ($.browser.msie) { // IE takes tooo long, so this should be called only when leaving the filterBy box
-            $(selector).one('done',filterTableDone);
+            $(multiSelect).one('done',filterTableDone);
             return;
         //}
     } else
-        waitOnFunction(filterTableTrigger);
+        filterTableTrigger();
 }
 
 function filterTableExcludeOptions(filter)
 { // bound to 'click' event inside ui.dorpdownchecklist.js.
   // Will mark all options in one filterBy box that are inconsistent with the current
   // selections in other filterBy boxes.  Mark with class ".excluded"
 
     // Find the var for this filter
     var filterVar = filterTableFilterVar(filter);
     if (filterVar == undefined)
         return false;
 
     // Look at list of visible trs.
     var visibleTrs = filterTablesTrsSurviving(filterVar);
     if (visibleTrs == undefined)
@@ -2611,318 +2617,15 @@
             $(this).removeClass('excluded'); // remove .excluded from matching
         else
             $(this).addClass('excluded');    // add .excluded" to non-matching
     });
 
     // If all options except "all" are included then all should nt be excluded
     var excluded = $(filter).children('option.excluded');
     if (excluded.length == 1) {
         var text = $(excluded[0]).text();
         if (text == 'All' || text == 'Any')
             $(excluded[0]).removeClass('excluded');
     }
     return true;
 }
 
-
-/////////// DDCL: drop-down checkbox-list wrapper code /////////////
-
-function textOfObjWrappedInStyle(obj)
-{ // returns the obj text and if there is obj style, the text gets span wrapped with it
-    var text = '';
-    var style = $(obj).attr('style');
-    if (style != undefined && style.length > 0)
-        text = "<span style='"+style+"'>";
-    text += $(obj).text();
-    if (style != undefined && style.length > 0)
-        text += "</span>";
-
-    return text;
-}
-
-function ddclTextOfCurrentSelections(options)
-{ // Generates a multi-line string of currently selected options
-    var chosen = $(options).filter(':selected');  // Works with FF and Chrome but not IE!
-    if (chosen.length == 0 && $.browser.msie)
-        chosen = $(options).find(':selected');  // Works with IE but not FF and Chrome!
-    var chosenCount = $(chosen).length;
-    var msg = '';
-    if(chosenCount == 0) {
-        msg = 'Please select...';
-    } else if(chosenCount == 1) {
-        msg = textOfObjWrappedInStyle(chosen[0]);
-    } else if(chosenCount == options.length) {
-        msg = textOfObjWrappedInStyle(options[0]);
-    } else {
-        for(var ix=0;ix<chosenCount;ix++) {
-            if (ix > 0)
-                msg += "<BR>";
-            msg += textOfObjWrappedInStyle(chosen[ix]);
-        }
-    }
-    return msg;
-}
-
-function ddclLabelSet(control,msg,newTextColor,newTitle)
-{ // Sets the label text (as opposed to the drop-down options)
-    var controlLabel    = $(control).find(".ui-dropdownchecklist-text");
-    var controlSelector = $(control).find(".ui-dropdownchecklist-selector");
-    var newHeight = msg.split('<BR>').length * 20;
-    //$(control).css('height',newHeight + 'px');
-    $(controlSelector).css({height: newHeight + 'px', background: '#fff'});
-    $(controlLabel).attr('title',newTitle);
-    $(controlLabel).css({height: newHeight + 'px'});
-    $(controlLabel).css('color',newTextColor ); // could be empty string, thus removing the color
-    $(controlLabel).html(msg);
-}
-
-function ddclOnOpen(event)
-{ // Called by a DDCL onClick event (when the drop list is opened)
-
-    // Set the label
-    var control = $(this).parent();
-    ddclLabelSet(control,"Select multiple...",'#000088','Selecting...');
-
-    // Find the active 'items' and original 'options'
-    var id = $(control).attr('id').substring('ddcl-'.length);
-    var dropWrapper = $('#ddcl-' + id + '-ddw');//.first();
-    var selector = $('#' + id);
-    var allCheckboxes = $(dropWrapper).find("input.active");
-    var selectOptions = selector[0].options;
-
-    // Special juice to handle "exclude" options based upon competing filterBoxes
-    try {
-        if(($(selector).hasClass('filterComp')  && filterCompositeExcludeOptions(selector))
-        || ($(selector).hasClass('filterTable') && filterTableExcludeOptions(selector))) {
-
-            // "exclude" items based upon the exclude tag of the true options
-            allCheckboxes.each(function(index) {
-                var item = $(this).parent();
-                if($(selectOptions[index]).hasClass('excluded')) {
-                    $(item).addClass("ui-state-excluded");
-                } else //if($(item).hasClass("ui-state-excluded"))
-                    $(item).removeClass("ui-state-excluded");
-            });
-        }
-    }
-    catch (err) {} // OK if filterCompositeExcludeOptions is not defined.
-
-    // Show only first as selected if it is selected
-    if (allCheckboxes[0].checked == true) {
-        allCheckboxes.each(function(index) {
-            if (index > 0)
-                $(this).attr('checked',false);
-        });
-    }
-}
-
-function ddclOnComplete(selector)
-{ // Called by ui.dropdownchecklist.js when selections have been made
-  // Also called at init to fill the selector with current choices
-
-    // Warning: In IE this gets called when still selecting!
-
-    var id = $(selector).attr('id');
-
-    // If no  options are selected, may have to force all
-    var chosen = $(selector).find('option:selected');
-    if (chosen.length == 0) {
-        if ($(selector).hasClass('noneIsAll')) {
-            //$(selector).first('option').first().attr('selected',true);
-            selector.options[0].selected = true;
-            // How to check the first item?
-            var dropWrapper = $('#ddcl-' + id + '-ddw');
-            $(dropWrapper).find("input").first().attr("checked",true);
-        }
-    } else if (chosen.length == $(selector).find('option').length) {
-        // If all are chosen then select only the first!
-        $(chosen).each(function(index) {
-            if (index > 0)
-                $(this).attr('selected',false);
-        });
-    }
-
-    var msg = ddclTextOfCurrentSelections(selector.options);
-
-    var control = this.controlWrapper;
-    if (control == null || control == undefined) { // caller is not constant
-        control = $('#ddcl-' + id);
-    }
-    var newColor = '';
-    if ($(selector).find('option:selected').length == 0)
-        newColor = '#AA0000'; // red
-    //else if (msg.search(/color:/i) == -1)
-    //    newColor = 'black';
-    ddclLabelSet(control,msg,newColor,'Click to select...');
-
-    // Notice special handling for a custom event
-    $(selector).trigger('done',selector);
-}
-
-function ddclReinit(filterBys,force)
-{ // ReInitialize the DDCLs (drop-down checkbox-list)
-  // This is done when the track search with tabs gets switched to advanced tab
-  // because the DDCLs were setup on hidden filterBys and dimensiuons are wrong.
-  // if not force, then only reinit when the dimensions are suspect
-
-    if (filterBys.length < 1)
-        return;
-
-    $(filterBys).each( function(i) { // Do this by 'each' to set noneIsAll individually
-        if (!force) { // condition on bad dimensions
-            var id = $(this).attr('id');
-            control = $('#ddcl-' + id);
-            if (control != null && control != undefined) {
-                var controlSelector = $(control).find(".ui-dropdownchecklist-selector");
-                if ($(controlSelector).width() > 20)
-                    return;  // Dimensions look okay
-            }
-        }
-        $(this).dropdownchecklist("destroy");
-        $(this).show(); // necessary to get dimensions
-        if (newJQuery)
-            ddclSetup(this,'noneIsAll');
-        else
-            $(this).dropdownchecklist({ firstItemChecksAll: true, noneIsAll: true, maxDropHeight: filterByMaxHeight(this) });
-    });
-}
-
-function ddclSetup(obj)
-{ // Initialize the multiselect as a DDCL (drop-down checkbox-list)
-
-    // Defaults
-    var myFirstIsAll = true;
-    var myNoneIsAll  = false;
-    var myIcon       = null;
-    var myEmptyText  = 'Select...';
-    var myClose      = 'close&nbsp;&nbsp;';
-    var myDropHeight = filterByMaxHeight(obj);
-    // parse optional args
-    for(var vIx=1;vIx<arguments.length;vIx++) {
-        switch(arguments[vIx]) {
-            case 'noneIsAll':   myNoneIsAll = true;
-                                break;
-            case 'firstNotAll': myFirstIsAll = false;
-                                break;
-            case 'arrows':      myIcon = {};
-                                break;
-            case 'noClose':     myClose = null;
-                                break;
-            case 'label':       vIx++;
-                                if (vIx<arguments.length)
-                                    myEmptyText  = arguments[vIx];
-                                break;
-            default:            warn('ddclSetup() unexpected argument: '+arguments[vIx]);
-                                break;
-        }
-    }
-    if (myFirstIsAll == false)
-        myNoneIsAll  = false;
-
-    // Make sure there is an id!
-    var id = $(obj).attr('id');
-    if (id == null || id.length == 0) {
-        var name = $(obj).attr('name');
-        if (name != null && name.length > 0)
-            id = 'dd-' + name;
-        else {
-            var ix = $('select').index(obj);
-            id = 'ix' + ix;
-        }
-        $(obj).attr('id',id);
-    }
-
-    // These values can only be taken from the select before it becomes a DDCL
-    var maxWidth = $(obj).width();
-    var minWidth = $(obj).css('min-width');
-    if (minWidth != undefined && minWidth.length > 0) {
-        minWidth = parseInt(maxWidth);
-        if (maxWidth < minWidth)
-            maxWidth = minWidth;
-    }
-    maxWidth = (Math.ceil(maxWidth / 10) * 10) + 10; // Makes for more even boxes
-    var style = $(obj).attr('style');
-
-    // The magic starts here:
-    $(obj).dropdownchecklist({
-                        firstItemChecksAll: true,
-                        noneIsAll: myNoneIsAll,
-                        maxDropHeight: myDropHeight,
-                        icon: myIcon,
-                        emptyText: myEmptyText,
-                        explicitClose: myClose,
-                        textFormatFunction: function () { return 'selecting...'; } ,
-                        onComplete: ddclOnComplete
-    });
-    if (myNoneIsAll)
-        $(obj).addClass('noneIsAll'); // Declare this as none selected same as all selected
-    ddclOnComplete(obj); // shows selected items in multiple lines
-
-    // Set up the selector (control seen always and replacing select)
-    control = $('#ddcl-' + id);
-    if (control == null || control == undefined) {
-        warn('ddclSetup('+id+') failed to create drop-down checkbox-list');
-        return;
-    }
-    var controlSelector = $(control).find(".ui-dropdownchecklist-selector");
-    $(controlSelector).click(ddclOnOpen);
-    $(controlSelector).css({width:maxWidth+'px'});
-    var controlText = $(control).find(".ui-dropdownchecklist-text");
-    $(controlText).css({width:maxWidth+'px'});
-
-    // Set up the drop list (control seen only on fucus and with items to choose)
-    var dropWrapper = $('#ddcl-' + id + '-ddw');
-    if (dropWrapper == null || dropWrapper == undefined) {
-        warn('ddclSetup('+id+') failed to create drop-down checkbox-list');
-        return;
-    }
-    // Individual items need styling
-    var itemHeight = 22;
-    // Exclude the close button
-    var dropItems = $(dropWrapper).find(".ui-dropdownchecklist-item");//.not('.ui-dropdownchecklist-close');
-    $(dropItems).hover(function () {$(this).css({backgroundColor:'#CCFFCC'});},
-                       function () {$(this).css({backgroundColor:'white'});});
-    var dropItems = $(dropItems).not('.ui-dropdownchecklist-close');
-    $(dropItems).css({background:'white', borderStyle:'none', height:itemHeight+'px'});
-    var itemCount = dropItems.length;
-    if (myClose != null) {  // target the close button
-        var dropClose = $(dropWrapper).find(".ui-dropdownchecklist-close");
-        $(dropClose).css({height:(itemHeight - 1)+'px',textAlign:'center'});
-        itemCount++;
-    }
-
-    // The whole droplist needs styling
-    var dropContainerDiv = dropWrapper.find(".ui-dropdownchecklist-dropcontainer");
-    var maxHeight = (itemHeight*itemCount) + 1; // extra prevents unwanted vertical scrollbar
-    var divHeight = dropContainerDiv.outerHeight();
-    if (divHeight > maxHeight) {
-        $(dropContainerDiv).css({height:maxHeight+'px'});
-        $(dropWrapper).css({height:maxHeight+'px'});
-    }
-    maxWidth += 30; // extra avoids horizontal scrollBar when vertical one is included
-    $(dropContainerDiv).css({width:(maxWidth)+'px'});
-    $(dropWrapper).css({width:maxWidth+'px'});
-
-    // Finally we can get style from the original select and apply it to the whole control (hopefully)
-    if (style != undefined && style.length > 0) {
-        var styles = style.split(';');
-        for(var ix = 0;ix < styles.length;ix++) {
-            var aStyleDef = styles[ix].split(':');
-             aStyleDef[0] = aStyleDef[0].replace(' ',''); // no spaces
-            if (aStyleDef[0] != 'display') // WARNING: Need to see if other styles should be restricted.
-                $(control).css(aStyleDef[0],aStyleDef[1]);
-            if (aStyleDef[0].substring(0,4) == 'font')  // Fonts should be applied too
-                $(dropItems).css(aStyleDef[0],aStyleDef[1]);
-        }
-    }
-
-    // TODO:
-    // - Chrome multi-select required changing ddcl code as per issue 176.
-    // - package these changes: Could keep this in utils or could make a wrapper like DDCL itself.
-    // - test test test
-    //   Works on FF: track search, hgFileUi, hgTrackUi filterComp and filterBy, popup
-    //   Works on Chrom: track search, hgFileUi, hgTrackUi filterComp and filterBy, popup
-    //   Mostly works on IE: track search, hgFileUi, hgTrackUi filterComp and filterBy, popup
-    //   - IE needed special code to block window.resize event in DDCL.
-    //   - Have seen scripting timeouts on IE but I am not sure this is still an issue.
-    // *** v1.4 has been released which works with jquery 1.6.1 ***
-}