1 /* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to you under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 18 /** 19 * Runtime/Startup class 20 * this is the central class which initializes all base mechanisms 21 * used by the rest of the system such as 22 * a) namespacing system 23 * b) browser detection 24 * c) loose configuration coupling 25 * d) utils methods to fetch the implementation 26 * e) ajaxed script loading 27 * f) global eval (because it is used internally) 28 * g) Structural base patterns as singleton, delegate and inheritance 29 * 30 * Note this class is self contained and must!!! be loaded 31 * as absolute first class before going into anything else 32 * 33 * 34 */ 35 /** @namespace myfaces._impl.core._Runtime*/ 36 37 myfaces._impl.core = (myfaces._impl.core) ? myfaces._impl.core : {}; 38 //now this is the only time we have to do this cascaded and manually 39 //for the rest of the classes our reserveNamespace function will do the trick 40 //Note, this class uses the classical closure approach (to save code) 41 //it cannot be inherited by our inheritance mechanism, but must be delegated 42 //if you want to derive from it 43 //closures and prototype inheritance do not mix, closures and delegation however do 44 /** 45 * @ignore 46 */ 47 if (!myfaces._impl.core._Runtime) { 48 /** 49 * @memberOf myfaces._impl.core 50 * @namespace 51 * @name _Runtime 52 */ 53 myfaces._impl.core._Runtime = new function() { 54 //the rest of the namespaces can be handled by our namespace feature 55 //helper to avoid unneeded hitches 56 /** 57 * @borrows myfaces._impl.core._Runtime as _T 58 */ 59 var _T = this; 60 61 //namespace idx to speed things up by hitting eval way less 62 this._reservedNMS = {}; 63 this._registeredSingletons = {}; 64 this._registeredClasses = []; 65 /** 66 * replacement counter for plugin classes 67 */ 68 this._classReplacementCnt = 0; 69 70 /** 71 * global eval on scripts 72 * @param {String} code 73 * @name myfaces._impl.core._Runtime.globalEval 74 * @function 75 */ 76 _T.globalEval = function(code) { 77 return myfaces._impl.core._EvalHandlers.globalEval(code); 78 }; 79 80 /** 81 * applies an object to a namespace 82 * basically does what bla.my.name.space = obj does 83 * note we cannot use var myNameSpace = fetchNamespace("my.name.space") 84 * myNameSpace = obj because the result of fetch is already the object 85 * which the namespace points to, hence this function 86 * 87 * @param {String} nms the namespace to be assigned to 88 * @param {Object} obj the object to be assigned 89 * @name myfaces._impl.core._Runtime.applyToGlobalNamespace 90 * @function 91 */ 92 _T.applyToGlobalNamespace = function(nms, obj) { 93 var splitted = nms.split(/\./); 94 if (splitted.length == 1) { 95 window[nms] = obj; 96 return; 97 } 98 var parent = splitted.slice(0, splitted.length - 1); 99 var child = splitted[splitted.length - 1]; 100 var parentNamespace = _T.fetchNamespace(parent.join(".")); 101 parentNamespace[child] = obj; 102 }; 103 104 /** 105 * fetches the object the namespace points to 106 * @param {String} nms the namespace which has to be fetched 107 * @return the object the namespace points to or null if nothing is found 108 */ 109 this.fetchNamespace = function(nms) { 110 if ('undefined' == typeof nms || null == nms || !_T._reservedNMS[nms]) { 111 return null; 112 } 113 114 var ret = null; 115 try { 116 //blackberries have problems as well in older non webkit versions 117 if (!_T.browser.isIE) { 118 //in ie 6 and 7 we get an error entry despite the suppression 119 ret = _T.globalEval("window." + nms); 120 } 121 //namespace could point to numeric or boolean hence full 122 //save check 123 124 } catch (e) {/*wanted*/ 125 } 126 //ie fallback for some ie versions path because it cannot eval namespaces 127 //ie in any version does not like that particularily 128 //we do it the hard way now 129 if ('undefined' != typeof ret && null != ret) { 130 return ret; 131 } 132 return _T._manuallyResolveNMS(nms); 133 134 }; 135 136 _T._manuallyResolveNMS = function(nms) { 137 //ie fallback for some ie versions path because it cannot eval namespaces 138 //ie in any version does not like that particularily 139 //we do it the hard way now 140 141 nms = nms.split(/\./); 142 var ret = window; 143 var len = nms.length; 144 145 for (var cnt = 0; cnt < len; cnt++) { 146 ret = ret[nms[cnt]]; 147 if ('undefined' == typeof ret || null == ret) { 148 return null; 149 } 150 } 151 return ret; 152 }; 153 154 /** 155 * Backported from dojo 156 * a failsafe string determination method 157 * (since in javascript String != "" typeof alone fails!) 158 * @param {Object} it the object to be checked for being a string 159 * @return {boolean} true in case of being a string false otherwise 160 */ 161 this.isString = function(/*anything*/ it) { 162 // summary: 163 // Return true if it is a String 164 return !!arguments.length && it != null && (typeof it == "string" || it instanceof String); // Boolean 165 }; 166 167 /** 168 * reserves a namespace in the specific scope 169 * 170 * usage: 171 * if(_T.reserve("org.apache.myfaces.MyUtils")) { 172 * org.apache.myfaces.MyUtils = function() { 173 * } 174 * } 175 * 176 * reserves a namespace and if the namespace is new the function itself is reserved 177 * 178 * 179 * 180 * or: 181 * _T.reserve("org.apache.myfaces.MyUtils", function() { .. }); 182 * 183 * reserves a namespace and if not already registered directly applies the function the namespace 184 * 185 * note for now the reserved namespaces reside as global maps justl like jsf.js but 186 * we also use a speedup index which is kept internally to reduce the number of evals or loops to walk through those 187 * namespaces (eval is a heavy operation and loops even only for namespace resolution introduce (O)2 runtime 188 * complexity while a simple map lookup is (O)log n with additional speedup from the engine. 189 * 190 * 191 * @param {String} nms 192 * @returns {boolean} true if it was not provided 193 * false otherwise for further action 194 */ 195 this.reserveNamespace = function(nms, obj) { 196 197 if (!_T.isString(nms)) { 198 throw Error("Namespace must be a string with . as delimiter"); 199 } 200 if (_T._reservedNMS[nms] || null != _T.fetchNamespace(nms)) { 201 return false; 202 } 203 204 var entries = nms.split(/\./); 205 var currNms = window; 206 207 var tmpNmsName = []; 208 var UDEF = "undefined"; 209 for (var cnt = 0; cnt < entries.length; cnt++) { 210 var subNamespace = entries[cnt]; 211 tmpNmsName.push(subNamespace); 212 if (UDEF == typeof currNms[subNamespace]) { 213 currNms[subNamespace] = {}; 214 } 215 if (cnt == entries.length - 1 && UDEF != typeof obj) { 216 currNms[subNamespace] = obj; 217 } else { 218 currNms = currNms[subNamespace]; 219 } 220 _T._reservedNMS[tmpNmsName.join(".")] = true; 221 } 222 return true; 223 }; 224 225 /** 226 * iterates over all registered singletons in the namespace 227 * @param operator a closure which applies a certain function 228 * on the namespace singleton 229 */ 230 this.iterateSingletons = function(operator) { 231 var singletons = _T._registeredSingletons; 232 for(var key in singletons) { 233 var nms = _T.fetchNamespace(key); 234 operator(nms); 235 } 236 }; 237 /** 238 * iterates over all registered singletons in the namespace 239 * @param operator a closure which applies a certain function 240 * on the namespace singleton 241 */ 242 this.iterateClasses = function(operator) { 243 var classes = _T._registeredClasses; 244 for(var cnt = 0; cnt < classes.length; cnt++) { 245 operator(classes[cnt], cnt); 246 } 247 }; 248 249 /** 250 * check if an element exists in the root 251 * also allows to check for subelements 252 * usage 253 * _T.exists(rootElem,"my.name.space") 254 * @param {Object} root the root element 255 * @param {String} subNms the namespace 256 */ 257 this.exists = function(root, subNms) { 258 if (!root) { 259 return false; 260 } 261 //special case locally reserved namespace 262 if (root == window && _T._reservedNMS[subNms]) { 263 return true; 264 } 265 266 //initial condition root set element not set or null 267 //equals to element exists 268 if (!subNms) { 269 return true; 270 } 271 var UDEF = "undefined"; 272 try { 273 //special condition subnamespace exists as full blown key with . instead of function map 274 if (UDEF != typeof root[subNms]) { 275 return true; 276 } 277 278 //crossported from the dojo toolkit 279 // summary: determine if an object supports a given method 280 // description: useful for longer api chains where you have to test each object in the chain 281 var p = subNms.split("."); 282 var len = p.length; 283 for (var i = 0; i < len; i++) { 284 //the original dojo code here was false because 285 //they were testing against ! which bombs out on exists 286 //which has a value set to false 287 // (TODO send in a bugreport to the Dojo people) 288 289 if (UDEF == typeof root[p[i]]) { 290 return false; 291 } // Boolean 292 root = root[p[i]]; 293 } 294 return true; // Boolean 295 296 } catch (e) { 297 //ie (again) has a special handling for some object attributes here which automatically throw an unspecified error if not existent 298 return false; 299 } 300 }; 301 302 303 304 /** 305 * fetches a global config entry 306 * @param {String} configName the name of the configuration entry 307 * @param {Object} defaultValue 308 * 309 * @return either the config entry or if none is given the default value 310 */ 311 this.getGlobalConfig = function(configName, defaultValue) { 312 /** 313 * note we could use exists but this is an heavy operation, since the config name usually 314 * given this function here is called very often 315 * is a single entry without . in between we can do the lighter shortcut 316 */ 317 return (myfaces["config"] && 'undefined' != typeof myfaces.config[configName] ) ? 318 myfaces.config[configName] 319 : 320 defaultValue; 321 }; 322 323 /** 324 * gets the local or global options with local ones having higher priority 325 * if no local or global one was found then the default value is given back 326 * 327 * @param {String} configName the name of the configuration entry 328 * @param {String} localOptions the local options root for the configuration myfaces as default marker is added implicitely 329 * 330 * @param {Object} defaultValue 331 * 332 * @return either the config entry or if none is given the default value 333 */ 334 this.getLocalOrGlobalConfig = function(localOptions, configName, defaultValue) { 335 /*use(myfaces._impl._util)*/ 336 var _local = !!localOptions; 337 var _localResult; 338 var MYFACES = "myfaces"; 339 340 if (_local) { 341 //note we also do not use exist here due to performance improvement reasons 342 //not for now we loose the subnamespace capabilities but we do not use them anyway 343 //this code will give us a performance improvement of 2-3% 344 _localResult = (localOptions[MYFACES]) ? localOptions[MYFACES][configName] : undefined; 345 _local = "undefined" != typeof _localResult; 346 } 347 348 return (!_local) ? _T.getGlobalConfig(configName, defaultValue) : _localResult; 349 }; 350 351 /** 352 * determines the xhr level which either can be 353 * 1 for classical level1 354 * 1.5 for mozillas send as binary implementation 355 * 2 for xhr level 2 356 */ 357 this.getXHRLvl = function() { 358 if (!_T.XHR_LEVEL) { 359 _T.getXHRObject(); 360 } 361 return _T.XHR_LEVEL; 362 }; 363 364 /** 365 * encapsulated xhr object which tracks down various implementations 366 * of the xhr object in a browser independent fashion 367 * (ie pre 7 used to have non standard implementations because 368 * the xhr object standard came after IE had implemented it first 369 * newer ie versions adhere to the standard and all other new browsers do anyway) 370 * 371 * @return the xhr object according to the browser type 372 */ 373 this.getXHRObject = function() { 374 var _ret = new XMLHttpRequest(); 375 //we now check the xhr level 376 //sendAsBinary = 1.5 which means mozilla only 377 //upload attribute present == level2 378 var XHR_LEVEL = "XHR_LEVEL"; 379 if (!_T[XHR_LEVEL]) { 380 var _e = _T.exists; 381 _T[XHR_LEVEL] = (_e(_ret, "sendAsBinary")) ? 1.5 : 1; 382 _T[XHR_LEVEL] = (_e(_ret, "upload") && 'undefined' != typeof FormData) ? 2 : _T.XHR_LEVEL; 383 } 384 return _ret; 385 }; 386 387 /** 388 * loads a script and executes it under a global scope 389 * @param {String} src the source of the script 390 * @param {String} type the type of the script 391 * @param {Boolean} defer defer true or false, same as the javascript tag defer param 392 * @param {String} charSet the charset under which the script has to be loaded 393 * @param {Boolean} async tells whether the script can be asynchronously loaded or not, currently 394 * not used 395 */ 396 this.loadScriptEval = function(src, type, defer, charSet, async) { 397 var xhr = _T.getXHRObject(); 398 xhr.open("GET", src, false); 399 400 if (charSet) { 401 xhr.setRequestHeader("Content-Type", "text/javascript; charset:" + charSet); 402 } 403 404 xhr.send(null); 405 406 //since we are synchronous we do it after not with onReadyStateChange 407 408 if (xhr.readyState == 4) { 409 if (xhr.status == 200) { 410 //defer also means we have to process after the ajax response 411 //has been processed 412 //we can achieve that with a small timeout, the timeout 413 //triggers after the processing is done! 414 if (!defer) { 415 //we moved the sourceurl notation to # instead of @ because ie does not cover it correctly 416 //newer browsers understand # including ie since windows 8.1 417 //see http://updates.html5rocks.com/2013/06/sourceMappingURL-and-sourceURL-syntax-changed 418 _T.globalEval(xhr.responseText.replace("\n", "\r\n") + "\r\n//# sourceURL=" + src); 419 } else { 420 //TODO not ideal we maybe ought to move to something else here 421 //but since it is not in use yet, it is ok 422 setTimeout(function() { 423 _T.globalEval(xhr.responseText.replace("\n", "\r\n") + "\r\n//# sourceURL=" + src); 424 }, 1); 425 } 426 } else { 427 throw Error(xhr.responseText); 428 } 429 } else { 430 throw Error("Loading of script " + src + " failed "); 431 } 432 433 }; 434 435 /** 436 * load script functionality which utilizes the browser internal 437 * script loading capabilities 438 * 439 * @param {String} src the source of the script 440 * @param {String} type the type of the script 441 * @param {Boolean} defer defer true or false, same as the javascript tag defer param 442 * @param {String} charSet the charset under which the script has to be loaded 443 */ 444 this.loadScriptByBrowser = function(src, type, defer, charSet, async) { 445 //if a head is already present then it is safer to simply 446 //use the body, some browsers prevent head alterations 447 //after the first initial rendering 448 449 //ok this is nasty we have to do a head modification for ie pre 8 450 //the rest can be finely served with body 451 var position = "head"; 452 var UDEF = "undefined"; 453 try { 454 var holder = document.getElementsByTagName(position)[0]; 455 if (UDEF == typeof holder || null == holder) { 456 holder = document.createElement(position); 457 var html = document.getElementsByTagName("html"); 458 html.appendChild(holder); 459 } 460 var script = document.createElement("script"); 461 462 script.type = type || "text/javascript"; 463 script.src = src; 464 if (charSet) { 465 script.charset = charSet; 466 } 467 if (defer) { 468 script.defer = defer; 469 } 470 /*html5 capable browsers can deal with script.async for 471 * proper head loading*/ 472 if (UDEF != typeof script.async) { 473 script.async = async; 474 } 475 holder.appendChild(script); 476 477 } catch (e) { 478 //in case of a loading error we retry via eval 479 return false; 480 } 481 482 return true; 483 }; 484 485 this.loadScript = function(src, type, defer, charSet, async) { 486 //the chrome engine has a nasty javascript bug which prevents 487 //a correct order of scripts being loaded 488 //if you use script source on the head, we have to revert 489 //to xhr+ globalEval for those 490 var b = _T.browser; 491 if (!b.isFF && !b.isWebkit && !b.isOpera >= 10) { 492 _T.loadScriptEval(src, type, defer, charSet); 493 } else { 494 //only firefox keeps the order, sorry ie... 495 _T.loadScriptByBrowser(src, type, defer, charSet, async); 496 } 497 }; 498 499 //Base Patterns, Inheritance, Delegation and Singleton 500 501 502 503 /* 504 * prototype based delegation inheritance 505 * 506 * implements prototype delegaton inheritance dest <- a 507 * 508 * usage 509 * <pre> 510 * var newClass = _T.extends( function (var1, var2) { 511 * _T._callSuper("constructor", var1,var2); 512 * }; 513 * ,origClass); 514 * 515 * newClass.prototype.myMethod = function(arg1) { 516 * _T._callSuper("myMethod", arg1,"hello world"); 517 * .... 518 * 519 * other option 520 * 521 * myfaces._impl._core._Runtime.extends("myNamespace.newClass", parent, { 522 * init: function() {constructor...}, 523 * method1: function(f1, f2) {}, 524 * method2: function(f1, f2,f3) { 525 * _T._callSuper("method2", F1,"hello world"); 526 * } 527 * }); 528 * </p> 529 * @param {function|String} newCls either a unnamed function which can be assigned later or a namespace 530 * @param {function} extendCls the function class to be extended 531 * @param {Object} protoFuncs (Map) an optional map of prototype functions which in case of overwriting a base function get an inherited method 532 * 533 * To explain further 534 * prototype functions: 535 * <pre> 536 * newClass.prototype.<prototypeFunction> 537 * namspace function 538 * newCls.<namespaceFunction> = function() {...} 539 * </pre> 540 */ 541 542 this.extendClass = function(newCls, extendCls, protoFuncs, nmsFuncs) { 543 544 if (!_T.isString(newCls)) { 545 throw Error("new class namespace must be of type String"); 546 } 547 var className = newCls; 548 549 if (_T._reservedNMS[newCls]) { 550 return _T.fetchNamespace(newCls); 551 } 552 var constr = "constructor_"; 553 var parClassRef = "_mfClazz"; 554 if(!protoFuncs[constr]) { 555 protoFuncs[constr] = (extendCls[parClassRef] || (extendCls.prototype && extendCls.prototype[parClassRef])) ? 556 function() {this._callSuper("constructor_");}: function() {}; 557 var assigned = true; 558 } 559 560 if ('function' != typeof newCls) { 561 newCls = _reserveClsNms(newCls, protoFuncs); 562 if (!newCls) return null; 563 } 564 //if the type information is known we use that one 565 //with this info we can inherit from objects also 566 //instead of only from classes 567 //sort of like this.extendClass(newCls, extendObj._mfClazz... 568 569 if (extendCls[parClassRef]) { 570 extendCls = extendCls[parClassRef]; 571 } 572 573 if ('undefined' != typeof extendCls && null != extendCls) { 574 //first we have to get rid of the constructor calling problem 575 //problem 576 var tmpFunc = function() { 577 }; 578 tmpFunc.prototype = extendCls.prototype; 579 580 var newClazz = newCls; 581 newClazz.prototype = new tmpFunc(); 582 tmpFunc = null; 583 var clzProto = newClazz.prototype; 584 clzProto.constructor = newCls; 585 clzProto._parentCls = extendCls.prototype; 586 //in case of overrides the namespace is altered with mfclazz 587 //we want the final namespace 588 clzProto._nameSpace = className.replace(/(\._mfClazz)+$/,""); 589 /** 590 * @ignore 591 */ 592 clzProto._callSuper = function(methodName) { 593 var passThrough = (arguments.length == 1) ? [] : Array.prototype.slice.call(arguments, 1); 594 var accDescLevel = "_mfClsDescLvl"; 595 //we store the descension level of each method under a mapped 596 //name to avoid name clashes 597 //to avoid name clashes with internal methods of array 598 //if we don't do this we trap the callSuper in an endless 599 //loop after descending one level 600 var _mappedName = ["_",methodName,"_mf_r"].join(""); 601 this[accDescLevel] = this[accDescLevel] || new Array(); 602 var descLevel = this[accDescLevel]; 603 //we have to detect the descension level 604 //we now check if we are in a super descension for the current method already 605 //if not we are on this level 606 var _oldDescLevel = this[accDescLevel][_mappedName] || this; 607 //we now step one level down 608 var _parentCls = _oldDescLevel._parentCls; 609 var ret = null; 610 try { 611 //we now store the level position as new descension level for callSuper 612 descLevel[_mappedName] = _parentCls; 613 //and call the code on this 614 if(!_parentCls[methodName]) { 615 throw Error("Method _callSuper('"+ methodName+"') called from "+className+" Method does not exist "); 616 } 617 ret = _parentCls[methodName].apply(this, passThrough); 618 } finally { 619 descLevel[_mappedName] = _oldDescLevel; 620 } 621 if('undefined' != typeof ret) { 622 return ret; 623 } 624 }; 625 //reference to its own type 626 clzProto[parClassRef] = newCls; 627 _T._registeredClasses.push(clzProto); 628 } 629 630 //we now map the function map in 631 _T._applyFuncs(newCls, protoFuncs, true); 632 //we could add inherited but that would make debugging harder 633 //see http://www.ruzee.com/blog/2008/12/javascript-inheritance-via-prototypes-and-closures on how to do it 634 635 _T._applyFuncs(newCls, nmsFuncs, false); 636 637 return newCls; 638 }; 639 640 641 642 /** 643 * Extends a class and puts a singleton instance at the reserved namespace instead 644 * of its original class 645 * 646 * @param {function|String} newCls either a unnamed function which can be assigned later or a namespace 647 * @param {function} extendsCls the function class to be extended 648 * @param {Object} protoFuncs (Map) an optional map of prototype functions which in case of overwriting a base function get an inherited method 649 */ 650 this.singletonExtendClass = function(newCls, extendsCls, protoFuncs, nmsFuncs) { 651 _T._registeredSingletons[newCls] = true; 652 return _T._makeSingleton(_T.extendClass, newCls, extendsCls, protoFuncs, nmsFuncs); 653 }; 654 655 656 657 //since the object is self contained and only 658 //can be delegated we can work with real private 659 //functions here, the other parts of the 660 //system have to emulate them via _ prefixes 661 this._makeSingleton = function(ooFunc, newCls, delegateObj, protoFuncs, nmsFuncs) { 662 if (_T._reservedNMS[newCls]) { 663 return _T._reservedNMS[newCls]; 664 } 665 666 var clazz = ooFunc(newCls + "._mfClazz", delegateObj, protoFuncs, nmsFuncs); 667 if (clazz != null) { 668 _T.applyToGlobalNamespace(newCls, new clazz()); 669 } 670 return _T.fetchNamespace(newCls)["_mfClazz"] = clazz; 671 }; 672 673 //internal class namespace reservation depending on the type (string or function) 674 var _reserveClsNms = function(newCls, protoFuncs) { 675 var constr = null; 676 var UDEF = "undefined"; 677 if (UDEF != typeof protoFuncs && null != protoFuncs) { 678 constr = (UDEF != typeof null != protoFuncs['constructor_'] && null != protoFuncs['constructor_']) ? protoFuncs['constructor_'] : function() { 679 }; 680 } else { 681 constr = function() { 682 }; 683 } 684 685 if (!_T.reserveNamespace(newCls, constr)) { 686 return null; 687 } 688 newCls = _T.fetchNamespace(newCls); 689 return newCls; 690 }; 691 692 this._applyFuncs = function (newCls, funcs, proto) { 693 if (funcs) { 694 for (var key in funcs) { 695 //constructor already passed, callSuper already assigned 696 if ('undefined' == typeof key || null == key || key == "_callSuper") { 697 continue; 698 } 699 if (!proto) 700 newCls[key] = funcs[key]; 701 else 702 newCls.prototype[key] = funcs[key]; 703 } 704 } 705 }; 706 707 /** 708 * general type assertion routine 709 * 710 * @param probe the probe to be checked for the correct type 711 * @param theType the type to be checked for 712 */ 713 this.assertType = function(probe, theType) { 714 return _T.isString(theType) ? probe == typeof theType : probe instanceof theType; 715 }; 716 717 /** 718 * onload wrapper for chaining the onload cleanly 719 * @param func the function which should be added to the load 720 * chain (note we cannot rely on return values here, hence jsf.util.chain will fail) 721 */ 722 this.addOnLoad = function(target, func) { 723 var oldonload = (target) ? target.onload : null; 724 target.onload = (!oldonload) ? func : function() { 725 try { 726 oldonload(); 727 } catch (e) { 728 throw e; 729 } finally { 730 func(); 731 } 732 }; 733 }; 734 735 /** 736 * returns the internationalisation setting 737 * for the given browser so that 738 * we can i18n our messages 739 * 740 * @returns a map with following entires: 741 * <ul> 742 * <li>language: the lowercase language iso code</li> 743 * <li>variant: the uppercase variant iso code</li> 744 * </ul> 745 * null is returned if the browser fails to determine the language settings 746 */ 747 this.getLanguage = function(lOverride) { 748 var deflt = {language: "en", variant: "UK"}; //default language and variant 749 try { 750 var lang = lOverride || navigator.language || navigator.browserLanguage; 751 if (!lang || lang.length < 2) return deflt; 752 return { 753 language: lang.substr(0, 2), 754 variant: (lang.length >= 5) ? lang.substr(3, 5) : null 755 }; 756 } catch(e) { 757 return deflt; 758 } 759 }; 760 761 //implemented in extruntime 762 this.singletonDelegateObj = function() {}; 763 764 /** 765 * browser detection code 766 * cross ported from dojo 1.2 767 * 768 * dojos browser detection code is very sophisticated 769 * hence we port it over it allows a very fine grained detection of 770 * browsers including the version number 771 * this however only can work out if the user 772 * does not alter the user agent, which they normally dont! 773 * 774 * the exception is the ie detection which relies on specific quirks in ie 775 */ 776 var n = navigator; 777 var dua = n.userAgent, 778 dav = n.appVersion, 779 tv = parseFloat(dav); 780 var _T = this; 781 _T.browser = {}; 782 myfaces._impl.core._EvalHandlers.browser = _T.browser; 783 var d = _T.browser; 784 785 if (dua.indexOf("Opera") >= 0) { 786 _T.isOpera = tv; 787 } 788 if (dua.indexOf("AdobeAIR") >= 0) { 789 d.isAIR = 1; 790 } 791 if (dua.indexOf("BlackBerry") >= 0) { 792 d.isBlackBerry = tv; 793 } 794 d.isKhtml = (dav.indexOf("Konqueror") >= 0) ? tv : 0; 795 d.isWebKit = parseFloat(dua.split("WebKit/")[1]) || undefined; 796 d.isChrome = parseFloat(dua.split("Chrome/")[1]) || undefined; 797 798 // safari detection derived from: 799 // http://developer.apple.com/internet/safari/faq.html#anchor2 800 // http://developer.apple.com/internet/safari/uamatrix.html 801 var index = Math.max(dav.indexOf("WebKit"), dav.indexOf("Safari"), 0); 802 if (index && !d.isChrome) { 803 // try to grab the explicit Safari version first. If we don't get 804 // one, look for less than 419.3 as the indication that we're on something 805 // "Safari 2-ish". 806 d.isSafari = parseFloat(dav.split("Version/")[1]); 807 if (!d.isSafari || parseFloat(dav.substr(index + 7)) <= 419.3) { 808 d.isSafari = 2; 809 } 810 } 811 812 //>>excludeStart("webkitMobile", kwArgs.webkitMobile); 813 814 if (dua.indexOf("Gecko") >= 0 && !d.isKhtml && !d.isWebKit) { 815 d.isMozilla = d.isMoz = tv; 816 } 817 if (d.isMoz) { 818 //We really need to get away from _T. Consider a sane isGecko approach for the future. 819 d.isFF = parseFloat(dua.split("Firefox/")[1] || dua.split("Minefield/")[1] || dua.split("Shiretoko/")[1]) || undefined; 820 } 821 822 if (document.all && !d.isOpera && !d.isBlackBerry) { 823 d.isIE = parseFloat(dav.split("MSIE ")[1]) || undefined; 824 d.isIEMobile = parseFloat(dua.split("IEMobile")[1]); 825 //In cases where the page has an HTTP header or META tag with 826 //X-UA-Compatible, then it is in emulation mode, for a previous 827 //version. Make sure isIE reflects the desired version. 828 //document.documentMode of 5 means quirks mode. 829 830 /** @namespace document.documentMode */ 831 if (d.isIE >= 8 && document.documentMode != 5) { 832 d.isIE = document.documentMode; 833 } 834 } 835 }; 836 } 837 838