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, cspMeta) { 77 return myfaces._impl.core._EvalHandlers.globalEval(code, cspMeta); 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 faces.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 * @param cspMetas csp meta data to be processed by globalEval 395 * not used 396 */ 397 this.loadScriptEval = function(src, type, defer, charSet, async, cspMeta) { 398 var xhr = _T.getXHRObject(); 399 xhr.open("GET", src, false); 400 401 if (charSet) { 402 xhr.setRequestHeader("Content-Type", "text/javascript; charset:" + charSet); 403 } 404 405 xhr.send(null); 406 407 //since we are synchronous we do it after not with onReadyStateChange 408 409 if (xhr.readyState == 4) { 410 if (xhr.status == 200) { 411 //defer also means we have to process after the ajax response 412 //has been processed 413 //we can achieve that with a small timeout, the timeout 414 //triggers after the processing is done! 415 if (!defer) { 416 //we moved the sourceurl notation to # instead of @ because ie does not cover it correctly 417 //newer browsers understand # including ie since windows 8.1 418 //see http://updates.html5rocks.com/2013/06/sourceMappingURL-and-sourceURL-syntax-changed 419 _T.globalEval(xhr.responseText.replace("\n", "\r\n") + "\r\n//# sourceURL=" + src, cspMeta); 420 } else { 421 //TODO not ideal we maybe ought to move to something else here 422 //but since it is not in use yet, it is ok 423 setTimeout(function() { 424 _T.globalEval(xhr.responseText.replace("\n", "\r\n") + "\r\n//# sourceURL=" + src, cspMeta); 425 }, 1); 426 } 427 } else { 428 throw Error(xhr.responseText); 429 } 430 } else { 431 throw Error("Loading of script " + src + " failed "); 432 } 433 434 }; 435 436 /** 437 * load script functionality which utilizes the browser internal 438 * script loading capabilities 439 * 440 * @param {String} src the source of the script 441 * @param {String} type the type of the script 442 * @param {Boolean} defer defer true or false, same as the javascript tag defer param 443 * @param {String} charSet the charset under which the script has to be loaded 444 */ 445 this.loadScriptByBrowser = function(src, type, defer, charSet, async, cspMeta) { 446 //if a head is already present then it is safer to simply 447 //use the body, some browsers prevent head alterations 448 //after the first initial rendering 449 450 //ok this is nasty we have to do a head modification for ie pre 8 451 //the rest can be finely served with body 452 var position = "head"; 453 var UDEF = "undefined"; 454 try { 455 var holder = document.getElementsByTagName(position)[0]; 456 if (UDEF == typeof holder || null == holder) { 457 holder = document.createElement(position); 458 var html = document.getElementsByTagName("html"); 459 html.appendChild(holder); 460 } 461 var script = document.createElement("script"); 462 463 script.type = type || "text/javascript"; 464 script.src = src; 465 if(cspMeta && cspMeta.nonce) { 466 script.setAttribute("nonce", cspMeta.nonce); 467 } 468 if (charSet) { 469 script.charset = charSet; 470 } 471 if (defer) { 472 script.defer = defer; 473 } 474 /*html5 capable browsers can deal with script.async for 475 * proper head loading*/ 476 if (UDEF != typeof script.async) { 477 script.async = async; 478 } 479 holder.appendChild(script); 480 481 } catch (e) { 482 //in case of a loading error we retry via eval 483 return false; 484 } 485 486 return true; 487 }; 488 489 this.loadScript = function(src, type, defer, charSet, async) { 490 //the chrome engine has a nasty javascript bug which prevents 491 //a correct order of scripts being loaded 492 //if you use script source on the head, we have to revert 493 //to xhr+ globalEval for those 494 var b = _T.browser; 495 if (!b.isFF && !b.isWebkit && !b.isOpera >= 10) { 496 _T.loadScriptEval(src, type, defer, charSet); 497 } else { 498 //only firefox keeps the order, sorry ie... 499 _T.loadScriptByBrowser(src, type, defer, charSet, async); 500 } 501 }; 502 503 //Base Patterns, Inheritance, Delegation and Singleton 504 505 506 507 /* 508 * prototype based delegation inheritance 509 * 510 * implements prototype delegaton inheritance dest <- a 511 * 512 * usage 513 * <pre> 514 * var newClass = _T.extends( function (var1, var2) { 515 * _T._callSuper("constructor", var1,var2); 516 * }; 517 * ,origClass); 518 * 519 * newClass.prototype.myMethod = function(arg1) { 520 * _T._callSuper("myMethod", arg1,"hello world"); 521 * .... 522 * 523 * other option 524 * 525 * myfaces._impl._core._Runtime.extends("myNamespace.newClass", parent, { 526 * init: function() {constructor...}, 527 * method1: function(f1, f2) {}, 528 * method2: function(f1, f2,f3) { 529 * _T._callSuper("method2", F1,"hello world"); 530 * } 531 * }); 532 * </p> 533 * @param {function|String} newCls either a unnamed function which can be assigned later or a namespace 534 * @param {function} extendCls the function class to be extended 535 * @param {Object} protoFuncs (Map) an optional map of prototype functions which in case of overwriting a base function get an inherited method 536 * 537 * To explain further 538 * prototype functions: 539 * <pre> 540 * newClass.prototype.<prototypeFunction> 541 * namspace function 542 * newCls.<namespaceFunction> = function() {...} 543 * </pre> 544 */ 545 546 this.extendClass = function(newCls, extendCls, protoFuncs, nmsFuncs) { 547 548 if (!_T.isString(newCls)) { 549 throw Error("new class namespace must be of type String"); 550 } 551 var className = newCls; 552 553 if (_T._reservedNMS[newCls]) { 554 return _T.fetchNamespace(newCls); 555 } 556 var constr = "constructor_"; 557 var parClassRef = "_mfClazz"; 558 if(!protoFuncs[constr]) { 559 protoFuncs[constr] = (extendCls[parClassRef] || (extendCls.prototype && extendCls.prototype[parClassRef])) ? 560 function() {this._callSuper("constructor_");}: function() {}; 561 var assigned = true; 562 } 563 564 if ('function' != typeof newCls) { 565 newCls = _reserveClsNms(newCls, protoFuncs); 566 if (!newCls) return null; 567 } 568 //if the type information is known we use that one 569 //with this info we can inherit from objects also 570 //instead of only from classes 571 //sort of like this.extendClass(newCls, extendObj._mfClazz... 572 573 if (extendCls[parClassRef]) { 574 extendCls = extendCls[parClassRef]; 575 } 576 577 if ('undefined' != typeof extendCls && null != extendCls) { 578 //first we have to get rid of the constructor calling problem 579 //problem 580 var tmpFunc = function() { 581 }; 582 tmpFunc.prototype = extendCls.prototype; 583 584 var newClazz = newCls; 585 newClazz.prototype = new tmpFunc(); 586 tmpFunc = null; 587 var clzProto = newClazz.prototype; 588 clzProto.constructor = newCls; 589 clzProto._parentCls = extendCls.prototype; 590 //in case of overrides the namespace is altered with mfclazz 591 //we want the final namespace 592 clzProto._nameSpace = className.replace(/(\._mfClazz)+$/,""); 593 /** 594 * @ignore 595 */ 596 clzProto._callSuper = function(methodName) { 597 var passThrough = (arguments.length == 1) ? [] : Array.prototype.slice.call(arguments, 1); 598 var accDescLevel = "_mfClsDescLvl"; 599 //we store the descension level of each method under a mapped 600 //name to avoid name clashes 601 //to avoid name clashes with internal methods of array 602 //if we don't do this we trap the callSuper in an endless 603 //loop after descending one level 604 var _mappedName = ["_",methodName,"_mf_r"].join(""); 605 this[accDescLevel] = this[accDescLevel] || new Array(); 606 var descLevel = this[accDescLevel]; 607 //we have to detect the descension level 608 //we now check if we are in a super descension for the current method already 609 //if not we are on this level 610 var _oldDescLevel = this[accDescLevel][_mappedName] || this; 611 //we now step one level down 612 var _parentCls = _oldDescLevel._parentCls; 613 var ret = null; 614 try { 615 //we now store the level position as new descension level for callSuper 616 descLevel[_mappedName] = _parentCls; 617 //and call the code on this 618 if(!_parentCls[methodName]) { 619 throw Error("Method _callSuper('"+ methodName+"') called from "+className+" Method does not exist "); 620 } 621 ret = _parentCls[methodName].apply(this, passThrough); 622 } finally { 623 descLevel[_mappedName] = _oldDescLevel; 624 } 625 if('undefined' != typeof ret) { 626 return ret; 627 } 628 }; 629 //reference to its own type 630 clzProto[parClassRef] = newCls; 631 _T._registeredClasses.push(clzProto); 632 } 633 634 //we now map the function map in 635 _T._applyFuncs(newCls, protoFuncs, true); 636 //we could add inherited but that would make debugging harder 637 //see http://www.ruzee.com/blog/2008/12/javascript-inheritance-via-prototypes-and-closures on how to do it 638 639 _T._applyFuncs(newCls, nmsFuncs, false); 640 641 return newCls; 642 }; 643 644 645 646 /** 647 * Extends a class and puts a singleton instance at the reserved namespace instead 648 * of its original class 649 * 650 * @param {function|String} newCls either a unnamed function which can be assigned later or a namespace 651 * @param {function} extendsCls the function class to be extended 652 * @param {Object} protoFuncs (Map) an optional map of prototype functions which in case of overwriting a base function get an inherited method 653 */ 654 this.singletonExtendClass = function(newCls, extendsCls, protoFuncs, nmsFuncs) { 655 _T._registeredSingletons[newCls] = true; 656 return _T._makeSingleton(_T.extendClass, newCls, extendsCls, protoFuncs, nmsFuncs); 657 }; 658 659 660 661 //since the object is self contained and only 662 //can be delegated we can work with real private 663 //functions here, the other parts of the 664 //system have to emulate them via _ prefixes 665 this._makeSingleton = function(ooFunc, newCls, delegateObj, protoFuncs, nmsFuncs) { 666 if (_T._reservedNMS[newCls]) { 667 return _T._reservedNMS[newCls]; 668 } 669 670 var clazz = ooFunc(newCls + "._mfClazz", delegateObj, protoFuncs, nmsFuncs); 671 if (clazz != null) { 672 _T.applyToGlobalNamespace(newCls, new clazz()); 673 } 674 return _T.fetchNamespace(newCls)["_mfClazz"] = clazz; 675 }; 676 677 //internal class namespace reservation depending on the type (string or function) 678 var _reserveClsNms = function(newCls, protoFuncs) { 679 var constr = null; 680 var UDEF = "undefined"; 681 if (UDEF != typeof protoFuncs && null != protoFuncs) { 682 constr = (UDEF != typeof null != protoFuncs['constructor_'] && null != protoFuncs['constructor_']) ? protoFuncs['constructor_'] : function() { 683 }; 684 } else { 685 constr = function() { 686 }; 687 } 688 689 if (!_T.reserveNamespace(newCls, constr)) { 690 return null; 691 } 692 newCls = _T.fetchNamespace(newCls); 693 return newCls; 694 }; 695 696 this._applyFuncs = function (newCls, funcs, proto) { 697 if (funcs) { 698 for (var key in funcs) { 699 //constructor already passed, callSuper already assigned 700 if ('undefined' == typeof key || null == key || key == "_callSuper") { 701 continue; 702 } 703 if (!proto) 704 newCls[key] = funcs[key]; 705 else 706 newCls.prototype[key] = funcs[key]; 707 } 708 } 709 }; 710 711 /** 712 * general type assertion routine 713 * 714 * @param probe the probe to be checked for the correct type 715 * @param theType the type to be checked for 716 */ 717 this.assertType = function(probe, theType) { 718 return _T.isString(theType) ? probe == typeof theType : probe instanceof theType; 719 }; 720 721 /** 722 * onload wrapper for chaining the onload cleanly 723 * @param func the function which should be added to the load 724 * chain (note we cannot rely on return values here, hence faces.util.chain will fail) 725 */ 726 this.addOnLoad = function(target, func) { 727 var oldonload = (target) ? target.onload : null; 728 target.onload = (!oldonload) ? func : function() { 729 try { 730 oldonload(); 731 } catch (e) { 732 throw e; 733 } finally { 734 func(); 735 } 736 }; 737 }; 738 739 /** 740 * returns the internationalisation setting 741 * for the given browser so that 742 * we can i18n our messages 743 * 744 * @returns a map with following entires: 745 * <ul> 746 * <li>language: the lowercase language iso code</li> 747 * <li>variant: the uppercase variant iso code</li> 748 * </ul> 749 * null is returned if the browser fails to determine the language settings 750 */ 751 this.getLanguage = function(lOverride) { 752 var deflt = {language: "en", variant: "UK"}; //default language and variant 753 try { 754 var lang = lOverride || navigator.language || navigator.browserLanguage; 755 if (!lang || lang.length < 2) return deflt; 756 return { 757 language: lang.substr(0, 2), 758 variant: (lang.length >= 5) ? lang.substr(3, 5) : null 759 }; 760 } catch(e) { 761 return deflt; 762 } 763 }; 764 765 //implemented in extruntime 766 this.singletonDelegateObj = function() {}; 767 768 /** 769 * browser detection code 770 * cross ported from dojo 1.2 771 * 772 * dojos browser detection code is very sophisticated 773 * hence we port it over it allows a very fine grained detection of 774 * browsers including the version number 775 * this however only can work out if the user 776 * does not alter the user agent, which they normally dont! 777 * 778 * the exception is the ie detection which relies on specific quirks in ie 779 * 780 * TODO check if the browser detection still is needed 781 * for 2.3 since our baseline will be IE11 most likely not 782 */ 783 var n = navigator; 784 var dua = n.userAgent, 785 dav = n.appVersion, 786 tv = parseFloat(dav); 787 var _T = this; 788 _T.browser = {}; 789 myfaces._impl.core._EvalHandlers.browser = _T.browser; 790 var d = _T.browser; 791 792 if (dua.indexOf("Opera") >= 0) { 793 _T.isOpera = tv; 794 } 795 if (dua.indexOf("AdobeAIR") >= 0) { 796 d.isAIR = 1; 797 } 798 if (dua.indexOf("BlackBerry") >= 0) { 799 d.isBlackBerry = tv; 800 } 801 d.isKhtml = (dav.indexOf("Konqueror") >= 0) ? tv : 0; 802 d.isWebKit = parseFloat(dua.split("WebKit/")[1]) || undefined; 803 d.isChrome = parseFloat(dua.split("Chrome/")[1]) || undefined; 804 805 // safari detection derived from: 806 // http://developer.apple.com/internet/safari/faq.html#anchor2 807 // http://developer.apple.com/internet/safari/uamatrix.html 808 var index = Math.max(dav.indexOf("WebKit"), dav.indexOf("Safari"), 0); 809 if (index && !d.isChrome) { 810 // try to grab the explicit Safari version first. If we don't get 811 // one, look for less than 419.3 as the indication that we're on something 812 // "Safari 2-ish". 813 d.isSafari = parseFloat(dav.split("Version/")[1]); 814 if (!d.isSafari || parseFloat(dav.substr(index + 7)) <= 419.3) { 815 d.isSafari = 2; 816 } 817 } 818 819 //>>excludeStart("webkitMobile", kwArgs.webkitMobile); 820 821 if (dua.indexOf("Gecko") >= 0 && !d.isKhtml && !d.isWebKit) { 822 d.isMozilla = d.isMoz = tv; 823 } 824 if (d.isMoz) { 825 //We really need to get away from _T. Consider a sane isGecko approach for the future. 826 d.isFF = parseFloat(dua.split("Firefox/")[1] || dua.split("Minefield/")[1] || dua.split("Shiretoko/")[1]) || undefined; 827 } 828 829 if (document.all && !d.isOpera && !d.isBlackBerry) { 830 d.isIE = parseFloat(dav.split("MSIE ")[1]) || undefined; 831 d.isIEMobile = parseFloat(dua.split("IEMobile")[1]); 832 //In cases where the page has an HTTP header or META tag with 833 //X-UA-Compatible, then it is in emulation mode, for a previous 834 //version. Make sure isIE reflects the desired version. 835 //document.documentMode of 5 means quirks mode. 836 837 /** @namespace document.documentMode */ 838 if (d.isIE >= 8 && document.documentMode != 5) { 839 d.isIE = document.documentMode; 840 } 841 } 842 }; 843 } 844 845