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 theoretically we could save some code 18 by 19 defining the parent object as 20 var parent = new Object(); 21 parent.prototype = new myfaces._impl.core._Runtime(); 22 extendClass(function () { 23 }, parent , { 24 But for now we are not doing it the little bit of saved 25 space is not worth the loss of readability 26 */ 27 /** 28 * @memberOf myfaces._impl 29 * @namespace 30 * @name _util 31 */ 32 /** 33 * @class 34 * @name _Lang 35 * @memberOf myfaces._impl._util 36 * @extends myfaces._impl.core._Runtime 37 * @namespace 38 * @description Object singleton for Language related methods, this object singleton 39 * decorates the namespace myfaces._impl.core._Runtime and adds a bunch of new methods to 40 * what _Runtime provided 41 * */ 42 _MF_SINGLTN(_PFX_UTIL + "_Lang", Object, /** @lends myfaces._impl._util._Lang.prototype */ { 43 _processedExceptions:{}, 44 _installedLocale:null, 45 _RT:myfaces._impl.core._Runtime, 46 /** 47 * returns a given localized message upon a given key 48 * basic java log like templating functionality is included 49 * 50 * @param {String} key the key for the message 51 * @param {String} defaultMessage optional default message if none was found 52 * 53 * Additionally you can pass additional arguments, which are used 54 * in the same way java log templates use the params 55 * 56 * @param key 57 */ 58 getMessage:function (key, defaultMessage /*,vararg templateParams*/) { 59 if (!this._installedLocale) { 60 //we first try to install language and variant, if that one fails 61 //we try to install the language only, and if that one fails 62 //we install the base messages 63 this.initLocale(); 64 } 65 var msg = this._installedLocale[key] || defaultMessage || key + " - undefined message"; 66 //we now make a simple templating replace of {0}, {1} etc... with their corresponding 67 //arguments 68 for (var cnt = 2; cnt < arguments.length; cnt++) { 69 msg = msg.replace(new RegExp(["\\{", cnt - 2, "\\}"].join(""), "g"), new String(arguments[cnt])); 70 } 71 return msg; 72 }, 73 /** 74 * (re)inits the currently installed 75 * messages so that after loading the main scripts 76 * a new locale can be installed optionally 77 * to our i18n subsystem 78 * 79 * @param newLocale locale override 80 */ 81 initLocale:function (newLocale) { 82 if (newLocale) { 83 this._installedLocale = new newLocale(); 84 return; 85 } 86 var language_Variant = this._RT.getLanguage(this._RT.getGlobalConfig("locale")), 87 langStr = language_Variant ? language_Variant.language : "", 88 variantStr = language_Variant ? [language_Variant.language, "_", language_Variant.variant || ""].join("") : "", 89 i18nRoot = myfaces._impl.i18n, i18nHolder = i18nRoot["Messages_" + variantStr] || i18nRoot["Messages_" + langStr] || i18nRoot["Messages"]; 90 this._installedLocale = new i18nHolder(); 91 }, 92 assertType:function (probe, theType) { 93 return this._RT.assertType(probe, theType); 94 }, 95 exists:function (nms, theType) { 96 return this._RT.exists(nms, theType); 97 }, 98 fetchNamespace:function (namespace) { 99 this._assertStr(namespace, "fetchNamespace", "namespace"); 100 return this._RT.fetchNamespace(namespace); 101 }, 102 reserveNamespace:function (namespace) { 103 this._assertStr(namespace, "reserveNamespace", "namespace"); 104 return this._RT.reserveNamespace(namespace); 105 }, 106 globalEval:function (code) { 107 this._assertStr(code, "globalEval", "code"); 108 return this._RT.globalEval(code); 109 }, 110 /** 111 * determines the correct event depending 112 * on the browsers state 113 * 114 * @param evt incoming event object (note not all browsers 115 * have this) 116 * 117 * @return an event object no matter what is incoming 118 */ 119 getEvent:function (evt) { 120 evt = (!evt) ? window.event || {} : evt; 121 return evt; 122 }, 123 /** 124 * cross port from the dojo lib 125 * browser save event resolution 126 * @param evt the event object 127 * (with a fallback for ie events if none is present) 128 */ 129 getEventTarget:function (evt) { 130 //ie6 and 7 fallback 131 evt = this.getEvent(evt); 132 /** 133 * evt source is defined in the faces events 134 * seems like some component authors use our code 135 * so we add it here see also 136 * https://issues.apache.org/jira/browse/MYFACES-2458 137 * not entirely a bug but makes sense to add this 138 * behavior. I dont use it that way but nevertheless it 139 * does not break anything so why not 140 * */ 141 var t = evt.srcElement || evt.target || evt.source || null; 142 while ((t) && (t.nodeType != 1)) { 143 t = t.parentNode; 144 } 145 return t; 146 }, 147 148 /** 149 * equalsIgnoreCase, case insensitive comparison of two strings 150 * 151 * @param source 152 * @param destination 153 */ 154 equalsIgnoreCase:function (source, destination) { 155 //either both are not set or null 156 if (!source && !destination) { 157 return true; 158 } 159 //source or dest is set while the other is not 160 if (!source || !destination) return false; 161 //in any other case we do a strong string comparison 162 return source.toLowerCase() === destination.toLowerCase(); 163 }, 164 165 /** 166 * Save document.getElementById (this code was ported over from dojo) 167 * the idea is that either a string or domNode can be passed 168 * @param {Object} reference the reference which has to be byIded 169 */ 170 byId:function (/*object*/ reference) { 171 if (!reference) { 172 throw this.makeException(new Error(), null, null, this._nameSpace, "byId", this.getMessage("ERR_REF_OR_ID", null, "_Lang.byId", "reference")); 173 } 174 return (this.isString(reference)) ? document.getElementById(reference) : reference; 175 }, 176 177 /** 178 * String to array function performs a string to array transformation 179 * @param {String} it the string which has to be changed into an array 180 * @param {RegExp} splitter our splitter reglar expression 181 * @return an array of the splitted string 182 */ 183 strToArray:function (/*string*/ it, /*regexp*/ splitter) { 184 // summary: 185 // Return true if it is a String 186 this._assertStr(it, "strToArray", "it"); 187 if (!splitter) { 188 throw this.makeException(new Error(), null, null, this._nameSpace, "strToArray", this.getMessage("ERR_PARAM_STR_RE", null, "myfaces._impl._util._Lang.strToArray", "splitter")); 189 } 190 var retArr = it.split(splitter); 191 var len = retArr.length; 192 for (var cnt = 0; cnt < len; cnt++) { 193 retArr[cnt] = this.trim(retArr[cnt]); 194 } 195 return retArr; 196 }, 197 _assertStr:function (it, functionName, paramName) { 198 if (!this.isString(it)) { 199 throw this.makeException(new Error(), null, null, this._nameSpace, arguments.caller.toString(), this.getMessage("ERR_PARAM_STR", null, "myfaces._impl._util._Lang." + functionName, paramName)); 200 } 201 }, 202 /** 203 * hyperfast trim 204 * http://blog.stevenlevithan.com/archives/faster-trim-javascript 205 * crossported from dojo 206 */ 207 trim:function (/*string*/ str) { 208 this._assertStr(str, "trim", "str"); 209 str = str.replace(/^\s\s*/, ''); 210 var ws = /\s/, i = str.length; 211 212 while (ws.test(str.charAt(--i))) { 213 //do nothing 214 } 215 return str.slice(0, i + 1); 216 }, 217 218 /** 219 * a fuzzy match where one item is subset of the other or vice versa 220 * @param str1 221 * @param str2 222 * @returns {boolean} 223 */ 224 match: function(str1, str2) { 225 //Sometimes we have to deal with paths in hrefs so 226 //one of the itmes either is an exact match or a substring 227 str1 = this.trim(str1 || ""); 228 str2 = this.trim(str2 || ""); 229 230 return str1.indexOf(str2) != -1 || str2.indexOf(str1) != -1; 231 }, 232 233 /** 234 * Backported from dojo 235 * a failsafe string determination method 236 * (since in javascript String != "" typeof alone fails!) 237 * @param it {|Object|} the object to be checked for being a string 238 * @return true in case of being a string false otherwise 239 */ 240 isString:function (/*anything*/ it) { 241 // summary: 242 // Return true if it is a String 243 return !!arguments.length && it != null && (typeof it == "string" || it instanceof String); // Boolean 244 }, 245 /** 246 * hitch backported from dojo 247 * hitch allows to assign a function to a dedicated scope 248 * this is helpful in situations when function reassignments 249 * can happen 250 * (notably happens often in lazy xhr code) 251 * 252 * @param {Function} scope of the function to be executed in 253 * @param {Function} method to be executed, the method must be of type function 254 * 255 * @return whatever the executed method returns 256 */ 257 hitch:function (scope, method) { 258 return !scope ? method : function () { 259 return method.apply(scope, arguments || []); 260 }; // Function 261 }, 262 /** 263 * Helper function to merge two maps 264 * into one 265 * @param {Object} dest the destination map 266 * @param {Object} src the source map 267 * @param {boolean} overwrite if set to true the destination is overwritten if the keys exist in both maps 268 **/ 269 mixMaps:function (dest, src, overwrite, blockFilter, allowlistFilter) { 270 if (!dest || !src) { 271 throw this.makeException(new Error(), null, null, this._nameSpace, "mixMaps", this.getMessage("ERR_PARAM_MIXMAPS", null, "_Lang.mixMaps")); 272 } 273 var _undef = "undefined"; 274 for (var key in src) { 275 if (!src.hasOwnProperty(key)) continue; 276 if (blockFilter && blockFilter[key]) { 277 continue; 278 } 279 if (allowlistFilter && !allowlistFilter[key]) { 280 continue; 281 } 282 if (!overwrite) { 283 /** 284 *we use exists instead of booleans because we cannot rely 285 *on all values being non boolean, we would need an elvis 286 *operator in javascript to shorten this :-( 287 */ 288 dest[key] = (_undef != typeof dest[key]) ? dest[key] : src[key]; 289 } else { 290 dest[key] = (_undef != typeof src[key]) ? src[key] : dest[key]; 291 } 292 } 293 return dest; 294 }, 295 /** 296 * checks if an array contains an element 297 * @param {Array} arr array 298 * @param {String} str string to check for 299 */ 300 contains:function (arr, str) { 301 if (!arr || !str) { 302 throw this.makeException(new Error(), null, null, this._nameSpace, "contains", this.getMessage("ERR_MUST_BE_PROVIDED", null, "_Lang.contains", "arr {array}", "str {string}")); 303 } 304 return this.arrIndexOf(arr, str) != -1; 305 }, 306 arrToMap:function (arr, offset) { 307 var ret = new Array(arr.length); 308 var len = arr.length; 309 offset = (offset) ? offset : 0; 310 for (var cnt = 0; cnt < len; cnt++) { 311 ret[arr[cnt]] = cnt + offset; 312 } 313 return ret; 314 }, 315 objToArray:function (obj, offset, pack) { 316 if (!obj) { 317 return null; 318 } 319 //since offset is numeric we cannot use the shortcut due to 0 being false 320 //special condition array delivered no offset no pack 321 if (obj instanceof Array && !offset && !pack) return obj; 322 var finalOffset = ('undefined' != typeof offset || null != offset) ? offset : 0; 323 var finalPack = pack || []; 324 try { 325 return finalPack.concat(Array.prototype.slice.call(obj, finalOffset)); 326 } catch (e) { 327 //ie8 (again as only browser) delivers for css 3 selectors a non convertible object 328 //we have to do it the hard way 329 //ie8 seems generally a little bit strange in its behavior some 330 //objects break the function is everything methodology of javascript 331 //and do not implement apply call, or are pseudo arrays which cannot 332 //be sliced 333 for (var cnt = finalOffset; cnt < obj.length; cnt++) { 334 finalPack.push(obj[cnt]); 335 } 336 return finalPack; 337 } 338 }, 339 /** 340 * foreach implementation utilizing the 341 * ECMAScript wherever possible 342 * with added functionality 343 * 344 * @param arr the array to filter 345 * @param func the closure to apply the function to, with the syntax defined by the ecmascript functionality 346 * function (element<,key, array>) 347 * <p /> 348 * optional params 349 * <p /> 350 * <ul> 351 * <li>param startPos (optional) the starting position </li> 352 * <li>param scope (optional) the scope to apply the closure to </li> 353 * </ul> 354 */ 355 arrForEach:function (arr, func, startPos, scope) { 356 if (!arr || !arr.length) return; 357 var start = startPos || 0; 358 var thisObj = scope || arr; 359 //check for an existing foreach mapping on array prototypes 360 //IE9 still does not pass array objects as result for dom ops 361 arr = this.objToArray(arr); 362 (start) ? arr.slice(start).forEach(func, thisObj) : arr.forEach(func, thisObj); 363 }, 364 /** 365 * foreach implementation utilizing the 366 * ECMAScript wherever possible 367 * with added functionality 368 * 369 * @param arr the array to filter 370 * @param func the closure to apply the function to, with the syntax defined by the ecmascript functionality 371 * function (element<,key, array>) 372 * <p /> 373 * additional params 374 * <ul> 375 * <li> startPos (optional) the starting position</li> 376 * <li> scope (optional) the scope to apply the closure to</li> 377 * </ul> 378 */ 379 arrFilter:function (arr, func, startPos, scope) { 380 if (!arr || !arr.length) return []; 381 var start = startPos || 0; 382 var thisObj = scope || arr; 383 arr = this.objToArray(arr); 384 return ((start) ? arr.slice(start).filter(func, thisObj) : arr.filter(func, thisObj)); 385 }, 386 /** 387 * adds a EcmaScript optimized indexOf to our mix, 388 * checks for the presence of an indexOf functionality 389 * and applies it, otherwise uses a fallback to the hold 390 * loop method to determine the index 391 * 392 * @param arr the array 393 * @param element the index to search for 394 */ 395 arrIndexOf:function (arr, element /*fromIndex*/) { 396 if (!arr || !arr.length) return -1; 397 var pos = Number(arguments[2]) || 0; 398 arr = this.objToArray(arr); 399 return arr.indexOf(element, pos); 400 }, 401 /** 402 * helper to automatically apply a delivered arguments map or array 403 * to its destination which has a field "_"<key> and a full field 404 * 405 * @param dest the destination object 406 * @param args the arguments array or map 407 * @param argNames the argument names to be transferred 408 */ 409 applyArgs:function (dest, args, argNames) { 410 var UDEF = 'undefined'; 411 if (argNames) { 412 for (var cnt = 0; cnt < args.length; cnt++) { 413 //dest can be null or 0 hence no shortcut 414 if (UDEF != typeof dest["_" + argNames[cnt]]) { 415 dest["_" + argNames[cnt]] = args[cnt]; 416 } 417 if (UDEF != typeof dest[ argNames[cnt]]) { 418 dest[argNames[cnt]] = args[cnt]; 419 } 420 } 421 } else { 422 for (var key in args) { 423 if (!args.hasOwnProperty(key)) continue; 424 if (UDEF != typeof dest["_" + key]) { 425 dest["_" + key] = args[key]; 426 } 427 if (UDEF != typeof dest[key]) { 428 dest[key] = args[key]; 429 } 430 } 431 } 432 }, 433 434 /** 435 * transforms a key value pair into a string 436 * @param key the key 437 * @param val the value 438 * @param delimiter the delimiter 439 */ 440 keyValToStr:function (key, val, delimiter) { 441 var ret = [], pushRet = this.hitch(ret, ret.push); 442 pushRet(key); 443 pushRet(val); 444 delimiter = delimiter || "\n"; 445 pushRet(delimiter); 446 return ret.join(""); 447 }, 448 parseXML:function (txt) { 449 try { 450 var parser = new DOMParser(); 451 return parser.parseFromString(txt, "text/xml"); 452 } catch (e) { 453 //undefined internal parser error 454 return null; 455 } 456 }, 457 serializeXML:function (xmlNode, escape) { 458 if (!escape) { 459 if (xmlNode.data) return xmlNode.data; //CDATA block has raw data 460 if (xmlNode.textContent) return xmlNode.textContent; //textNode has textContent 461 } 462 return (new XMLSerializer()).serializeToString(xmlNode); 463 }, 464 serializeChilds:function (xmlNode) { 465 var buffer = []; 466 if (!xmlNode.childNodes) return ""; 467 for (var cnt = 0; cnt < xmlNode.childNodes.length; cnt++) { 468 buffer.push(this.serializeXML(xmlNode.childNodes[cnt])); 469 } 470 return buffer.join(""); 471 }, 472 isXMLParseError:function (xmlContent) { 473 //no xml content 474 if (xmlContent == null) return true; 475 var findParseError = function (node) { 476 if (!node || !node.childNodes) return false; 477 for (var cnt = 0; cnt < node.childNodes.length; cnt++) { 478 var childNode = node.childNodes[cnt]; 479 if (childNode.tagName && childNode.tagName == "parsererror") return true; 480 } 481 return false; 482 }; 483 return !xmlContent || 484 (this.exists(xmlContent, "parseError.errorCode") && xmlContent.parseError.errorCode != 0) || 485 findParseError(xmlContent); 486 }, 487 /** 488 * fetches the error message from the xml content 489 * in a browser independent way 490 * 491 * @param xmlContent 492 * @return a map with the following structure {errorMessage: the error Message, sourceText: the text with the error} 493 */ 494 fetchXMLErrorMessage:function (text, xmlContent) { 495 var _t = this; 496 var findParseError = function (node) { 497 if (!node || !node.childNodes) return false; 498 for (var cnt = 0; cnt < node.childNodes.length; cnt++) { 499 var childNode = node.childNodes[cnt]; 500 if (childNode.tagName && childNode.tagName == "parsererror") { 501 var errorMessage = _t.serializeXML(childNode.childNodes[0]); 502 //we now have to determine the row and column position 503 var lastLine = errorMessage.split("\n"); 504 lastLine = lastLine[lastLine.length-1]; 505 var positions = lastLine.match(/[^0-9]*([0-9]+)[^0-9]*([0-9]+)[^0-9]*/); 506 507 var ret = { 508 errorMessage: errorMessage, 509 sourceText: _t.serializeXML(childNode.childNodes[1].childNodes[0]) 510 } 511 if(positions) { 512 ret.line = Math.max(0, parseInt(positions[1])-1); 513 ret.linePos = Math.max(0, parseInt(positions[2])-1); 514 } 515 return ret; 516 } 517 } 518 return null; 519 }; 520 var ret = null; 521 if (!xmlContent) { 522 //chrome does not deliver any further data 523 ret = (this.trim(text || "").length > 0)? {errorMessage:"Illegal response",sourceText:""} : {errorMessage:"Empty Response",sourceText:""}; 524 } else if (this.exists(xmlContent, "parseError.errorCode") && xmlContent.parseError.errorCode != 0) { 525 ret = { 526 errorMessage:xmlContent.parseError.reason, 527 line:Math.max(0, parseInt(xmlContent.parseError.line)-1), 528 linePos:Math.max(0,parseInt(xmlContent.parseError.linepos) -1), 529 sourceText:xmlContent.parseError.srcText 530 }; 531 } else { 532 ret = findParseError(xmlContent); 533 } 534 //we have a line number we now can format the source accordingly 535 if(ret && 'undefined' != typeof ret.line) { 536 var source = ret.sourceText ||""; 537 source = source.split("\n"); 538 if(source.length-1 < ret.line) return ret; 539 source = source[ret.line]; 540 var secondLine = []; 541 var lineLen = (ret.linePos - 2); 542 for(var cnt = 0; cnt < lineLen; cnt++) { 543 secondLine.push(" "); 544 } 545 secondLine.push("^^"); 546 ret.sourceText = source; 547 ret.visualError = secondLine; 548 } 549 return ret; 550 }, 551 552 /** 553 * creates a neutral form data wrapper over an existing form Data element 554 * the wrapper delegates following methods, append 555 * and adds makeFinal as finalizing method which returns the final 556 * send representation of the element 557 * 558 * @param formData an array 559 */ 560 createFormDataDecorator:function (formData) { 561 //we simulate the dom level 2 form element here 562 var _newCls = null; 563 var bufInstance = null; 564 if (!this.FormDataDecoratorArray) { 565 this.FormDataDecoratorArray = function (theFormData) { 566 this._valBuf = theFormData; 567 this._idx = {}; 568 }; 569 _newCls = this.FormDataDecoratorArray; 570 _newCls.prototype.append = function (key, val) { 571 this._valBuf.push([encodeURIComponent(key), encodeURIComponent(val)].join("=")); 572 this._idx[key] = true; 573 }; 574 _newCls.prototype.hasKey = function (key) { 575 return !!this._idx[key]; 576 }; 577 _newCls.prototype.makeFinal = function () { 578 return this._valBuf.join("&"); 579 }; 580 } 581 if (!this.FormDataDecoratorString) { 582 this.FormDataDecoratorString = function (theFormData) { 583 this._preprocessedData = theFormData; 584 this._valBuf = []; 585 this._idx = {}; 586 }; 587 _newCls = this.FormDataDecoratorString; 588 _newCls.prototype.append = function (key, val) { 589 this._valBuf.push([encodeURIComponent(key), encodeURIComponent(val)].join("=")); 590 this._idx[key] = true; 591 }; 592 //for now we check only for keys which are added subsequently otherwise we do not perform any checks 593 _newCls.prototype.hasKey = function (key) { 594 return !!this._idx[key]; 595 }; 596 _newCls.prototype.makeFinal = function () { 597 if (this._preprocessedData != "") { 598 return this._preprocessedData + "&" + this._valBuf.join("&") 599 } else { 600 return this._valBuf.join("&"); 601 } 602 }; 603 } 604 if (!this.FormDataDecoratorOther) { 605 this.FormDataDecoratorOther = function (theFormData) { 606 this._valBuf = theFormData || []; 607 this._idx = {}; 608 }; 609 _newCls = this.FormDataDecoratorOther; 610 _newCls.prototype.append = function (key, val) { 611 this._valBuf.push([encodeURIComponent(key), encodeURIComponent(val)]); 612 this._idx[key] = true; 613 }; 614 _newCls.prototype.hasKey = function (key) { 615 return !!this._idx[key]; 616 }; 617 _newCls.prototype.makeFinal = function () { 618 return this._valBuf; 619 }; 620 } 621 if (formData instanceof Array) { 622 bufInstance = new this.FormDataDecoratorArray(formData); 623 } else if (this.isString(formData)) { 624 bufInstance = new this.FormDataDecoratorString(formData); 625 } else { 626 bufInstance = new this.FormDataDecoratorOther(formData); 627 } 628 return bufInstance; 629 }, 630 /** 631 * define a property mechanism which is browser neutral 632 * we cannot use the existing setter and getter mechanisms 633 * for now because old browsers do not support them 634 * in the long run we probably can switch over 635 * or make a code split between legacy and new 636 * 637 * 638 * @param obj 639 * @param name 640 * @param value 641 */ 642 attr:function (obj, name, value) { 643 var findAccessor = function (theObj, theName) { 644 return (theObj["_" + theName]) ? "_" + theName : ( (theObj[theName]) ? theName : null) 645 }; 646 var applyAttr = function (theObj, theName, value, isFunc) { 647 if (value) { 648 if (isFunc) { 649 theObj[theName](value); 650 } else { 651 theObj[theName] = value; 652 } 653 return null; 654 } 655 return (isFunc) ? theObj[theName]() : theObj[theName]; 656 }; 657 try { 658 var finalAttr = findAccessor(obj, name); 659 //simple attibute no setter and getter overrides 660 if (finalAttr) { 661 return applyAttr(obj, finalAttr, value); 662 } 663 //lets check for setter and getter overrides 664 var found = false; 665 var prefix = (value) ? "set" : "get"; 666 finalAttr = [prefix, name.substr(0, 1).toUpperCase(), name.substr(1)].join(""); 667 finalAttr = findAccessor(obj, finalAttr); 668 if (finalAttr) { 669 return applyAttr(obj, finalAttr, value, true); 670 } 671 672 throw this.makeException(new Error(), null, null, this._nameSpace, "contains", "property " + name + " not found"); 673 } finally { 674 findAccessor = null; 675 applyAttr = null; 676 } 677 }, 678 679 /** 680 * creates an exeption with additional internal parameters 681 * for extra information 682 * 683 * @param {String} title the exception title 684 * @param {String} name the exception name 685 * @param {String} callerCls the caller class 686 * @param {String} callFunc the caller function 687 * @param {String} message the message for the exception 688 */ 689 makeException:function (error, title, name, callerCls, callFunc, message) { 690 error.name = name || "clientError"; 691 error.title = title || ""; 692 error.message = message || ""; 693 error._mfInternal = {}; 694 error._mfInternal.name = name || "clientError"; 695 error._mfInternal.title = title || "clientError"; 696 error._mfInternal.caller = callerCls || this._nameSpace; 697 error._mfInternal.callFunc = callFunc || ("" + arguments.caller.toString()); 698 return error; 699 } 700 }); 701