dc954816332fdd522f6999b04cb7409a2a9f8239 tdreszer Wed Jun 4 17:42:48 2014 -0700 Tightened the screws on several descrete cases where comparison to undefined might have been acting on undeclared variable. I have looked through all the js files I altered for jshint and only found these few cases which might (but in practice probably don't) trigger exceptions. diff --git src/hg/js/utils.js src/hg/js/utils.js index 36cbe07..6814a83 100644 --- src/hg/js/utils.js +++ src/hg/js/utils.js @@ -146,42 +146,42 @@ strReturn = aParam[1]; break; } } } return unescape(strReturn); } function makeHiddenInput(theForm,aName,aValue) { // Create a hidden input to hold a value $(theForm).find("input:last").after(""); } function updateOrMakeNamedVariable(theForm,aName,aValue) { // Store a value to a named input. Will make the input if necessary - var inp = $(theForm).find("input[name='"+aName+"']:last"); - if (inp && inp.length > 0) { + var inp = normed($(theForm).find("input[name='"+aName+"']:last")); + if (inp) { inp.val(aValue); inp.disabled = false; } else makeHiddenInput(theForm,aName,aValue); } function disableNamedVariable(theForm,aName) { // Store a value to a named input. Will make the input if necessary - var inp = $(theForm).find("input[name='"+aName+"']:last"); - if (inp && inp.length > 0) + var inp = normed($(theForm).find("input[name='"+aName+"']:last")); + if (inp) inp.disabled = true; } function parseUrlAndUpdateVars(theForm,href) // DEAD CODE? { // Parses the URL and converts GET vals to POST vals var url = href; var extraIx = url.indexOf("?"); if (extraIx > 0) { var extra = url.substring(extraIx+1); url = url.substring(0,extraIx); // now extra must be repeatedly broken into name=var extraIx = extra.indexOf("="); for (; extraIx > 0;extraIx = extra.indexOf("=")) { var aValue; var aName = extra.substring(0,extraIx); @@ -291,31 +291,31 @@ } function isFloat(s) { return (!isNaN(parseFloat(s)) && isFinite(s)); } function validateInt(obj,min,max) { // validates an integer which may be restricted to a range (if min and/or max are numbers) var title = obj.title; var rangeMin=parseInt(min); var rangeMax=parseInt(max); if (title.length === 0) title = "Value"; var popup=( $.browser.msie === false ); for (;;) { - if ((!obj.value || obj.value === "") + if ((typeof(obj.value) === 'undefined' || obj.value === "") && isInteger(obj.defaultValue)) obj.value = obj.defaultValue; if (!isInteger(obj.value)) { if (popup) { obj.value = prompt(title +" is invalid.\nMust be an integer.",obj.value); continue; } else { alert(title +" of '"+obj.value +"' is invalid.\nMust be an integer."); obj.value = obj.defaultValue; return false; } } var val = parseInt(obj.value); if (isInteger(min) && isInteger(max)) { if (val < rangeMin || val > rangeMax) { @@ -358,31 +358,31 @@ } } return true; } } function validateFloat(obj,min,max) { // validates an float which may be restricted to a range (if min and/or max are numbers) var title = obj.title; var rangeMin=parseFloat(min); var rangeMax=parseFloat(max); if (title.length === 0) title = "Value"; var popup=( $.browser.msie === false ); for (;;) { - if ((!obj.value || obj.value === "") + if ((typeof(obj.value) === 'undefined' || obj.value === "") && isFloat(obj.defaultValue)) obj.value = obj.defaultValue; if (!isFloat(obj.value)) { if (popup) { obj.value = prompt(title +" is invalid.\nMust be a number.",obj.value); continue; } else { alert(title +" of '"+obj.value +"' is invalid.\nMust be a number."); // try a prompt box! obj.value = obj.defaultValue; return false; } } var val = parseFloat(obj.value); if (isFloat(min) && isFloat(max)) { if (val < rangeMin || val > rangeMax) { @@ -431,46 +431,45 @@ function validateUrl(url) { // returns true if url is a valid url, otherwise returns false and shows an alert // I got this regexp from http://stackoverflow.com/questions/1303872/url-validation-using-javascript var regexp = /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i; if (regexp.test(url)) { return true; } else { alert(url + " is an invalid url"); return false; } } function metadataIsVisible(trackName) { - var divit = $("#div_"+trackName+"_meta"); - if (!divit || divit.length === 0) + var divit = normed($("#div_"+trackName+"_meta")); + if (!divit) return false; return ($(divit).css('display') !== 'none'); } function metadataShowHide(trackName,showLonglabel,showShortLabel) { // Will show subtrack specific configuration controls // Config controls not matching name will be hidden - var divit = $("#div_"+trackName+"_meta"); - if (!divit || divit.length === 0) + var divit = normed($("#div_"+trackName+"_meta")); + if (!divit) return false; - var img = $(divit).prev('a').find("img"); - if (img && $(img).length === 1) { - img = $(img)[0]; + var img = normed($(divit).prev('a').find("img")); + if (img) { if ($(divit).css('display') === 'none') $(img).attr('src','../images/upBlue.png'); else $(img).attr('src','../images/downBlue.png'); } if ($(divit).css('display') === 'none') { if (typeof(subCfg) === "object") {// subCfg.js file included? var cfg = normed($("#div_cfg_"+trackName)); if (cfg) // Hide any configuration when opening metadata $(cfg).hide(); } if ($(divit).find('table').length === 0) { lookupMetadata(trackName,showLonglabel,showShortLabel); return false; @@ -488,32 +487,32 @@ if (bgClass) { $(divit).children('table').removeClass('bgLevel1 bgLevel2 bgLevel3 bgLevel4'); $(divit).children('table').addClass(bgClass); } } $(divit).toggle(); // jQuery hide/show return false; } function setTableRowVisibility(button, prefix, hiddenPrefix, titleDesc, doAjax) { // Show or hide one or more table rows whose id's begin with prefix followed by "-". // This code also modifies the corresponding hidden field (cart variable) and the // src of the +/- img button. var retval = true; - var hidden = $("input[name='"+hiddenPrefix+"_"+prefix+"_close']"); - if (button && hidden && $(hidden).length > 0) { + var hidden = normed($("input[name='"+hiddenPrefix+"_"+prefix+"_close']")); + if (button && hidden) { var newVal = -1; if (arguments.length > 5) newVal = arguments[5] ? 0 : 1; var oldSrc = $(button).attr("src"); if (oldSrc && oldSrc.length > 0) { // Old img version of the toggleButton if (newVal === -1) newVal = oldSrc.indexOf("/remove") > 0 ? 1 : 0; if (newVal === 1) $(button).attr("src", oldSrc.replace("/remove", "/add") ); else $(button).attr("src", oldSrc.replace("/add", "/remove") ); } else { // new BUTTONS_BY_CSS if (newVal === -1) { @@ -565,36 +564,36 @@ html += "window.scrollTo(0, 0);"; html += "}"; html += "function hideWarnBox() {"; html += "var warnBox=document.getElementById('warnBox');"; html += "warnBox.style.display='none';warnBox.innerHTML='';"; html += "var endOfPage = document.body.innerHTML.substr(document.body.innerHTML.length-20);"; html += "if(endOfPage.lastIndexOf('-- ERROR --') > 0) { history.back(); }"; html += "}"; html += ""; $('body').prepend(html); } function warn(msg) { // adds warnings to the warnBox - var warnList = $('#warnList'); // warnBox contains warnList - if (!warnList || $(warnList).length === 0) { + var warnList = normed($('#warnList')); // warnBox contains warnList + if (!warnList) { warnBoxJsSetup(); - warnList = $('#warnList'); + warnList = normed($('#warnList')); } - if ($(warnList).length === 0) + if (!warnList) alert(msg); else { $( warnList ).append('
  • '+msg+'
  • '); if ($.isFunction(showWarnBox)) showWarnBox(); else alert(msg); } } var gWarnSinceMSecs = 0; function warnSince(msg) // DEAD CODE? { // Warn messages with msecs since last warnSince msg // This is necessary because IE Developer tools are hanging var now = new Date(); @@ -1018,35 +1017,35 @@ // This code is intended to allow setting up a wait cursor while waiting on the function var gWaitFuncArgs = []; var gWaitFunc; function waitMaskClear() { // Clears the waitMask var waitMask = normed($('#waitMask')); if (waitMask) $(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 || waitMask.length !== 1) { + var waitMask = normed($('#waitMask')); + if (!waitMask) { // create the waitMask $("body").append("
    "); - waitMask = $('#waitMask'); + waitMask = normed($('#waitMask')); } $(waitMask).css({opacity:0.0,display:'block',top: '0px', height: $(document).height().toString() + 'px' }); // Special for IE, since it takes so long, make mask obvious //if ($.browser.msie) // $(waitMask).css({opacity:0.4,backgroundColor:'gray'}); // Things could fail, so always have a timeout. if (!timeOutInMs) // works for undefined, null and 0 timeOutInMs = 30000; // IE can take forever! if (timeOutInMs > 0) setTimeout(waitMaskClear,timeOutInMs); // Just in case return waitMask; // The caller could add css if they wanted. @@ -1054,57 +1053,57 @@ function _launchWaitOnFunction() { // should ONLY be called by waitOnFunction() // Launches the saved function var func = gWaitFunc; gWaitFunc = null; var funcArgs = gWaitFuncArgs; gWaitFuncArgs = []; if (!func || !jQuery.isFunction(func)) warn("_launchWaitOnFunction called without a function"); else func.apply(this, funcArgs); // Special if the first var is a button that can visually be inset - if (funcArgs.length > 0 && funcArgs[0].type) { + if (funcArgs.length > 0 && typeof(funcArgs[0].type) !== 'undefined') { if (funcArgs[0].type === 'button' && $(funcArgs[0]).hasClass('inOutButton')) { $(funcArgs[0]).css('borderStyle',"outset"); } } // 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 (gWaitFunc) { if (gWaitFunc === func) // already called (sometimes hapens when onchange event is triggered return true; // by js (rather than direct user action). Happens in IE8 warn("waitOnFunction called but already waiting on a function"); return false; } waitMaskSetup(0); // Find or create waitMask (which masks 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) { + if (arguments.length > 1 && typeof(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,10); } @@ -1769,31 +1768,31 @@ while (classList.length > 0) { var aClass = classList.pop(); if (aClass.indexOf("sort") === 0) { if (aClass === "sortRev") reverse = true; else { aClass = aClass.substring(4); // clip off the "sort" portion var ix = parseInt(aClass); if (!isNaN(ix)) { sortIx = ix; } } } } if (sortIx >= 0) { - if (this.id && this.id.length > 0) + if (typeof(this.id) !== 'undefined' && this.id.length > 0) fields[sortIx] = this.id + "=" + (reverse ? "-":"+"); else fields[sortIx] = this.cellIndex + "=" + (reverse ? "-":"+"); } }); if (fields.length > 0) { if (!fields[0]) fields.shift(); // 1 based sort ix and 0 based fields ix return fields.join(' '); } } return ""; }, columnsFromSortOrder: function (sortOrder) @@ -2050,31 +2049,31 @@ if (!sortColumns || sortColumns.cellIxs.length === 0) { // could mark all columns as sortable! $(tr).find('th').each(function (ix) { $(this).addClass('sortable'); $(this).addClass('sort'+(ix+1)); //warn("Added class='sortable sort"+(ix+1)+"' to th:"+this.innerHTML); }); sortColumns = new sortTable.columnsFromTr(tr,"silent"); if (!sortColumns || sortColumns.cellIxs.length === 0) { warn("sortable table's header row contains no sort columns."); return; } } // Can wrap all columnn headers with link $(tr).find("th.sortable").each(function (ix) { - if ( ! $(this).attr('onclick') ) { + if ( typeof($(this).attr('onclick')) === 'undefined') { $(this).click( function () { sortTable.sortOnButtonPress(this);} ); } if ($.browser.msie) { // Special case for IE since CSS :hover doesn't work $(this).hover( function () { $(this).css( { backgroundColor: '#CCFFCC', cursor: 'hand' } ); }, function () { $(this).css( { backgroundColor: '#FCECC0', cursor: '' } ); } ); } if ( $(this).attr('title').length === 0) { var title = $(this).text().replace(/[^a-z0-9 ]/ig,''); if (title.length > 0 && $(this).find('sup')) title = title.replace(/[0-9]$/g,''); if (title.length > 0) $(this).attr('title',"Sort list on '" + title + "'." ); else @@ -2277,34 +2276,34 @@ } $(hiddenVis).attr('disabled',false); $('input.viewBtn').val('View in Browser'); }, clickedOne: function (selCb,justClicked) { // called by on click of CB and findTracks.checkAll() var selName = $(selCb).attr('id'); var trackName = selName.substring(0,selName.length - "_sel_id".length); var hiddenSel = $("input[name='"+trackName+"_sel']"); var seenVis = $('select#' + trackName + "_id"); var hiddenVis = $("input[name='"+trackName+"']"); var tr = $(selCb).parents('tr.found'); var tdb = tdbGetJsonRecord(trackName); - var needSel = (tdb.parentTrack !== undefined && tdb.parentTrack !== null); + var needSel = (typeof(tdb.parentTrack) === 'string' && tdb.parentTrack !== ''); var shouldPack = tdb.canPack && tdb.kindOfParent === 0; // If parent then not pack but full if (shouldPack - && tdb.shouldPack !== undefined && tdb.shouldPack !== null && !tdb.shouldPack) + && typeof(tdb.shouldPack) !== 'undefined' && tdb.shouldPack !== null && !tdb.shouldPack) shouldPack = false; var checked = $(selCb).attr('checked'); // First deal with seenVis control if (checked) { $(seenVis).attr('disabled', false); if ($(seenVis).attr('selectedIndex') === 0) { if (shouldPack) $(seenVis).attr('selectedIndex',3); // packed else $(seenVis).attr('selectedIndex',$(seenVis).attr('length') - 1); } } else { $(seenVis).attr('selectedIndex',0); // hide $(seenVis).attr('disabled', true );