1 // MISC 2 3 /** 4 * @namespace 5 */ 6 7 var Util = {}; 8 9 Util.is_ie = navigator.appVersion.indexOf('MSIE') >= 0; 10 Util.is_ie6 = navigator.appVersion.indexOf('MSIE 6') >= 0; 11 Util.addCommas = function(nStr) 12 { 13 nStr += ''; 14 var x = nStr.split('.'); 15 var x1 = x[0]; 16 var x2 = x.length > 1 ? '.' + x[1] : ''; 17 var rgx = /(\d+)(\d{3})/; 18 while (rgx.test(x1)) { 19 x1 = x1.replace(rgx, '$1' + ',' + '$2'); 20 } 21 return x1 + x2; 22 }; 23 24 Util.wheel = function(event){ 25 var delta = 0; 26 if (!event) event = window.event; 27 if (event.wheelDelta) { 28 delta = event.wheelDelta/120; 29 if (window.opera) delta = -delta; 30 } else if (event.detail) { delta = -event.detail/3; } 31 return Math.round(delta); //Safari Round 32 }; 33 34 Util.isRightButton = function(e) { 35 if (!e) var e = window.event; 36 if (e.which) return e.which == 3; 37 else if (e.button) return e.button == 2; 38 }; 39 40 Util.getViewportWidth = function() { 41 var width = 0; 42 if( document.documentElement && document.documentElement.clientWidth ) { 43 width = document.documentElement.clientWidth; 44 } 45 else if( document.body && document.body.clientWidth ) { 46 width = document.body.clientWidth; 47 } 48 else if( window.innerWidth ) { 49 width = window.innerWidth - 18; 50 } 51 return width; 52 }; 53 54 Util.getViewportHeight = function() { 55 var height = 0; 56 if( document.documentElement && document.documentElement.clientHeight ) { 57 height = document.documentElement.clientHeight; 58 } 59 else if( document.body && document.body.clientHeight ) { 60 height = document.body.clientHeight; 61 } 62 else if( window.innerHeight ) { 63 height = window.innerHeight - 18; 64 } 65 return height; 66 }; 67 68 Util.findNearest = function(numArray, num) { 69 var minIndex = 0; 70 var min = Math.abs(num - numArray[0]); 71 for (var i = 0; i < numArray.length; i++) { 72 if (Math.abs(num - numArray[i]) < min) { 73 minIndex = i; 74 min = Math.abs(num - numArray[i]); 75 } 76 } 77 return minIndex; 78 }; 79 80 /** 81 * replace variables in a template string with values 82 * @param template String with variable names in curly brackets 83 * e.g., "http://foo/{bar}?arg={baz} 84 * @param fillWith object with attribute-value mappings 85 * e.g., {'bar': 'someurl', 'baz': 'valueforbaz'} 86 * @returns the template string with variables in fillWith replaced 87 * e.g., 'htp://foo/someurl?arg=valueforbaz' 88 */ 89 Util.fillTemplate = function(template, fillWith) { 90 return template.replace(/\{([^}]+)\}/g, 91 function(match, group) { 92 if (fillWith[group] !== undefined) 93 return fillWith[group]; 94 else 95 return "{" + group + "}"; 96 }); 97 }; 98 99 /** 100 * function to load a specified resource only once 101 * @param {Object} dojoXhrArgs object containing arguments for dojo.xhrGet, 102 * like <code>url</code> and <code>handleAs</code> 103 * @param {Object} stateObj object that stores the state of the load 104 * @param {Function} successCallback function to call on a successful load 105 * @param {Function} errorCallback function to call on an unsuccessful load 106 */ 107 Util.maybeLoad = function ( dojoXhrArgs, stateObj, successCallback, errorCallback) { 108 if (stateObj.state) { 109 if ("loaded" == stateObj.state) { 110 successCallback(stateObj.data); 111 } else if ("error" == stateObj.state) { 112 errorCallback(); 113 } else if ("loading" == stateObj.state) { 114 stateObj.successCallbacks.push(successCallback); 115 if (errorCallback) stateObj.errorCallbacks.push(errorCallback); 116 } 117 } else { 118 stateObj.state = "loading"; 119 stateObj.successCallbacks = [successCallback]; 120 stateObj.errorCallbacks = [errorCallback]; 121 122 var args = dojo.clone( dojoXhrArgs ); 123 args.load = function(o) { 124 stateObj.state = "loaded"; 125 stateObj.data = o; 126 var cbs = stateObj.successCallbacks; 127 for (var c = 0; c < cbs.length; c++) cbs[c](o); 128 }; 129 args.error = function(error) { 130 console.error(''+error); 131 stateObj.state = "error"; 132 var cbs = stateObj.errorCallbacks; 133 for (var c = 0; c < cbs.length; c++) cbs[c](); 134 }; 135 136 dojo.xhrGet( args ); 137 } 138 }; 139 140 /** 141 * updates a with values from b, recursively 142 */ 143 Util.deepUpdate = function(a, b) { 144 for (var prop in b) { 145 if ((prop in a) 146 && ("object" == typeof b[prop]) 147 && ("object" == typeof a[prop]) ) { 148 Util.deepUpdate(a[prop], b[prop]); 149 } else if( typeof a[prop] == 'undefined' || typeof b[prop] != undefined ){ 150 a[prop] = b[prop]; 151 } 152 } 153 return a; 154 }; 155 156 // from http://bugs.dojotoolkit.org/ticket/5794 157 Util.resolveUrl = function(baseUrl, relativeUrl) { 158 // summary: 159 // This takes a base url and a relative url and resolves the target url. 160 // For example: 161 // resolveUrl("http://www.domain.com/path1/path2","../path3") ->"http://www.domain.com/path1/path3" 162 // 163 if (relativeUrl.match(/\w+:\/\//)) 164 return relativeUrl; 165 if (relativeUrl.charAt(0)=='/') { 166 baseUrl = baseUrl.match(/.*\/\/[^\/]*/); 167 return (baseUrl ? baseUrl[0] : '') + relativeUrl; 168 } 169 //TODO: handle protocol relative urls: ://www.domain.com 170 baseUrl = baseUrl.substring(0,baseUrl.length - baseUrl.match(/[^\/]*$/)[0].length);// clean off the trailing path 171 if (relativeUrl == '.') 172 return baseUrl; 173 while (relativeUrl.substring(0,3) == '../') { 174 baseUrl = baseUrl.substring(0,baseUrl.length - baseUrl.match(/[^\/]*\/$/)[0].length); 175 relativeUrl = relativeUrl.substring(3); 176 } 177 return baseUrl + relativeUrl; 178 }; 179 180 Util.parseLocString = function( locstring ) { 181 locstring = dojo.trim( locstring ); 182 183 // (chromosome) ( start ) ( sep ) ( end ) 184 var matches = locstring.match(/^(((\S*)\s*:)?\s*(-?[\d,.']+)\s*(\.\.|-|\s+))?\s*(-?[\d,.']+)$/i); 185 //matches potentially contains location components: 186 //matches[3] = chromosome (optional) 187 //matches[4] = start base (optional) 188 //matches[6] = end base (or center base, if it's the only one) 189 190 if( !matches ) 191 return null; 192 193 // parses a number from a locstring that's a coordinate, and 194 // converts it from 1-based to interbase coordinates 195 var parseCoord = function( coord ) { 196 coord = (coord+'').replace(/\D/g,''); 197 var num = parseInt( coord, 10 ); 198 return typeof num == 'number' && !isNaN(num) ? num : null; 199 }; 200 201 return { 202 start: parseCoord( matches[4] )-1, 203 end: parseCoord( matches[6] ), 204 ref: matches[3] 205 }; 206 }; 207 208 Util.assembleLocString = function( loc_in ) { 209 var s = '', 210 types = { start: 'number', end: 'number', ref: 'string' }, 211 location = {} 212 ; 213 214 // filter the incoming loc_in to only pay attention to slots that we 215 // know how to handle 216 for( var slot in types ) { 217 if( types[slot] == typeof loc_in[slot] 218 && (types[slot] != 'number' || !isNaN(loc_in[slot])) //filter any NaNs 219 ) { 220 location[slot] = loc_in[slot]; 221 } 222 } 223 224 //finally assemble our string 225 if( 'ref' in location ) { 226 s += location.ref; 227 if( location.start || location.end ) 228 s += ':'; 229 } 230 if( 'start' in location ) { 231 s += (Math.round(location.start)+1).toFixed(0).toLocaleString(); 232 if( 'end' in location ) 233 s+= '..'; 234 } 235 if( 'end' in location ) 236 s += Math.round(location.end).toFixed(0).toLocaleString(); 237 238 return s; 239 }; 240 241 // given a possible reference sequence name and an object as { 'foo': 242 // <refseq foo>, ... }, try to match that reference sequence name 243 // against the actual name of one of the reference sequences. returns 244 // the reference sequence record, or null 245 // if none matched. 246 Util.matchRefSeqName = function( name, refseqs ) { 247 for( var ref in refseqs ) { 248 if( ! refseqs.hasOwnProperty(ref) ) 249 continue; 250 251 var ucname = name.toUpperCase(); 252 var ucref = ref.toUpperCase(); 253 254 if( ucname == ucref 255 || "CHR" + ucname == ucref 256 || ucname == "CHR" + ucref 257 ) { 258 return refseqs[ref]; 259 } 260 } 261 return null; 262 }; 263 264 /** 265 * Wrap a handler function to be called 1ms later in a window timeout. 266 * This will usually give a better stack trace for figuring out where 267 * errors are happening. 268 */ 269 Util.debugHandler = function( context, func ) { 270 var debuggedHandler = function() { 271 var args = arguments; 272 window.setTimeout( function() { func.apply(context,args);}, 1); 273 }; 274 return debuggedHandler; 275 }; 276 277 if (!Array.prototype.reduce) 278 { 279 Array.prototype.reduce = function(fun /*, initial*/) 280 { 281 var len = this.length; 282 if (typeof fun != "function") 283 throw new TypeError(); 284 285 // no value to return if no initial value and an empty array 286 if (len == 0 && arguments.length == 1) 287 throw new TypeError(); 288 289 var i = 0; 290 if (arguments.length >= 2) 291 { 292 var rv = arguments[1]; 293 } 294 else 295 { 296 do 297 { 298 if (i in this) 299 { 300 rv = this[i++]; 301 break; 302 } 303 304 // if array contains no values, no initial value to return 305 if (++i >= len) 306 throw new TypeError(); 307 } 308 while (true); 309 } 310 311 for (; i < len; i++) 312 { 313 if (i in this) 314 rv = fun.call(null, rv, this[i], i, this); 315 } 316 317 return rv; 318 }; 319 } 320 321 if (!Array.prototype.map) 322 { 323 Array.prototype.map = function(fun /*, thisp */) 324 { 325 "use strict"; 326 327 if (this === void 0 || this === null) 328 throw new TypeError(); 329 330 var t = Object(this); 331 var len = t.length >>> 0; 332 if (typeof fun !== "function") 333 throw new TypeError(); 334 335 var res = new Array(len); 336 var thisp = arguments[1]; 337 for (var i = 0; i < len; i++) 338 { 339 if (i in t) 340 res[i] = fun.call(thisp, t[i], i, t); 341 } 342 343 return res; 344 }; 345 } 346 347 if (!Array.prototype.indexOf) 348 { 349 Array.prototype.indexOf = function(searchElement /*, fromIndex */) 350 { 351 "use strict"; 352 353 if (this === void 0 || this === null) 354 throw new TypeError(); 355 356 var t = Object(this); 357 var len = t.length >>> 0; 358 if (len === 0) 359 return -1; 360 361 var n = 0; 362 if (arguments.length > 0) 363 { 364 n = Number(arguments[1]); 365 if (n !== n) // shortcut for verifying if it's NaN 366 n = 0; 367 else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) 368 n = (n > 0 || -1) * Math.floor(Math.abs(n)); 369 } 370 371 if (n >= len) 372 return -1; 373 374 var k = n >= 0 375 ? n 376 : Math.max(len - Math.abs(n), 0); 377 378 for (; k < len; k++) 379 { 380 if (k in t && t[k] === searchElement) 381 return k; 382 } 383 return -1; 384 }; 385 } 386 387 /** 388 * @class 389 */ 390 function Finisher(fun) { 391 this.fun = fun; 392 this.count = 0; 393 } 394 395 Finisher.prototype.inc = function() { 396 this.count++; 397 }; 398 399 Finisher.prototype.dec = function() { 400 this.count--; 401 this.finish(); 402 }; 403 404 Finisher.prototype.finish = function() { 405 if (this.count <= 0) this.fun(); 406 }; 407 408 409 /* 410 411 Copyright (c) 2007-2010 The Evolutionary Software Foundation 412 413 Created by Mitchell Skinner <mitch_skinner@berkeley.edu> 414 415 This package and its accompanying libraries are free software; you can 416 redistribute it and/or modify it under the terms of the LGPL (either 417 version 2.1, or at your option, any later version) or the Artistic 418 License 2.0. Refer to LICENSE for the full license text. 419 420 */ 421