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