e0c9cb5c5b9536dc3771e3fe09f3afb6ad5ad9ff tdreszer Tue Jul 5 18:32:21 2011 -0700 Major performance improvements for IE javascript. parent() and add() both dragged the JSript engine to it's knees. Debug code is being checked in but not called. diff --git src/hg/js/utils.js src/hg/js/utils.js index a594c63..0882f5a 100644 --- src/hg/js/utils.js +++ src/hg/js/utils.js @@ -538,30 +538,43 @@ if( warnList == undefined || $(warnList).length == 0 ) { warnBoxJsSetup(); warnList = $('#warnList'); } if( $(warnList).length == 0 ) alert(msg); else { $( warnList ).append('
  • '+msg+'
  • '); if(showWarnBox != undefined) showWarnBox(); else alert(msg); } } +var gWarnSinceMSecs = 0; +function warnSince(msg) +{ // Warn messages with msecs since last warnSince msg + // This is necessary because IE Developer tools are hanging + var now = new Date(); + var msecs = now.getTime(); + var since = 0; + if (gWarnSinceMSecs > 0) + since = msecs - gWarnSinceMSecs; + gWarnSinceMSecs = msecs; + warn('['+since+'] '+msg); +} + function cgiBooleanShadowPrefix() // Prefix for shadow variable set with boolean variables. // Exact copy of code in cheapcgi.c { return "boolshad."; } function getAllVars(obj,subtrackName) { // Returns a hash for all inputs and selects in an obj. // If obj is undefined then obj is document! var urlData = new Object(); if($(obj) == undefined) obj = $('document'); var inp = $(obj).find('input'); @@ -915,39 +928,40 @@ { // Clears the waitMask var waitMask = $('#waitMask'); if( waitMask != undefined ) $(waitMask).hide(); } function waitMaskSetup(timeOutInMs) { // Sets up the waitMask to block page manipulation until cleared // Find or create the waitMask (which masks the whole page) var waitMask = $('#waitMask'); if( waitMask == undefined || waitMask.length != 1) { // create the waitMask $("body").append("
    "); waitMask = $('#waitMask'); - // Special for IE + // Special for IE, since it takes so long, make mask obvious if ($.browser.msie) - $(waitMask).css('filter','alpha(opacity= 0)'); + $(waitMask).css({opacity:0.4,backgroundColor:'gray'}); } $(waitMask).css('display','block'); // Things could fail, so always have a timeout. if(timeOutInMs == undefined || timeOutInMs <=0) - timeOutInMs = 5000; // Don't ever leave this as infinite + timeOutInMs = 30000; // IE can take forever! + setTimeout('waitMaskClear();',timeOutInMs); // Just in case } function _launchWaitOnFunction() { // should ONLY be called by waitOnFunction() // Launches the saved function var func = gWaitFunc; gWaitFunc = null; var funcArgs = gWaitFuncArgs; gWaitFuncArgs = []; if(func == undefined || !jQuery.isFunction(func)) warn("_launchWaitOnFunction called without a function"); else { if(funcArgs.length == 0) @@ -993,30 +1007,61 @@ if(arguments[1].type == 'button' && $(arguments[1]).hasClass('inOutButton')) { $(arguments[1]).css( 'borderStyle',"inset"); } } // Build up the aruments array for(var aIx=1;aIx 0) + ro.step(msecs,args); // recursion + else if (msecs == 0) + continuingFunc(args); // completion + // else (msec < 0) // abandon + }); + ro.step(1,args); // kick-off +} + function showLoadingImage(id) { // Show a loading image above the given id; return's id of div added (so it can be removed when loading is finished). // This code was mostly directly copied from hgHeatmap.js, except I also added the "overlay.appendTo("body");" var loadingId = id + "LoadingOverlay"; var overlay = $("
    ").attr("id", loadingId).css("position", "absolute"); overlay.appendTo("body"); overlay.css("top", $('#'+ id).position().top); var divLeft = $('#'+ id).position().left + 2; overlay.css("left",divLeft); var width = $('#'+ id).width() - 5; var height = $('#'+ id).height(); overlay.width(width); overlay.height(height); overlay.css("background", "white"); @@ -2240,120 +2285,285 @@ 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(); } -function filterTablesTrsSurviving(filterClass) -// returns a list of trs that satisfy all filters -// If defined, will exclude filter identified by filterClass -{ - // find all filterable table rows - var showTrs = $('tr.filterable'); // Default all - if (showTrs.length == 0) - return undefined; +function _filterTableByClassesIterative(args) +{ // Applies a single class filter to a filterTable TRs + // Called via yieldingIterator + if (args.curIx >= args.classes.length) + return 0; - // Find all filters - var filters = $("select.filterBy"); - if (filters.length == 0) - return undefined; + 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++; + if (args.curIx >= args.classes.length) + return 0; + return 1; +} - // Exclude one if requested. - if (filterClass != undefined && filterClass.length > 0) - filters = $(filters).not('.' + filterClass); +function _filterTableByClassesComplete(args) +{ // Continues after filterTableByClassesIterative + // Called via yieldingIterator + var filtersStruct = args.filtersStruct; - // For each filter, filter the list of trs that matches that filter - $(filters).each(function (i) { - var val = $(this).val(); - if (val == null || val.length == 0) - return; - val = val.join(); - if(val.indexOf("All") == 0) - return; + //warnSince("Completing classes..."); + if (args.tdsFiltered == null) + filtersStruct.trsRemaining = null; + else { + //filtersStruct.trsRemaining = $(args.tdsFiltered).parent(); // Very slow in IE!!! + var tds = args.tdsFiltered; + var trs = []; + $(tds).each(function (ix) { + trs[ix] = this.parentNode; + }); + filtersStruct.trsRemaining = trs; + } + //warnSince("Mostly complete classes..."); + filtersStruct.curIx++; + yieldingIterator(_filterTableIterative,_filterTableComplete,filtersStruct); + //warnSince("Really complete classes."); +} - // Get the filter variable - var filterVar = filterTableFilterVar(this); - if (filterVar == undefined) - return; +function _filterTableIterative(args) +{ // Applies a single filter to a filterTable TRs + // Called via yieldingIterator - // Get the selected values for this filter - var classes = $(this).val(); - if (classes.length == 0) - return; + //warnSince("Filter "+args.curIx+" iterating..."); + if (args.curIx >= args.filters.length) + return 0; - var varTds = $(showTrs).children('td.' + filterVar); - var filteredTrs = new Array; - var ix =0; - for(;ix 0) { - if (filteredTrs.length == 0) - filteredTrs = $(tds).parent('tr').get(); + 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 = filteredTrs.concat( $(tds).parent('tr').get() ); + 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; } - // The following tighter code may take too long - //var filterVals = 'td.'+filterVar+'.' + classes.join(',td.'+filterVar+'.'); // "td.cell.GM12878,td.cell.K562,td.cell.H1-hESC" - //var filteredTrs = $(showTrs).filter(":has(" + filterVals + ")"); - if (filteredTrs.length > 0) - showTrs = filteredTrs; - }); - return showTrs; +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'); + + if (args.trsRemaining != null) { + //$(args.trsRemaining).show(); + $(args.trsRemaining).css('display', ''); + + // Update count + var counter = $('.filesCount'); + if(counter != undefined) + $(counter).text($(args.trsRemaining).length + " / "); + } else { + var counter = $('.filesCount'); + if(counter != undefined) + $(counter).text(0 + " / "); } -function _filterTable() + 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(); - if (showTrs == undefined) - return; //$('tr.filterable').hide(); // <========= This is what is taking so long! $('tr.filterable').css('display', 'none') - $(showTrs).show(); + 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() +{ // 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; + + var varTds = $(remainingTrs).children('td.' + filterVar); + var filteredTrs = null; + var ix =0; + for(;ix 0) { + var trs = []; + $(tds).each(function (ix) { + trs[ix] = this.parentNode; + }); + + if (filteredTrs == null) + filteredTrs = trs; + else + filteredTrs = jQuery.merge( filteredTrs, trs ); // This one takes too long in IE! + } + } + return filteredTrs; +} + +function filterTablesTrsSurviving(filterClass) +// returns a list of trs that satisfy all filters +// If defined, will exclude filter identified by filterClass +{ + // find all filterable table rows + var showTrs = $('tr.filterable'); // Default all + if (showTrs.length == 0) + return undefined; + + // 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 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('_filterTable();',10); // Just in case + setTimeout('_filterTableOld();',2); // Just in case +} + +function filterTableDone(event) +{ // Called by custom 'done' event + event.stopImmediatePropagation(); + $(this).unbind( event ); + waitOnFunction(filterTableTrigger); } -function filterTable() +function filterTable(selector) { // 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); + return; + //} + } else waitOnFunction(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); @@ -2526,30 +2736,33 @@ }); } 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);