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 * @class 19 * @name Impl 20 * @memberOf myfaces._impl.core 21 * @description Implementation singleton which implements all interface method 22 * defined by our jsf.js API 23 * */ 24 _MF_SINGLTN(_PFX_CORE + "Impl", _MF_OBJECT, /** @lends myfaces._impl.core.Impl.prototype */ { 25 26 //third option myfaces._impl.xhrCoreAjax which will be the new core impl for now 27 _transport : myfaces._impl.core._Runtime.getGlobalConfig("transport", myfaces._impl.xhrCore._Transports), 28 29 /** 30 * external event listener queue! 31 */ 32 _evtListeners : new (myfaces._impl.core._Runtime.getGlobalConfig("eventListenerQueue", myfaces._impl._util._ListenerQueue))(), 33 34 /** 35 * external error listener queue! 36 */ 37 _errListeners : new (myfaces._impl.core._Runtime.getGlobalConfig("errorListenerQueue", myfaces._impl._util._ListenerQueue))(), 38 39 /*CONSTANTS*/ 40 41 /*internal identifiers for options*/ 42 IDENT_ALL: "@all", 43 IDENT_NONE: "@none", 44 IDENT_THIS: "@this", 45 IDENT_FORM: "@form", 46 47 /* 48 * [STATIC] constants 49 */ 50 51 P_PARTIAL_SOURCE: "javax.faces.source", 52 P_VIEWSTATE: "javax.faces.ViewState", 53 P_AJAX: "javax.faces.partial.ajax", 54 P_EXECUTE: "javax.faces.partial.execute", 55 P_RENDER: "javax.faces.partial.render", 56 P_EVT: "javax.faces.partial.event", 57 58 /* message types */ 59 ERROR: "error", 60 EVENT: "event", 61 62 /* event emitting stages */ 63 BEGIN: "begin", 64 COMPLETE: "complete", 65 SUCCESS: "success", 66 67 /*ajax errors spec 14.4.2*/ 68 HTTPERROR: "httpError", 69 EMPTY_RESPONSE: "emptyResponse", 70 MALFORMEDXML: "malformedXML", 71 SERVER_ERROR: "serverError", 72 CLIENT_ERROR: "clientError", 73 TIMEOUT_EVENT: "timeout", 74 75 76 /*error reporting threshold*/ 77 _threshold: "ERROR", 78 79 /*blockfilter for the passthrough filtering, the attributes given here 80 * will not be transmitted from the options into the passthrough*/ 81 _BLOCKFILTER: {onerror: 1, onevent: 1, render: 1, execute: 1, myfaces: 1}, 82 83 84 85 /** 86 * collect and encode data for a given form element (must be of type form) 87 * find the javax.faces.ViewState element and encode its value as well! 88 * return a concatenated string of the encoded values! 89 * 90 * @throws Error in case of the given element not being of type form! 91 * https://issues.apache.org/jira/browse/MYFACES-2110 92 */ 93 getViewState : function(form) { 94 /** 95 * typecheck assert!, we opt for strong typing here 96 * because it makes it easier to detect bugs 97 */ 98 if (form) { 99 form = this._Lang.byId(form); 100 } 101 102 if (!form 103 || !form.nodeName 104 || form.nodeName.toLowerCase() != "form") { 105 throw new Error(this._Lang.getMessage("ERR_VIEWSTATE")); 106 } 107 108 var ajaxUtils = myfaces._impl.xhrCore._AjaxUtils; 109 110 var ret = this._Lang.createFormDataDecorator([]); 111 ajaxUtils.encodeSubmittableFields(ret, form, null); 112 113 return ret.makeFinal(); 114 }, 115 116 /** 117 * this function has to send the ajax requests 118 * 119 * following request conditions must be met: 120 * <ul> 121 * <li> the request must be sent asynchronously! </li> 122 * <li> the request must be a POST!!! request </li> 123 * <li> the request url must be the form action attribute </li> 124 * <li> all requests must be queued with a client side request queue to ensure the request ordering!</li> 125 * </ul> 126 * 127 * @param {String|Node} elem any dom element no matter being it html or jsf, from which the event is emitted 128 * @param {|Event|} event any javascript event supported by that object 129 * @param {|Object|} options map of options being pushed into the ajax cycle 130 * 131 * 132 * a) transformArguments out of the function 133 * b) passThrough handling with a map copy with a filter map block map 134 */ 135 request : function(elem, event, options) { 136 if(this._delayTimeout) { 137 clearTimeout(this._delayTimeout); 138 delete this._delayTimeout; 139 } 140 /*namespace remap for our local function context we mix the entire function namespace into 141 *a local function variable so that we do not have to write the entire namespace 142 *all the time 143 **/ 144 var _Lang = this._Lang, 145 _Dom = this._Dom, 146 WINDOW_ID = "javax.faces.windowId"; 147 /*assert if the onerror is set and once if it is set it must be of type function*/ 148 _Lang.assertType(options.onerror, "function"); 149 /*assert if the onevent is set and once if it is set it must be of type function*/ 150 _Lang.assertType(options.onevent, "function"); 151 152 //options not set we define a default one with nothing 153 options = options || {}; 154 155 /*preparations for jsf 2.2 windowid handling*/ 156 //pass the window id into the options if not set already 157 if (!options.windowId) { 158 var windowId = _Dom.getWindowId(); 159 (windowId) ? options[WINDOW_ID] = windowId : null; 160 } else { 161 options[WINDOW_ID] = options.windowId; 162 delete options.windowId; 163 } 164 165 /** 166 * we cross reference statically hence the mapping here 167 * the entire mapping between the functions is stateless 168 */ 169 //null definitely means no event passed down so we skip the ie specific checks 170 if ('undefined' == typeof event) { 171 event = window.event || null; 172 } 173 174 //improve the error messages if an empty elem is passed 175 if(!elem) { 176 throw _Lang.makeException(new Error(), "ArgNotSet", null, this._nameSpace, "request", _Lang.getMessage("ERR_MUST_BE_PROVIDED1","{0}: source must be provided","jsf.ajax.request", "source element id")); 177 } 178 var oldElem = elem; 179 elem = _Dom.byIdOrName(elem); 180 if(!elem) { 181 throw _Lang.makeException(new Error(), "Notfound", null, this._nameSpace, "request", _Lang.getMessage("ERR_PPR_UNKNOWNCID","{0}: Node with id {1} could not be found from source",this._nameSpace+".request", oldElem)); 182 } 183 184 var elementId = _Dom.nodeIdOrName(elem); 185 186 /* 187 * We make a copy of our options because 188 * we should not touch the incoming params! 189 */ 190 var passThrgh = _Lang.mixMaps({}, options, true, this._BLOCKFILTER); 191 192 if (event) { 193 passThrgh[this.P_EVT] = event.type; 194 } 195 196 /** 197 * ajax pass through context with the source 198 * onevent and onerror 199 */ 200 var context = { 201 source: elem, 202 onevent: options.onevent, 203 onerror: options.onerror, 204 205 //TODO move the myfaces part into the _mfInternal part 206 myfaces: options.myfaces 207 }; 208 209 /** 210 * fetch the parent form 211 * 212 * note we also add an override possibility here 213 * so that people can use dummy forms and work 214 * with detached objects 215 */ 216 var form = (options.myfaces && options.myfaces.form) ? 217 _Lang.byId(options.myfaces.form) : 218 this._getForm(elem, event); 219 220 /** 221 * binding contract the javax.faces.source must be set 222 */ 223 passThrgh[this.P_PARTIAL_SOURCE] = elementId; 224 225 /** 226 * javax.faces.partial.ajax must be set to true 227 */ 228 passThrgh[this.P_AJAX] = true; 229 230 if (options.execute) { 231 /*the options must be a blank delimited list of strings*/ 232 /*compliance with Mojarra which automatically adds @this to an execute 233 * the spec rev 2.0a however states, if none is issued nothing at all should be sent down 234 */ 235 if(options.execute.indexOf("@this") == -1) { 236 options.execute = options.execute + " @this"; 237 } 238 this._transformList(passThrgh, this.P_EXECUTE, options.execute, form, elementId); 239 } else { 240 passThrgh[this.P_EXECUTE] = elementId; 241 } 242 243 if (options.render) { 244 this._transformList(passThrgh, this.P_RENDER, options.render, form, elementId); 245 } 246 247 /** 248 * multiple transports upcoming jsf 2.x feature currently allowed 249 * default (no value) xhrQueuedPost 250 * 251 * xhrQueuedPost 252 * xhrPost 253 * xhrGet 254 * xhrQueuedGet 255 * iframePost 256 * iframeQueuedPost 257 * 258 */ 259 var transportType = this._getTransportType(context, passThrgh, form); 260 261 //additional meta information to speed things up, note internal non jsf 262 //pass through options are stored under _mfInternal in the context 263 context._mfInternal = {}; 264 var mfInternal = context._mfInternal; 265 266 mfInternal["_mfSourceFormId"] = form.id; 267 mfInternal["_mfSourceControlId"] = elementId; 268 mfInternal["_mfTransportType"] = transportType; 269 270 //mojarra compatibility, mojarra is sending the form id as well 271 //this is not documented behavior but can be determined by running 272 //mojarra under blackbox conditions 273 //i assume it does the same as our formId_submit=1 so leaving it out 274 //wont hurt but for the sake of compatibility we are going to add it 275 passThrgh[form.id] = form.id; 276 277 //delay handling is an experimental feature which will most likely 278 //make it into jsf 2.2 279 /* jsf2.2 only: options.delay || */ 280 var delayTimeout = this._RT.getLocalOrGlobalConfig(context, "delay", false); 281 if (delayTimeout) { 282 this._delayTimeout = setTimeout(_Lang.hitch(this, function() { 283 this._transport[transportType](elem, form, context, passThrgh); 284 }), delayTimeout); 285 } else { 286 this._transport[transportType](elem, form, context, passThrgh); 287 } 288 }, 289 290 /** 291 * fetches the form in an unprecise manner depending 292 * on an element or event target 293 * 294 * @param elem 295 * @param event 296 */ 297 _getForm: function(elem, event) { 298 var _Dom = this._Dom; 299 var _Lang = this._Lang; 300 var form = _Dom.fuzzyFormDetection(elem); 301 302 if (!form && event) { 303 //in case of no form is given we retry over the issuing event 304 form = _Dom.fuzzyFormDetection(_Lang.getEventTarget(event)); 305 if (!form) { 306 throw _Lang.makeException(new Error(), null, null, this._nameSpace, "_getForm", _Lang.getMessage("ERR_FORM")); 307 } 308 } else if (!form) { 309 throw _Lang.makeException(new Error(), null, null, this._nameSpace, "_getForm", _Lang.getMessage("ERR_FORM")); 310 311 } 312 return form; 313 }, 314 315 /** 316 * determines the transport type to be called 317 * for the ajax call 318 * 319 * @param context the context 320 * @param passThrgh pass through values 321 * @param form the form which issues the request 322 */ 323 _getTransportType: function(context, passThrgh, form) { 324 /** 325 * if execute or render exist 326 * we have to pass them down as a blank delimited string representation 327 * of an array of ids! 328 */ 329 //for now we turn off the transport auto selection, to enable 2.0 backwards compatibility 330 //on protocol level, the file upload only can be turned on if the auto selection is set to true 331 var getConfig = this._RT.getLocalOrGlobalConfig, 332 _Lang = this._Lang, 333 _Dom = this._Dom; 334 335 var transportAutoSelection = getConfig(context, "transportAutoSelection", false); 336 var isMultipart = (transportAutoSelection && _Dom.getAttribute(form, "enctype") == "multipart/form-data") ? 337 _Dom.isMultipartCandidate(passThrgh[this.P_EXECUTE]) : 338 false; 339 340 /** 341 * multiple transports upcoming jsf 2.1 feature currently allowed 342 * default (no value) xhrQueuedPost 343 * 344 * xhrQueuedPost 345 * xhrPost 346 * xhrGet 347 * xhrQueuedGet 348 * iframePost 349 * iframeQueuedPost 350 * 351 */ 352 var transportType = (!isMultipart) ? 353 getConfig(context, "transportType", "xhrQueuedPost") : 354 getConfig(context, "transportType", "multipartQueuedPost"); 355 if (!this._transport[transportType]) { 356 //throw new Error("Transport type " + transportType + " does not exist"); 357 throw new Error(_Lang.getMessage("ERR_TRANSPORT", null, transportType)); 358 } 359 return transportType; 360 361 }, 362 363 /** 364 * transforms the list to the expected one 365 * with the proper none all form and this handling 366 * (note we also could use a simple string replace but then 367 * we would have had double entries under some circumstances) 368 * 369 * @param passThrgh 370 * @param target 371 * @param srcStr 372 * @param form 373 * @param elementId 374 */ 375 _transformList: function(passThrgh, target, srcStr, form, elementId) { 376 var _Lang = this._Lang; 377 //this is probably the fastest transformation method 378 //it uses an array and an index to position all elements correctly 379 //the offset variable is there to prevent 0 which results in a javascript 380 //false 381 srcStr = _Lang.trim(srcStr); 382 var offset = 1, 383 vals = (srcStr) ? srcStr.split(/\s+/) : [], 384 idIdx = (vals.length) ? _Lang.arrToMap(vals, offset) : {}, 385 386 //helpers to improve speed and compression 387 none = idIdx[this.IDENT_NONE], 388 all = idIdx[this.IDENT_ALL], 389 theThis = idIdx[this.IDENT_THIS], 390 theForm = idIdx[this.IDENT_FORM]; 391 392 if (none) { 393 //in case of none nothing is returned 394 if('undefined' != typeof passThrgh.target) { 395 delete passThrgh.target; 396 } 397 return passThrgh; 398 } 399 if (all) { 400 //in case of all only one value is returned 401 passThrgh[target] = this.IDENT_ALL; 402 return passThrgh; 403 } 404 405 if (theForm) { 406 //the form is replaced with the proper id but the other 407 //values are not touched 408 vals[theForm - offset] = form.id; 409 } 410 if (theThis && !idIdx[elementId]) { 411 //in case of this, the element id is set 412 vals[theThis - offset] = elementId; 413 } 414 415 //the final list must be blank separated 416 passThrgh[target] = vals.join(" "); 417 return passThrgh; 418 }, 419 420 addOnError : function(/*function*/errorListener) { 421 /*error handling already done in the assert of the queue*/ 422 this._errListeners.enqueue(errorListener); 423 }, 424 425 addOnEvent : function(/*function*/eventListener) { 426 /*error handling already done in the assert of the queue*/ 427 this._evtListeners.enqueue(eventListener); 428 }, 429 430 431 432 /** 433 * implementation triggering the error chain 434 * 435 * @param {Object} request the request object which comes from the xhr cycle 436 * @param {Object} context (Map) the context object being pushed over the xhr cycle keeping additional metadata 437 * @param {String} name the error name 438 * @param {String} serverErrorName the server error name in case of a server error 439 * @param {String} serverErrorMessage the server error message in case of a server error 440 * @param {String} caller optional caller reference for extended error messages 441 * @param {String} callFunc optional caller Function reference for extended error messages 442 * 443 * handles the errors, in case of an onError exists within the context the onError is called as local error handler 444 * the registered error handlers in the queue receiv an error message to be dealt with 445 * and if the projectStage is at development an alert box is displayed 446 * 447 * note: we have additional functionality here, via the global config myfaces.config.defaultErrorOutput a function can be provided 448 * which changes the default output behavior from alert to something else 449 * 450 * 451 */ 452 sendError : function sendError(/*Object*/request, /*Object*/ context, /*String*/ name, /*String*/ serverErrorName, /*String*/ serverErrorMessage, caller, callFunc) { 453 var _Lang = myfaces._impl._util._Lang; 454 var UNKNOWN = _Lang.getMessage("UNKNOWN"); 455 456 var eventData = {}; 457 //we keep this in a closure because we might reuse it for our serverErrorMessage 458 var malFormedMessage = function() { 459 return (name && name === myfaces._impl.core.Impl.MALFORMEDXML) ? _Lang.getMessage("ERR_MALFORMEDXML") : ""; 460 }; 461 462 //by setting unknown values to unknown we can handle cases 463 //better where a simulated context is pushed into the system 464 eventData.type = this.ERROR; 465 466 eventData.status = name || UNKNOWN; 467 eventData.serverErrorName = serverErrorName || UNKNOWN; 468 eventData.serverErrorMessage = serverErrorMessage || UNKNOWN; 469 470 471 472 try { 473 eventData.source = context.source || UNKNOWN; 474 eventData.responseCode = request.status || UNKNOWN; 475 eventData.responseText = request.responseText || UNKNOWN; 476 eventData.responseXML = request.responseXML || UNKNOWN; 477 } catch (e) { 478 // silently ignore: user can find out by examining the event data 479 } 480 //extended error message only in dev mode 481 if(jsf.getProjectStage() === "Development") { 482 eventData.serverErrorMessage = eventData.serverErrorMessage || ""; 483 eventData.serverErrorMessage = (caller)? eventData.serverErrorMessage + "\nCalling class: "+caller:eventData.serverErrorMessage; 484 eventData.serverErrorMessage = (callFunc)? eventData.serverErrorMessage + "\n Calling function: "+callFunc :eventData.serverErrorMessage; 485 } 486 487 /**/ 488 if (context["onerror"]) { 489 context.onerror(eventData); 490 } 491 492 /*now we serve the queue as well*/ 493 this._errListeners.broadcastEvent(eventData); 494 495 if (jsf.getProjectStage() === "Development" && this._errListeners.length() == 0 && !context["onerror"]) { 496 var DIVIDER = "--------------------------------------------------------", 497 defaultErrorOutput = myfaces._impl.core._Runtime.getGlobalConfig("defaultErrorOutput", alert), 498 finalMessage = [], 499 //we remap the function to achieve a better compressability 500 pushMsg = _Lang.hitch(finalMessage, finalMessage.push); 501 502 (serverErrorMessage) ? pushMsg(_Lang.getMessage("MSG_ERROR_MESSAGE") +" "+ serverErrorMessage +"\n") : null; 503 504 pushMsg(DIVIDER); 505 506 (caller)? pushMsg("Calling class:"+ caller): null; 507 (callFunc)? pushMsg("Calling function:"+ callFunc): null; 508 (name) ? pushMsg(_Lang.getMessage("MSG_ERROR_NAME") +" "+name ): null; 509 (serverErrorName && name != serverErrorName) ? pushMsg("Server error name: "+ serverErrorName ) : null; 510 511 512 pushMsg(malFormedMessage()); 513 pushMsg(DIVIDER); 514 pushMsg(_Lang.getMessage("MSG_DEV_MODE")); 515 defaultErrorOutput(finalMessage.join("\n")); 516 } 517 }, 518 519 /** 520 * sends an event 521 */ 522 sendEvent : function sendEvent(/*Object*/request, /*Object*/ context, /*event name*/ name) { 523 var _Lang = myfaces._impl._util._Lang; 524 var eventData = {}; 525 var UNKNOWN = _Lang.getMessage("UNKNOWN"); 526 527 eventData.type = this.EVENT; 528 529 eventData.status = name; 530 eventData.source = context.source; 531 532 if (name !== this.BEGIN) { 533 534 try { 535 //we bypass a problem with ie here, ie throws an exception if no status is given on the xhr object instead of just passing a value 536 var getValue = function(value, key) { 537 try { 538 return value[key] 539 } catch (e) { 540 return UNKNOWN; 541 } 542 }; 543 544 eventData.responseCode = getValue(request, "status"); 545 eventData.responseText = getValue(request, "responseText"); 546 eventData.responseXML = getValue(request, "responseXML"); 547 548 } catch (e) { 549 var impl = myfaces._impl.core._Runtime.getGlobalConfig("jsfAjaxImpl", myfaces._impl.core.Impl); 550 impl.sendError(request, context, this.CLIENT_ERROR, "ErrorRetrievingResponse", 551 _Lang.getMessage("ERR_CONSTRUCT", e.toString())); 552 553 //client errors are not swallowed 554 throw e; 555 } 556 557 } 558 559 /**/ 560 if (context.onevent) { 561 /*calling null to preserve the original scope*/ 562 context.onevent.call(null, eventData); 563 } 564 565 /*now we serve the queue as well*/ 566 this._evtListeners.broadcastEvent(eventData); 567 }, 568 569 570 /** 571 * Spec. 13.3.3 572 * Examining the response markup and updating the DOM tree 573 * @param {XMLHttpRequest} request - the ajax request 574 * @param {Object} context - the ajax context 575 */ 576 response : function(request, context) { 577 this._RT.getLocalOrGlobalConfig(context, "responseHandler", myfaces._impl.xhrCore._AjaxResponse).processResponse(request, context); 578 }, 579 580 /** 581 * @return the project stage also emitted by the server: 582 * it cannot be cached and must be delivered over the server 583 * The value for it comes from the request parameter of the jsf.js script called "stage". 584 */ 585 getProjectStage : function() { 586 //since impl is a singleton we only have to do it once at first access 587 588 if(!this._projectStage) { 589 var PRJ_STAGE = "projectStage", 590 STG_PROD = "Production", 591 592 scriptTags = document.getElementsByTagName("script"), 593 getConfig = myfaces._impl.core._Runtime.getGlobalConfig, 594 projectStage = null, 595 found = false, 596 allowedProjectStages = {STG_PROD:1,"Development":1, "SystemTest":1,"UnitTest":1}; 597 598 /* run through all script tags and try to find the one that includes jsf.js */ 599 for (var i = 0; i < scriptTags.length && !found; i++) { 600 if (scriptTags[i].src.search(/\/javax\.faces\.resource\/jsf\.js.*ln=javax\.faces/) != -1) { 601 var result = scriptTags[i].src.match(/stage=([^&;]*)/); 602 //alert("result found"); 603 //alert(result); 604 found = true; 605 if (result) { 606 // we found stage=XXX 607 // return only valid values of ProjectStage 608 projectStage = (allowedProjectStages[result[1]]) ? result[1] : null; 609 610 } 611 else { 612 //we found the script, but there was no stage parameter -- Production 613 //(we also add an override here for testing purposes, the default, however is Production) 614 projectStage = getConfig(PRJ_STAGE, STG_PROD); 615 } 616 } 617 } 618 /* we could not find anything valid --> return the default value */ 619 this._projectStage = projectStage || getConfig(PRJ_STAGE, STG_PROD); 620 } 621 return this._projectStage; 622 }, 623 624 /** 625 * implementation of the external chain function 626 * moved into the impl 627 * 628 * @param {Object} source the source which also becomes 629 * the scope for the calling function (unspecified side behavior) 630 * the spec states here that the source can be any arbitrary code block. 631 * Which means it either is a javascript function directly passed or a code block 632 * which has to be evaluated separately. 633 * 634 * After revisiting the code additional testing against components showed that 635 * the this parameter is only targeted at the component triggering the eval 636 * (event) if a string code block is passed. This is behavior we have to resemble 637 * in our function here as well, I guess. 638 * 639 * @param {Event} event the event object being passed down into the the chain as event origin 640 * the spec is contradicting here, it on one hand defines event, and on the other 641 * it says it is optional, after asking, it meant that event must be passed down 642 * but can be undefined 643 */ 644 chain : function(source, event) { 645 var len = arguments.length; 646 var _Lang = this._Lang; 647 var throwErr = function(msgKey) { 648 throw Error("jsf.util.chain: "+ _Lang.getMessage(msgKey)); 649 }; 650 /** 651 * generic error condition checker which raises 652 * an exception if the condition is met 653 * @param assertion 654 * @param message 655 */ 656 var errorCondition = function(assertion, message) { 657 if(assertion === true) throwErr(message); 658 }; 659 var FUNC = 'function'; 660 var ISSTR = _Lang.isString; 661 662 //the spec is contradicting here, it on one hand defines event, and on the other 663 //it says it is optional, I have cleared this up now 664 //the spec meant the param must be passed down, but can be 'undefined' 665 666 errorCondition(len < 2, "ERR_EV_OR_UNKNOWN"); 667 errorCondition(len < 3 && (FUNC == typeof event || ISSTR(event)), "ERR_EVT_PASS"); 668 if (len < 3) { 669 //nothing to be done here, move along 670 return true; 671 } 672 //now we fetch from what is given from the parameter list 673 //we cannot work with splice here in any performant way so we do it the hard way 674 //arguments only are give if not set to undefined even null values! 675 676 //assertions source either null or set as dom element: 677 errorCondition('undefined' == typeof source, "ERR_SOURCE_DEF_NULL"); 678 errorCondition(FUNC == typeof source, "ERR_SOURCE_FUNC"); 679 errorCondition(ISSTR(source), "ERR_SOURCE_NOSTR"); 680 681 //assertion if event is a function or a string we already are in our function elements 682 //since event either is undefined, null or a valid event object 683 errorCondition(FUNC == typeof event || ISSTR(event), "ERR_EV_OR_UNKNOWN"); 684 685 for (var cnt = 2; cnt < len; cnt++) { 686 //we do not change the scope of the incoming functions 687 //but we reuse the argument array capabilities of apply 688 var ret; 689 690 if (FUNC == typeof arguments[cnt]) { 691 ret = arguments[cnt].call(source, event); 692 } else { 693 //either a function or a string can be passed in case of a string we have to wrap it into another function 694 ret = new Function("event", arguments[cnt]).call(source, event); 695 } 696 //now if one function returns false in between we stop the execution of the cycle 697 //here, note we do a strong comparison here to avoid constructs like 'false' or null triggering 698 if (ret === false /*undefined check implicitly done here by using a strong compare*/) { 699 return false; 700 } 701 } 702 return true; 703 }, 704 705 /** 706 * error handler behavior called internally 707 * and only into the impl it takes care of the 708 * internal message transformation to a myfaces internal error 709 * and then uses the standard send error mechanisms 710 * also a double error logging prevention is done as well 711 * 712 * @param request the request currently being processed 713 * @param context the context affected by this error 714 * @param exception the exception being thrown 715 */ 716 stdErrorHandler: function(request, context, exception) { 717 //newer browsers do not allow to hold additional values on native objects like exceptions 718 //we hence capsule it into the request, which is gced automatically 719 //on ie as well, since the stdErrorHandler usually is called between requests 720 //this is a valid approach 721 if (this._threshold == "ERROR") { 722 var mfInternal = exception._mfInternal || {}; 723 724 var finalMsg = []; 725 finalMsg.push(exception.message); 726 this.sendError(request, context, 727 mfInternal.title || this.CLIENT_ERROR, mfInternal.name || exception.name, finalMsg.join("\n"), mfInternal.caller, mfInternal.callFunc); 728 } 729 } 730 }); 731 732 733