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