1 var Xmpp4Js = {}; 2 3 4 5 Xmpp4Js.logLevel = Log4js.Level.ALL; 6 Xmpp4Js.appender = new Log4js.ConsoleAppender(); 7 Xmpp4Js.loggers = []; 8 9 Xmpp4Js.createLogger = function(logId) { 10 var logger = Log4js.getLogger( logId ); 11 logger.setLevel( Xmpp4Js.logLevel ); 12 logger.addAppender( Xmpp4Js.appender ); 13 14 Xmpp4Js.loggers.push( logger ); 15 16 return logger; 17 } 18 //javascript:Xmpp4Js.setLogLevel( Log4js.Level.OFF ); 19 Xmpp4Js.setLogLevel = function(level) { 20 Xmpp4Js.logLevel = level; 21 22 for(var i = 0; i < Xmpp4Js.loggers.length; i++ ) { 23 Xmpp4Js.loggers[i].setLevel( level ); 24 } 25 } 26 27 28 /** 29 * Do not fork for a browser if it can be avoided. Use feature detection when 30 * you can. Use the user agent as a last resort. YAHOO.env.ua stores a version 31 * number for the browser engine, 0 otherwise. This value may or may not map 32 * to the version number of the browser using the engine. The value is 33 * presented as a float so that it can easily be used for boolean evaluation 34 * as well as for looking for a particular range of versions. Because of this, 35 * some of the granularity of the version info may be lost (e.g., Gecko 1.8.0.9 36 * reports 1.8). 37 * @class YAHOO.env.ua 38 * @static 39 */ 40 Xmpp4Js.UA = function() { 41 var o={ 42 43 /** 44 * Internet Explorer version number or 0. Example: 6 45 * @property ie 46 * @type float 47 */ 48 ie:0, 49 50 /** 51 * Opera version number or 0. Example: 9.2 52 * @property opera 53 * @type float 54 */ 55 opera:0, 56 57 /** 58 * Gecko engine revision number. Will evaluate to 1 if Gecko 59 * is detected but the revision could not be found. Other browsers 60 * will be 0. Example: 1.8 61 * <pre> 62 * Firefox 1.0.0.4: 1.7.8 <-- Reports 1.7 63 * Firefox 1.5.0.9: 1.8.0.9 <-- Reports 1.8 64 * Firefox 2.0.0.3: 1.8.1.3 <-- Reports 1.8 65 * Firefox 3 alpha: 1.9a4 <-- Reports 1.9 66 * </pre> 67 * @property gecko 68 * @type float 69 */ 70 gecko:0, 71 72 /** 73 * AppleWebKit version. KHTML browsers that are not WebKit browsers 74 * will evaluate to 1, other browsers 0. Example: 418.9.1 75 * <pre> 76 * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the 77 * latest available for Mac OSX 10.3. 78 * Safari 2.0.2: 416 <-- hasOwnProperty introduced 79 * Safari 2.0.4: 418 <-- preventDefault fixed 80 * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run 81 * different versions of webkit 82 * Safari 2.0.4 (419.3): 419 <-- Tiger installations that have been 83 * updated, but not updated 84 * to the latest patch. 85 * Webkit 212 nightly: 522+ <-- Safari 3.0 precursor (with native SVG 86 * and many major issues fixed). 87 * 3.x yahoo.com, flickr:422 <-- Safari 3.x hacks the user agent 88 * string when hitting yahoo.com and 89 * flickr.com. 90 * Safari 3.0.4 (523.12):523.12 <-- First Tiger release - automatic update 91 * from 2.x via the 10.4.11 OS patch 92 * Webkit nightly 1/2008:525+ <-- Supports DOMContentLoaded event. 93 * yahoo.com user agent hack removed. 94 * 95 * </pre> 96 * http://developer.apple.com/internet/safari/uamatrix.html 97 * @property webkit 98 * @type float 99 */ 100 webkit: 0, 101 102 /** 103 * The mobile property will be set to a string containing any relevant 104 * user agent information when a modern mobile browser is detected. 105 * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series 106 * devices with the WebKit-based browser, and Opera Mini. 107 * @property mobile 108 * @type string 109 */ 110 mobile: null, 111 112 /** 113 * Adobe AIR version number or 0. Only populated if webkit is detected. 114 * Example: 1.0 115 * @property air 116 * @type float 117 */ 118 air: 0 119 120 }; 121 122 var ua=navigator.userAgent, m; 123 124 // Modern KHTML browsers should qualify as Safari X-Grade 125 if ((/KHTML/).test(ua)) { 126 o.webkit=1; 127 } 128 // Modern WebKit browsers are at least X-Grade 129 m=ua.match(/AppleWebKit\/([^\s]*)/); 130 if (m&&m[1]) { 131 o.webkit=parseFloat(m[1]); 132 133 // Mobile browser check 134 if (/ Mobile\//.test(ua)) { 135 o.mobile = "Apple"; // iPhone or iPod Touch 136 } else { 137 m=ua.match(/NokiaN[^\/]*/); 138 if (m) { 139 o.mobile = m[0]; // Nokia N-series, ex: NokiaN95 140 } 141 } 142 143 m=ua.match(/AdobeAIR\/([^\s]*)/); 144 if (m) { 145 o.air = m[0]; // Adobe AIR 1.0 or better 146 } 147 148 } 149 150 if (!o.webkit) { // not webkit 151 // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr) 152 m=ua.match(/Opera[\s\/]([^\s]*)/); 153 if (m&&m[1]) { 154 o.opera=parseFloat(m[1]); 155 m=ua.match(/Opera Mini[^;]*/); 156 if (m) { 157 o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316 158 } 159 } else { // not opera or webkit 160 m=ua.match(/MSIE\s([^;]*)/); 161 if (m&&m[1]) { 162 o.ie=parseFloat(m[1]); 163 } else { // not opera, webkit, or ie 164 m=ua.match(/Gecko\/([^\s]*)/); 165 if (m) { 166 o.gecko=1; // Gecko detected, look for revision 167 m=ua.match(/rv:([^\s\)]*)/); 168 if (m&&m[1]) { 169 o.gecko=parseFloat(m[1]); 170 } 171 } 172 } 173 } 174 } 175 176 return o; 177 }(); 178 179 Xmpp4Js.Lang = { 180 logger: Xmpp4Js.createLogger("xmpp4js.lang"), 181 182 /** 183 * Determines whether or not the property was added 184 * to the object instance. Returns false if the property is not present 185 * in the object, or was inherited from the prototype. 186 * This abstraction is provided to enable hasOwnProperty for Safari 1.3.x. 187 * There is a discrepancy between YAHOO.lang.hasOwnProperty and 188 * Object.prototype.hasOwnProperty when the property is a primitive added to 189 * both the instance AND prototype with the same value: 190 * <pre> 191 * var A = function() {}; 192 * A.prototype.foo = 'foo'; 193 * var a = new A(); 194 * a.foo = 'foo'; 195 * alert(a.hasOwnProperty('foo')); // true 196 * alert(YAHOO.lang.hasOwnProperty(a, 'foo')); // false when using fallback 197 * </pre> 198 * @method hasOwnProperty 199 * @param {any} o The object being testing 200 * @param prop {string} the name of the property to test 201 * @return {boolean} the result 202 */ 203 hasOwnProperty : (Object.prototype.hasOwnProperty) ? 204 function(o, prop) { 205 return o && o.hasOwnProperty(prop); 206 } : function(o, prop) { 207 return !Xmpp4Js.Lang.isUndefined(o[prop]) && 208 o.constructor.prototype[prop] !== o[prop]; 209 }, 210 211 namespace: function(namespace, root) { 212 if( !root ) { root = window; } 213 var splitNS = namespace.split(/\./); 214 215 var ctx = root; 216 for( var i = 0; i < splitNS.length; i++ ) { 217 var nsPiece = splitNS[i]; 218 219 if( ctx[nsPiece] === undefined ) { 220 ctx[nsPiece] = {}; 221 } 222 223 ctx = ctx[nsPiece]; 224 } 225 226 return ctx; 227 }, 228 229 /** 230 * IE will not enumerate native functions in a derived object even if the 231 * function was overridden. This is a workaround for specific functions 232 * we care about on the Object prototype. 233 * @property _IEEnumFix 234 * @param {Function} r the object to receive the augmentation 235 * @param {Function} s the object that supplies the properties to augment 236 * @static 237 * @private 238 */ 239 _IEEnumFix: (Xmpp4Js.UA.ie) ? function(r, s) { 240 241 // ADD = ["toString", "valueOf", "hasOwnProperty"], 242 var ADD = ["toString", "valueOf"]; 243 244 for (var i=0;i<ADD.length;i=i+1) { 245 var fname=ADD[i],f=s[fname]; 246 if (Xmpp4Js.Lang.isFunction(f) && f!=Object.prototype[fname]) { 247 r[fname]=f; 248 } 249 } 250 } : function(){}, 251 252 /** 253 * Determines whether or not the provided object is a function 254 * @method isFunction 255 * @param {any} o The object being testing 256 * @return {boolean} the result 257 */ 258 isFunction: function(o) { 259 return typeof o === 'function'; 260 }, 261 262 /** 263 * Determines whether or not the provided object is undefined 264 * @method isUndefined 265 * @param {any} o The object being testing 266 * @return {boolean} the result 267 */ 268 isUndefined: function(o) { 269 return typeof o === 'undefined'; 270 }, 271 272 /** 273 * Utility to set up the prototype, constructor and superclass properties to 274 * support an inheritance strategy that can chain constructors and methods. 275 * Static members will not be inherited. 276 * 277 * @method extend 278 * @static 279 * @param {Function} subc the object to modify 280 * @param {Function} superc the object to inherit 281 * @param {Object} overrides additional properties/methods to add to the 282 * subclass prototype. These will override the 283 * matching items obtained from the superclass 284 * if present. 285 */ 286 extend: function(subc, superc, overrides) { 287 if (!superc||!subc) { 288 throw new Error("extend failed, please check that " + 289 "all dependencies are included."); 290 } 291 var F = function() {}; 292 F.prototype=superc.prototype; 293 subc.prototype=new F(); 294 subc.prototype.constructor=subc; 295 subc.superclass=superc.prototype; 296 if (superc.prototype.constructor == Object.prototype.constructor) { 297 superc.prototype.constructor=superc; 298 } 299 300 if (overrides) { 301 for (var i in overrides) { 302 if (Xmpp4Js.Lang.hasOwnProperty(overrides, i)) { 303 subc.prototype[i]=overrides[i]; 304 } 305 } 306 307 Xmpp4Js.Lang._IEEnumFix(subc.prototype, overrides); 308 } 309 }, 310 311 id: function(prefix) { 312 if(!prefix) { prefix = "soashable-"; } 313 314 return prefix+Math.random(0, 50000); 315 }, 316 317 /** 318 * Applies all properties in the supplier to the receiver if the 319 * receiver does not have these properties yet. Optionally, one or 320 * more methods/properties can be specified (as additional 321 * parameters). This option will overwrite the property if receiver 322 * has it already. If true is passed as the third parameter, all 323 * properties will be applied and _will_ overwrite properties in 324 * the receiver. 325 * 326 * @method augmentObject 327 * @static 328 * @since 2.3.0 329 * @param {Function} r the object to receive the augmentation 330 * @param {Function} s the object that supplies the properties to augment 331 * @param {String*|boolean} arguments zero or more properties methods 332 * to augment the receiver with. If none specified, everything 333 * in the supplier will be used unless it would 334 * overwrite an existing property in the receiver. If true 335 * is specified as the third parameter, all properties will 336 * be applied and will overwrite an existing property in 337 * the receiver 338 */ 339 augmentObject: function(r, s) { 340 if (!s||!r) { 341 throw new Error("Absorb failed, verify dependencies."); 342 } 343 var a=arguments, i, p, override=a[2]; 344 if (override && override!==true) { // only absorb the specified properties 345 for (i=2; i<a.length; i=i+1) { 346 r[a[i]] = s[a[i]]; 347 } 348 } else { // take everything, overwriting only if the third parameter is true 349 for (p in s) { 350 if (override || !(p in r)) { 351 r[p] = s[p]; 352 } 353 } 354 355 Xmpp4Js.Lang._IEEnumFix(r, s); 356 } 357 }, 358 359 asyncRequest: function(request) { 360 var xhr = Xmpp4Js.Lang.createXhr(); 361 362 xhr.open(request.method, request.url, request.async != undefined ? request.async : true); 363 for( var header in request.headers ) { 364 xhr.setRequestHeader( header, request.headers[ header ] ); 365 } 366 xhr.onreadystatechange = function() { 367 if (xhr.readyState == 4 ) { 368 var success = xhr.status == 200; 369 370 request.callback.call( request.scope, request, success, xhr ); 371 } 372 }; 373 374 var xml = request.xmlNode.toString(); 375 376 xhr.send(xml); 377 }, 378 379 createXhr : function () { 380 var xhr = false; 381 if(window.XMLHttpRequest) { 382 xhr = new XMLHttpRequest(); 383 if(xhr.overrideMimeType) { 384 xhr.overrideMimeType('text/xml'); 385 } 386 } else if(window.ActiveXObject) { 387 try { 388 xhr = new ActiveXObject('Msxml2.XMLHTTP'); 389 } catch(e) { 390 try { 391 xhr = new ActiveXObject('Microsoft.XMLHTTP'); 392 } catch(e) { 393 xhr = false; 394 } 395 } 396 } 397 return xhr; 398 }, 399 400 urlEncode: function (clearString) { 401 var output = ''; 402 var x = 0; 403 clearString = clearString.toString(); 404 var regex = /(^[a-zA-Z0-9_.]*)/; 405 while (x < clearString.length) { 406 var match = regex.exec(clearString.substr(x)); 407 if (match != null && match.length > 1 && match[1] != '') { 408 output += match[1]; 409 x += match[1].length; 410 } else { 411 if (clearString[x] == ' ') { 412 output += '+'; 413 } else { 414 var charCode = clearString.charCodeAt(x); 415 var hexVal = charCode.toString(16); 416 output += '%' + ( hexVal.length < 2 ? '0' : '' ) + hexVal.toUpperCase(); 417 } 418 x++; 419 } 420 } 421 return output; 422 }, 423 424 noOp: function(){}, 425 426 bind: function( fn, scope ) { 427 var args = Array.prototype.slice.call(arguments); 428 args.shift(); args.shift(); // remove fn and scope 429 430 return function() { 431 var fnArgs = Array.prototype.slice.call(arguments) 432 return fn.apply(scope, args.concat(fnArgs)); 433 } 434 } 435 } 436 437 Function.prototype.bind = function(scope) { 438 //;;; Xmpp4Js.Lang.logger.warn( "Using Function.prototype.bind" ); 439 var args = Array.prototype.slice.call(arguments); 440 args.unshift( this ); // add fn argument to the beginning 441 return Xmpp4Js.Lang.bind.apply( this, args ); 442 } 443 444 445 Xmpp4Js.Lang.TaskRunner = function(interval) { 446 this.interval = interval; 447 this.tasks = []; 448 449 this.intervalId = setInterval(this.onInterval.bind(this), this.interval); 450 } 451 452 Xmpp4Js.Lang.TaskRunner.prototype = { 453 start: function(task) { 454 this.tasks.push( task ); 455 }, 456 457 stop: function(task) { 458 var removeIdxs = []; 459 460 for( var i = 0; i < this.tasks.length; i++ ) { 461 if( this.tasks[i] === task ) { 462 removeIdxs.push( i ); 463 } 464 } 465 466 this.removeTasks( removeIdxs ); 467 }, 468 469 removeTasks: function( removeIdxs ) { 470 // JS is single threaded, so this shouldn't have concurrency issues 471 for( var i = 0; i < removeIdxs.length; i++ ) { 472 var task = this.tasks[i]; 473 474 // fire a stop event if present 475 if( task.onStop ) { 476 task.onStop.apply( task.scope ? task.scope : task ); 477 } 478 479 this.tasks.splice( i, 1 ); 480 } 481 }, 482 483 stopAll: function() { 484 var removeIdxs = []; 485 486 // this is kind of stupid... 487 for( var i = 0; i < this.tasks.length; i++ ) { 488 removeIdxs.push(i); 489 } 490 491 this.removeTasks( removeIdxs ); 492 }, 493 494 onInterval: function() { 495 for( var i = 0; i < this.tasks.length; i++ ) { 496 var task = this.tasks[i]; 497 498 task.run.apply( task.scope ? task.scope : task ); 499 } 500 } 501 502 } 503 504 505 506 507