1 /*
  2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  3  *
  4  * Copyright 1997-2016 Sun Microsystems, Inc. All rights reserved.
  5  *
  6  * The contents of this file are subject to the terms of either the GNU
  7  * General Public License Version 2 only ("GPL") or the Common Development
  8  * and Distribution License("CDDL") (collectively, the "License").  You
  9  * may not use this file except in compliance with the License. You can obtain
 10  * a copy of the License at https://glassfish.java.net/public/CDDL+GPL.html
 11  * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 12  * language governing permissions and limitations under the License.
 13  *
 14  * When distributing the software, include this License Header Notice in each
 15  * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 16  * Sun designates this particular file as subject to the "Classpath" exception
 17  * as provided by Sun in the GPL Version 2 section of the License file that
 18  * accompanied this code.  If applicable, add the following below the License
 19  * Header, with the fields enclosed by brackets [] replaced by your own
 20  * identifying information: "Portions Copyrighted [year]
 21  * [name of copyright owner]"
 22  *
 23  * Contributor(s):
 24  *
 25  * If you wish your version of this file to be governed by only the CDDL or
 26  * only the GPL Version 2, indicate your decision by adding "[Contributor]
 27  * elects to include this software in this distribution under the [CDDL or GPL
 28  * Version 2] license."  If you don't indicate a single choice of license, a
 29  * recipient has the option to distribute your version of this file under
 30  * either the CDDL, the GPL Version 2 or to extend the choice of license to
 31  * its licensees as provided above.  However, if you add GPL Version 2 code
 32  * and therefore, elected the GPL Version 2 license, then the option applies
 33  * only if the new code is made subject to such option by the copyright
 34  * holder.
 35  *
 36  *
 37  * This file incorporates work covered by the following copyright and
 38  * permission notices:
 39  *
 40  * Copyright 2004 The Apache Software Foundation
 41  * Copyright 2004-2008 Emmanouil Batsis, mailto: mbatsis at users full stop sourceforge full stop net
 42  *
 43  * Licensed under the Apache License, Version 2.0 (the "License");
 44  * you may not use this file except in compliance with the License.
 45  * You may obtain a copy of the License at
 46  *
 47  *     http://www.apache.org/licenses/LICENSE-2.0
 48  *
 49  * Unless required by applicable law or agreed to in writing, software
 50  * distributed under the License is distributed on an "AS IS" BASIS,
 51  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 52  * See the License for the specific language governing permissions and
 53  * limitations under the License.
 54  */
 55 
 56 /**
 57  @project JSF JavaScript Library
 58  @version 2.2
 59  @description This is the standard implementation of the JSF JavaScript Library.
 60  */
 61 
 62 // Detect if this is already loaded, and if loaded, if it's a higher version
 63 if (!((jsf && jsf.specversion && jsf.specversion >= 23000 ) &&
 64       (jsf.implversion && jsf.implversion >= 3))) {
 65 
 66     /**
 67      * <span class="changed_modified_2_2">The top level global namespace
 68      * for JavaServer Faces functionality.</span>
 69 
 70      * @name jsf
 71      * @namespace
 72      */
 73     var jsf = {};
 74 
 75     /**
 76 
 77      * <span class="changed_modified_2_2 changed_modified_2_3">The namespace for Ajax
 78      * functionality.</span>
 79 
 80      * @name jsf.ajax
 81      * @namespace
 82      * @exec
 83      */
 84     jsf.ajax = function() {
 85 
 86         var eventListeners = [];
 87         var errorListeners = [];
 88 
 89         var delayHandler = null;
 90         /**
 91          * Determine if the current browser is part of Microsoft's failed attempt at
 92          * standards modification.
 93          * @ignore
 94          */
 95         var isIE = function isIE() {
 96             if (typeof isIECache !== "undefined") {
 97                 return isIECache;
 98             }
 99             isIECache =
100                    document.all && window.ActiveXObject &&
101                    navigator.userAgent.toLowerCase().indexOf("msie") > -1 &&
102                    navigator.userAgent.toLowerCase().indexOf("opera") == -1;
103             return isIECache;
104         };
105         var isIECache;
106 
107         /**
108          * Determine the version of IE.
109          * @ignore
110          */
111         var getIEVersion = function getIEVersion() {
112             if (typeof IEVersionCache !== "undefined") {
113                 return IEVersionCache;
114             }
115             if (/MSIE ([0-9]+)/.test(navigator.userAgent)) {
116                 IEVersionCache = parseInt(RegExp.$1);
117             } else {
118                 IEVersionCache = -1;
119             }
120             return IEVersionCache;
121         }
122         var IEVersionCache;
123 
124         /**
125          * Determine if loading scripts into the page executes the script.
126          * This is instead of doing a complicated browser detection algorithm.  Some do, some don't.
127          * @returns {boolean} does including a script in the dom execute it?
128          * @ignore
129          */
130         var isAutoExec = function isAutoExec() {
131             try {
132                 if (typeof isAutoExecCache !== "undefined") {
133                     return isAutoExecCache;
134                 }
135                 var autoExecTestString = "<script>var mojarra = mojarra || {};mojarra.autoExecTest = true;</script>";
136                 var tempElement = document.createElement('span');
137                 tempElement.innerHTML = autoExecTestString;
138                 var body = document.getElementsByTagName('body')[0];
139                 var tempNode = body.appendChild(tempElement);
140                 if (mojarra && mojarra.autoExecTest) {
141                     isAutoExecCache = true;
142                     delete mojarra.autoExecTest;
143                 } else {
144                     isAutoExecCache = false;
145                 }
146                 deleteNode(tempNode);
147                 return isAutoExecCache;
148             } catch (ex) {
149                 // OK, that didn't work, we'll have to make an assumption
150                 if (typeof isAutoExecCache === "undefined") {
151                     isAutoExecCache = false;
152                 }
153                 return isAutoExecCache;
154             }
155         };
156         var isAutoExecCache;
157 
158         /**
159          * @ignore
160          */
161         var getTransport = function getTransport(context) {
162             var returnVal;
163             // Here we check for encoding type for file upload(s).
164             // This is where we would also include a check for the existence of
165             // input file control for the current form (see hasInputFileControl
166             // function) but IE9 (at least) seems to render controls outside of
167             // form.
168             if (typeof context !== 'undefined' && context !== null &&
169                 context.includesInputFile &&
170                 context.form.enctype === "multipart/form-data") {
171                 returnVal = new FrameTransport(context);
172                 return returnVal;
173             }
174             var methods = [
175                 function() {
176                     return new XMLHttpRequest();
177                 },
178                 function() {
179                     return new ActiveXObject('Msxml2.XMLHTTP');
180                 },
181                 function() {
182                     return new ActiveXObject('Microsoft.XMLHTTP');
183                 }
184             ];
185 
186             for (var i = 0, len = methods.length; i < len; i++) {
187                 try {
188                     returnVal = methods[i]();
189                 } catch(e) {
190                     continue;
191                 }
192                 return returnVal;
193             }
194             throw new Error('Could not create an XHR object.');
195         };
196         
197         /**
198          * Used for iframe based communication (instead of XHR).
199          * @ignore
200          */
201         var FrameTransport = function FrameTransport(context) {
202             this.context = context;
203             this.frame = null;
204             this.FRAME_ID = "JSFFrameId";
205             this.FRAME_PARTIAL_ID = "Faces-Request";
206             this.partial = null;
207             this.aborted = false;
208             this.responseText = null;
209             this.responseXML = null;
210             this.readyState = 0;
211             this.requestHeader = {};
212             this.status = null;
213             this.method = null;
214             this.url = null;
215             this.requestParams = null;
216         };
217         
218         /**
219          * Extends FrameTransport an adds method functionality.
220          * @ignore
221          */
222         FrameTransport.prototype = {
223             
224             /**
225              *@ignore
226              */
227             setRequestHeader:function(key, value) {
228                 if (typeof(value) !== "undefined") {
229                     this.requestHeader[key] = value;  
230                 }
231             },
232             
233             /**
234              * Creates the hidden iframe and sets readystate.
235              * @ignore
236              */
237             open:function(method, url, async) {
238                 this.method = method;
239                 this.url = url;
240                 this.async = async;
241                 this.frame = document.getElementById(this.FRAME_ID);
242                 if (this.frame) {
243                     this.frame.parentNode.removeChild(this.frame);
244                     this.frame = null;
245                 }
246                 if (!this.frame) {  
247                     if ((!isIE() && !isIE9Plus())) {
248                         this.frame = document.createElement('iframe');
249                         this.frame.src = "about:blank";
250                         this.frame.id = this.FRAME_ID;
251                         this.frame.name = this.FRAME_ID;
252                         this.frame.type = "content";
253                         this.frame.collapsed = "true";
254                         this.frame.style = "visibility:hidden";   
255                         this.frame.width = "0";
256                         this.frame.height = "0";
257                         this.frame.style = "border:0";
258                         this.frame.frameBorder = 0;
259                         document.body.appendChild(this.frame);
260                         this.frame.onload = bind(this, this.callback);
261                     } else {
262                         var div = document.createElement("div");
263                         div.id = "frameDiv";
264                         div.innerHTML = "<iframe id='" + this.FRAME_ID + "' name='" + this.FRAME_ID + "' style='display:none;' src='about:blank' type='content' onload='this.onload_cb();'  ></iframe>";
265                         document.body.appendChild(div);
266                         this.frame = document.getElementById(this.FRAME_ID);
267                         this.frame.onload_cb = bind(this, this.callback);
268                     }
269                 }
270                 // Create to send "Faces-Request" param with value "partial/ajax"
271                 // For iframe approach we are sending as request parameter
272                 // For non-iframe (xhr ajax) it is sent in the request header
273                 this.partial = document.createElement("input");
274                 this.partial.setAttribute("type", "hidden");
275                 this.partial.setAttribute("id", this.FRAME_PARTIAL_ID);
276                 this.partial.setAttribute("name", this.FRAME_PARTIAL_ID);
277                 this.partial.setAttribute("value", "partial/ajax");
278                 this.context.form.appendChild(this.partial);
279   
280                 this.readyState = 1;                         
281             },
282             
283             /**
284              * Sets the form target to iframe, sets up request parameters
285              * and submits the form.
286              * @ignore
287              */
288             send: function(data) {
289                 var evt = {};
290                 this.context.form.target = this.frame.name;
291                 this.context.form.method = this.method;
292                 if (this.url) {
293                     this.context.form.action = this.url;
294                 }
295 
296                 this.readyState = 3;
297 
298                 this.onreadystatechange(evt);
299                 
300                 var ddata = decodeURIComponent(data);
301                 var dataArray = ddata.split("&");
302                 var input;
303                 this.requestParams = new Array();
304                 for (var i=0; i<dataArray.length; i++) {
305                     var nameValue = dataArray[i].split("=");
306                     if (nameValue[0] === this.context.namingContainerPrefix + "javax.faces.source" ||
307                         nameValue[0] === this.context.namingContainerPrefix + "javax.faces.partial.event" ||
308                         nameValue[0] === this.context.namingContainerPrefix + "javax.faces.partial.execute" ||
309                         nameValue[0] === this.context.namingContainerPrefix + "javax.faces.partial.render" ||
310                         nameValue[0] === this.context.namingContainerPrefix + "javax.faces.partial.ajax" ||
311                         nameValue[0] === this.context.namingContainerPrefix + "javax.faces.behavior.event") {
312                         input = document.createElement("input");
313                         input.setAttribute("type", "hidden");
314                         input.setAttribute("id", nameValue[0]);
315                         input.setAttribute("name", nameValue[0]);
316                         input.setAttribute("value", nameValue[1]);
317                         this.context.form.appendChild(input);
318                         this.requestParams.push(nameValue[0]);
319                     }
320                 }
321                 this.requestParams.push(this.FRAME_PARTIAL_ID);
322                 this.context.form.submit();
323             },
324             
325             /**
326              *@ignore
327              */
328             abort:function() {
329                 this.aborted = true; 
330             },
331             
332             /**
333              *@ignore
334              */
335             onreadystatechange:function(evt) {
336                 
337             },
338             
339             /**
340              * Extracts response from iframe document, sets readystate.
341              * @ignore
342              */
343             callback: function() {
344                 if (this.aborted) {
345                     return;
346                 }
347                 var iFrameDoc;
348                 var docBody;
349                 try {
350                     var evt = {};
351                     iFrameDoc = this.frame.contentWindow.document || 
352                         this.frame.contentDocument || this.frame.document;
353                     docBody = iFrameDoc.body || iFrameDoc.documentElement;
354                     this.responseText = docBody.innerHTML;
355                     this.responseXML = iFrameDoc.XMLDocument || iFrameDoc;
356                     this.status = 201;
357                     this.readyState = 4;  
358 
359                     this.onreadystatechange(evt);                
360                 } finally {
361                     this.cleanupReqParams();
362                 }               
363             },
364             
365             /**
366              *@ignore
367              */
368             cleanupReqParams: function() {
369                 var clone = this.frame.cloneNode();
370                 while (this.frame.firstChild) {
371                     clone.appendChild(this.frame.lastChild);
372                 }
373 
374                 this.frame.parentNode.replaceChild(clone, this.frame);
375                 this.context.form.removeAttribute("target");
376                 for (var i=0; i<this.requestParams.length; i++) {
377                     var elements = this.context.form.childNodes;
378                     for (var j=0; j<elements.length; j++) {
379                         if (!elements[j].type === "hidden") {
380                             continue;
381                         }
382                         if (elements[j].name === this.requestParams[i]) {
383                             var node = this.context.form.removeChild(elements[j]);
384                             node = null;                           
385                             break;
386                         }
387                     }   
388                 }
389             }
390         };
391         
392        
393         /**
394          *Utility function that binds function to scope.
395          *@ignore
396          */
397         var bind = function(scope, fn) {
398             return function () {
399                 fn.apply(scope, arguments);
400             };
401         };
402 
403         /**
404          * Utility function that determines if a file control exists
405          * for the form.
406          * @ignore
407          */
408         var hasInputFileControl = function(form) {
409             var returnVal = false;
410             var inputs = form.getElementsByTagName("input");
411             if (inputs !== null && typeof inputs !=="undefined") {
412                 for (var i=0; i<inputs.length; i++) {
413                     if (inputs[i].type === "file") {
414                         returnVal = true;
415                         break;
416                     }
417                 }    
418             }
419             return returnVal;
420         };
421         
422         /**
423          * Find instance of passed String via getElementById
424          * @ignore
425          */
426         var $ = function $() {
427             var results = [], element;
428             for (var i = 0; i < arguments.length; i++) {
429                 element = arguments[i];
430                 if (typeof element == 'string') {
431                     element = document.getElementById(element);
432                 }
433                 results.push(element);
434             }
435             return results.length > 1 ? results : results[0];
436         };
437 
438         /**
439          * Get the form element which encloses the supplied element.
440          * @param element - element to act against in search
441          * @returns form element representing enclosing form, or first form if none found.
442          * @ignore
443          */
444         var getForm = function getForm(element) {
445             if (element) {
446                 var form = $(element);
447                 while (form) {
448 
449                     if (form.nodeName && (form.nodeName.toLowerCase() == 'form')) {
450                         return form;
451                     }
452                     if (form.form) {
453                         return form.form;
454                     }
455                     if (form.parentNode) {
456                         form = form.parentNode;
457                     } else {
458                         form = null;
459                     }
460                 }
461                 return document.forms[0];
462             }
463             return null;
464         };
465 
466         /**
467          * Get an array of all JSF form elements which need their view state to be updated.
468          * This covers at least the form that submitted the request and any form that is covered in the render target list.
469          * 
470          * @param context An object containing the request context, including the following properties:
471          * the source element, per call onerror callback function, per call onevent callback function, the render
472          * instructions, the submitting form ID, the naming container ID and naming container prefix.
473          * @ignore
474          */
475         var getFormsToUpdate = function getFormsToUpdate(context) {
476             var formsToUpdate = [];
477 
478             var add = function(element) {
479                 if (element) {
480                     if (element.nodeName 
481                         && element.nodeName.toLowerCase() == "form" 
482                         && element.method == "post" 
483                         && element.id 
484                         && element.elements 
485                         && element.id.indexOf(context.namingContainerPrefix) == 0)
486                     {
487                         formsToUpdate.push(element);
488                     }
489                     else {
490                         var forms = element.getElementsByTagName("form");
491     
492                         for (var i = 0; i < forms.length; i++) {
493                             add(forms[i]);
494                         }
495                     }
496                 }
497             }
498 
499             if (context.formId) {
500                 add(document.getElementById(context.formId));
501             }
502 
503             if (context.render) {
504                 if (context.render.indexOf("@all") >= 0) {
505                     add(document);
506                 }
507                 else {
508                     var clientIds = context.render.split(" ");
509 
510                     for (var i = 0; i < clientIds.length; i++) {
511                         if (clientIds.hasOwnProperty(i)) {
512                             add(document.getElementById(clientIds[i]));
513                         }
514                     }
515                 }
516             }
517 
518             return formsToUpdate;
519         }
520 
521         /**
522          * <p>Namespace given space separated parameters if necessary (only
523          * call this if there is a namingContainerPrefix!).  This
524          * function is here for backwards compatibility with manual
525          * jsf.ajax.request() calls written before Spec790 changes.</p>
526 
527          * @param parameters Spaceseparated string of parameters as
528          * usually specified in f:ajax execute and render attributes.
529 
530          * @param sourceClientId The client ID of the f:ajax
531          * source. This is to be used for prefixing relative target
532          * client IDs.
533 
534          * It's expected that this already starts with
535          * namingContainerPrefix.
536 
537          * @param namingContainerPrefix The naming container prefix (the
538          * view root ID suffixed with separator character).
539 
540          * This is to be used for prefixing absolute target client IDs.
541          * @ignore
542          */
543         var namespaceParametersIfNecessary = function namespaceParametersIfNecessary(parameters, sourceClientId, namingContainerPrefix) {
544             if (sourceClientId.indexOf(namingContainerPrefix) != 0) {
545                 return parameters; // Unexpected source client ID; let's silently do nothing.
546             }
547 
548             var targetClientIds = parameters.replace(/^\s+|\s+$/g, '').split(/\s+/g);
549 
550             for (var i = 0; i < targetClientIds.length; i++) {
551                 var targetClientId = targetClientIds[i];
552 
553                 if (targetClientId.indexOf(jsf.separatorchar) == 0) {
554                     targetClientId = targetClientId.substring(1);
555 
556                     if (targetClientId.indexOf(namingContainerPrefix) != 0) {
557                         targetClientId = namingContainerPrefix + targetClientId;
558                     }
559                 }
560                 else if (targetClientId.indexOf(namingContainerPrefix) != 0) {
561                     var parentClientId = sourceClientId.substring(0, sourceClientId.lastIndexOf(jsf.separatorchar));
562 
563                     if (namingContainerPrefix + targetClientId == parentClientId) {
564                         targetClientId = parentClientId;
565                     }
566                     else {
567                         targetClientId = parentClientId + jsf.separatorchar + targetClientId;
568                     }
569                 }
570 
571                 targetClientIds[i] = targetClientId;
572             }
573 
574             return targetClientIds.join(' ');
575         };
576 
577         /**
578          * Check if a value exists in an array
579          * @ignore
580          */
581         var isInArray = function isInArray(array, value) {
582             for (var i = 0; i < array.length; i++) {
583                 if (array[i] === value) {
584                     return true;
585                 }
586             }
587             return false;
588         };
589 
590 
591         /**
592          * Evaluate JavaScript code in a global context.
593          * @param src JavaScript code to evaluate
594          * @ignore
595          */
596         var globalEval = function globalEval(src) {
597             if (window.execScript) {
598                 window.execScript(src);
599                 return;
600             }
601             // We have to wrap the call in an anon function because of a firefox bug, where this is incorrectly set
602             // We need to explicitly call window.eval because of a Chrome peculiarity
603             /**
604              * @ignore
605              */
606             var fn = function() {
607                 window.eval.call(window,src);
608             };
609             fn();
610         };
611 
612         /**
613          * Get all scripts from supplied string, return them as an array for later processing.
614          * @param str
615          * @returns {array} of script text
616          * @ignore
617          */
618         var getScripts = function getScripts(str) {
619             // Regex to find all scripts in a string
620             var findscripts = /<script[^>]*>([\S\s]*?)<\/script>/igm;
621             // Regex to find one script, to isolate it's content [2] and attributes [1]
622             var findscript = /<script([^>]*)>([\S\s]*?)<\/script>/im;
623             // Regex to find type attribute
624             var findtype = /type="([\S]*?)"/im;
625             var initialnodes = [];
626             var scripts = [];
627             initialnodes = str.match(findscripts);
628             while (!!initialnodes && initialnodes.length > 0) {
629                 var scriptStr = [];
630                 scriptStr = initialnodes.shift().match(findscript);
631                 // check the type - skip if it not javascript type
632                 var type = [];
633                 type = scriptStr[1].match(findtype);
634                 if ( !!type && type[1]) {
635                     if (type[1] !== "text/javascript") {
636                         continue;
637                     }
638                 }
639                 scripts.push(scriptStr);
640             }
641             return scripts;
642         };
643 
644         var removeScripts = function removeScripts(str) {
645             return str.replace(/<script[^>]*type="text\/javascript"[^>]*>([\S\s]*?)<\/script>/igm,"");
646         };
647 
648         /**
649          * Run an array of script nodes,
650          * @param scripts Array of script nodes.
651          * @ignore
652          */
653         var runScripts = function runScripts(scripts) {
654             if (!scripts || scripts.length === 0) {
655                 return;
656             }
657 
658             var loadedScripts = document.getElementsByTagName("script");
659             var loadedScriptUrls = [];
660 
661             for (var i = 0; i < loadedScripts.length; i++) {
662                 var scriptNode = loadedScripts[i];
663                 var url = scriptNode.getAttribute("src");
664 
665                 if (url) {
666                     loadedScriptUrls.push(url);
667                 }
668             }
669 
670             var head = document.head || document.getElementsByTagName('head')[0] || document.documentElement;
671             runScript(head, loadedScriptUrls, scripts, 0);
672         };
673 
674         /**
675          * Run script at given index.
676          * @param head Document's head.
677          * @param loadedScriptUrls URLs of scripts which are already loaded.
678          * @param scripts Array of script nodes.
679          * @param index Index of script to be loaded.
680          * @ignore
681          */
682         var runScript = function runScript(head, loadedScriptUrls, scripts, index) {
683             if (index >= scripts.length) {
684                 return;
685             }
686 
687             // Regex to find src attribute
688             var findsrc = /src="([\S]*?)"/im;
689             // Regex to remove leading cruft
690             var stripStart = /^\s*(<!--)*\s*(\/\/)*\s*(\/\*)*\s*\n*\**\n*\s*\*.*\n*\s*\*\/(<!\[CDATA\[)*/;
691 
692             var scriptStr = scripts[index];
693             var src = scriptStr[1].match(findsrc);
694             var scriptLoadedViaUrl = false;
695 
696             if (!!src && src[1]) {
697                 // if this is a file, load it
698                 var url = unescapeHTML(src[1]);
699                 // if this is already loaded, don't load it
700                 // it's never necessary, and can make debugging difficult
701                 if (loadedScriptUrls.indexOf(url) < 0) {
702                     // create script node
703                     var scriptNode = document.createElement('script');
704                     var parserElement = document.createElement('div');
705                     parserElement.innerHTML = scriptStr[0];
706                     cloneAttributes(scriptNode, parserElement.firstChild);
707                     deleteNode(parserElement);
708                     scriptNode.type = 'text/javascript';
709                     scriptNode.src = url; // add the src to the script node
710                     scriptNode.onload = scriptNode.onreadystatechange = function(_, abort) {
711                         if (abort || !scriptNode.readyState || /loaded|complete/.test(scriptNode.readyState)) {
712                             scriptNode.onload = scriptNode.onreadystatechange = null; // IE memory leak fix.
713                             scriptNode = null;
714                             runScript(head, loadedScriptUrls, scripts, index + 1); // Run next script.
715                         }
716                     };
717                     head.insertBefore(scriptNode, null); // add it to end of the head (and don't remove it)
718                     scriptLoadedViaUrl = true;
719                 }
720             } else if (!!scriptStr && scriptStr[2]) {
721                 // else get content of tag, without leading CDATA and such
722                 var script = scriptStr[2].replace(stripStart,"");
723 
724                 if (!!script) {
725                     // create script node
726                     var scriptNode = document.createElement('script');
727                     scriptNode.type = 'text/javascript';
728                     scriptNode.text = script; // add the code to the script node
729                     head.appendChild(scriptNode); // add it to the head
730                     head.removeChild(scriptNode); // then remove it
731                 }
732             }
733 
734             if (!scriptLoadedViaUrl) {
735                 runScript(head, loadedScriptUrls, scripts, index + 1); // Run next script.
736             }
737         };
738 
739         /**
740          * Get all stylesheets from supplied string and run them all.
741          * @param str
742          * @ignore
743          */
744         var runStylesheets = function runStylesheets(str) {
745             // Regex to find all links in a string
746             var findlinks = /<link[^>]*\/>/igm;
747             // Regex to find one link, to isolate its attributes [1]
748             var findlink = /<link([^>]*)\/>/im;
749             // Regex to find type attribute
750             var findtype = /type="([\S]*?)"/im;
751             var findhref = /href="([\S]*?)"/im;
752 
753             var stylesheets = [];
754             var loadedStylesheetUrls = null;
755             var head = document.head || document.getElementsByTagName('head')[0] || document.documentElement;
756             var parserElement = null;
757 
758             var initialnodes = str.match(findlinks);
759             while (!!initialnodes && initialnodes.length > 0) {
760                 var linkStr = initialnodes.shift().match(findlink);
761                 // check the type - skip if it not css type
762                 var type = linkStr[1].match(findtype);
763                 if (!type || type[1] !== "text/css") {
764                     continue;
765                 }
766                 var href = linkStr[1].match(findhref);
767                 if (!!href && href[1]) {
768                     if (loadedStylesheetUrls === null) {
769                         var loadedLinks = document.getElementsByTagName("link");
770                         loadedStylesheetUrls = [];
771 
772                         for (var i = 0; i < loadedLinks.length; i++) {
773                             var linkNode = loadedLinks[i];
774                             
775                             if (linkNode.getAttribute("type") === "text/css") {
776                                 var url = linkNode.getAttribute("href");
777 
778                                 if (url) {
779                                     loadedStylesheetUrls.push(url);
780                                 }
781                             }
782                         }
783                     }
784 
785                     var url = unescapeHTML(href[1]);
786 
787                     if (loadedStylesheetUrls.indexOf(url) < 0) {
788                         // create stylesheet node
789                         parserElement = parserElement !== null ? parserElement : document.createElement('div');
790                         parserElement.innerHTML = linkStr[0];
791                         var linkNode = parserElement.firstChild;
792                         linkNode.type = 'text/css';
793                         linkNode.rel = 'stylesheet';
794                         linkNode.href = url;
795                         head.insertBefore(linkNode, null); // add it to end of the head (and don't remove it)
796                     }
797                 }
798             }
799 
800             deleteNode(parserElement);
801         };
802 
803         /**
804          * Replace DOM element with a new tagname and supplied innerHTML
805          * @param element element to replace
806          * @param tempTagName new tag name to replace with
807          * @param src string new content for element
808          * @ignore
809          */
810         var elementReplaceStr = function elementReplaceStr(element, tempTagName, src) {
811 
812             var temp = document.createElement(tempTagName);
813             if (element.id) {
814                 temp.id = element.id;
815             }
816 
817             // Creating a head element isn't allowed in IE, and faulty in most browsers,
818             // so it is not allowed
819             if (element.nodeName.toLowerCase() === "head") {
820                 throw new Error("Attempted to replace a head element - this is not allowed.");
821             } else {
822                 var scripts = [];
823                 if (isAutoExec()) {
824                     temp.innerHTML = src;
825                 } else {
826                     // Get scripts from text
827                     scripts = getScripts(src);
828                     // Remove scripts from text
829                     src = removeScripts(src);
830                     temp.innerHTML = src;
831                 }
832             }
833 
834             replaceNode(temp, element);            
835             cloneAttributes(temp, element);
836             runScripts(scripts);
837 
838         };
839 
840         /**
841          * Get a string with the concatenated values of all string nodes under the given node
842          * @param  oNode the given DOM node
843          * @param  deep boolean - whether to recursively scan the children nodes of the given node for text as well. Default is <code>false</code>
844          * @ignore
845          * Note:  This code originally from Sarissa: http://dev.abiss.gr/sarissa
846          * It has been modified to fit into the overall codebase
847          */
848         var getText = function getText(oNode, deep) {
849             var Node = {ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4,
850                 ENTITY_REFERENCE_NODE: 5,  ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7,
851                 COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10,
852                 DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12};
853 
854             var s = "";
855             var nodes = oNode.childNodes;
856             for (var i = 0; i < nodes.length; i++) {
857                 var node = nodes[i];
858                 var nodeType = node.nodeType;
859                 if (nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE) {
860                     s += node.data;
861                 } else if (deep === true && (nodeType == Node.ELEMENT_NODE ||
862                                              nodeType == Node.DOCUMENT_NODE ||
863                                              nodeType == Node.DOCUMENT_FRAGMENT_NODE)) {
864                     s += getText(node, true);
865                 }
866             }
867             return s;
868         };
869 
870         var PARSED_OK = "Document contains no parsing errors";
871         var PARSED_EMPTY = "Document is empty";
872         var PARSED_UNKNOWN_ERROR = "Not well-formed or other error";
873         var getParseErrorText;
874         if (isIE()) {
875             /**
876              * Note: This code orginally from Sarissa: http://dev.abiss.gr/sarissa
877              * @ignore
878              */
879             getParseErrorText = function (oDoc) {
880                 var parseErrorText = PARSED_OK;
881                 if (oDoc && oDoc.parseError && oDoc.parseError.errorCode && oDoc.parseError.errorCode !== 0) {
882                     parseErrorText = "XML Parsing Error: " + oDoc.parseError.reason +
883                                      "\nLocation: " + oDoc.parseError.url +
884                                      "\nLine Number " + oDoc.parseError.line + ", Column " +
885                                      oDoc.parseError.linepos +
886                                      ":\n" + oDoc.parseError.srcText +
887                                      "\n";
888                     for (var i = 0; i < oDoc.parseError.linepos; i++) {
889                         parseErrorText += "-";
890                     }
891                     parseErrorText += "^\n";
892                 }
893                 else if (oDoc.documentElement === null) {
894                     parseErrorText = PARSED_EMPTY;
895                 }
896                 return parseErrorText;
897             };
898         } else { // (non-IE)
899 
900             /**
901              * <p>Returns a human readable description of the parsing error. Useful
902              * for debugging. Tip: append the returned error string in a <pre>
903              * element if you want to render it.</p>
904              * @param  oDoc The target DOM document
905              * @returns {String} The parsing error description of the target Document in
906              *          human readable form (preformated text)
907              * @ignore
908              * Note:  This code orginally from Sarissa: http://dev.abiss.gr/sarissa
909              */
910             getParseErrorText = function (oDoc) {
911                 var parseErrorText = PARSED_OK;
912                 if ((!oDoc) || (!oDoc.documentElement)) {
913                     parseErrorText = PARSED_EMPTY;
914                 } else if (oDoc.documentElement.tagName == "parsererror") {
915                     parseErrorText = oDoc.documentElement.firstChild.data;
916                     parseErrorText += "\n" + oDoc.documentElement.firstChild.nextSibling.firstChild.data;
917                 } else if (oDoc.getElementsByTagName("parsererror").length > 0) {
918                     var parsererror = oDoc.getElementsByTagName("parsererror")[0];
919                     parseErrorText = getText(parsererror, true) + "\n";
920                 } else if (oDoc.parseError && oDoc.parseError.errorCode !== 0) {
921                     parseErrorText = PARSED_UNKNOWN_ERROR;
922                 }
923                 return parseErrorText;
924             };
925         }
926 
927         if ((typeof(document.importNode) == "undefined") && isIE()) {
928             try {
929                 /**
930                  * Implementation of importNode for the context window document in IE.
931                  * If <code>oNode</code> is a TextNode, <code>bChildren</code> is ignored.
932                  * @param oNode the Node to import
933                  * @param bChildren whether to include the children of oNode
934                  * @returns the imported node for further use
935                  * @ignore
936                  * Note:  This code orginally from Sarissa: http://dev.abiss.gr/sarissa
937                  */
938                 document.importNode = function(oNode, bChildren) {
939                     var tmp;
940                     if (oNode.nodeName == '#text') {
941                         return document.createTextNode(oNode.data);
942                     }
943                     else {
944                         if (oNode.nodeName == "tbody" || oNode.nodeName == "tr") {
945                             tmp = document.createElement("table");
946                         }
947                         else if (oNode.nodeName == "td") {
948                             tmp = document.createElement("tr");
949                         }
950                         else if (oNode.nodeName == "option") {
951                             tmp = document.createElement("select");
952                         }
953                         else {
954                             tmp = document.createElement("div");
955                         }
956                         if (bChildren) {
957                             tmp.innerHTML = oNode.xml ? oNode.xml : oNode.outerHTML;
958                         } else {
959                             tmp.innerHTML = oNode.xml ? oNode.cloneNode(false).xml : oNode.cloneNode(false).outerHTML;
960                         }
961                         return tmp.getElementsByTagName("*")[0];
962                     }
963                 };
964             } catch(e) {
965             }
966         }
967         // Setup Node type constants for those browsers that don't have them (IE)
968         var Node = {ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4,
969             ENTITY_REFERENCE_NODE: 5,  ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7,
970             COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10,
971             DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12};
972 
973         // PENDING - add support for removing handlers added via DOM 2 methods
974         /**
975          * Delete all events attached to a node
976          * @param node
977          * @ignore
978          */
979         var clearEvents = function clearEvents(node) {
980             if (!node) {
981                 return;
982             }
983 
984             // don't do anything for text and comment nodes - unnecessary
985             if (node.nodeType == Node.TEXT_NODE || node.nodeType == Node.COMMENT_NODE) {
986                 return;
987             }
988 
989             var events = ['abort', 'blur', 'change', 'error', 'focus', 'load', 'reset', 'resize', 'scroll', 'select', 'submit', 'unload',
990             'keydown', 'keypress', 'keyup', 'click', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'dblclick' ];
991             try {
992                 for (var e in events) {
993                     if (events.hasOwnProperty(e)) {
994                         node[e] = null;
995                     }
996                 }
997             } catch (ex) {
998                 // it's OK if it fails, at least we tried
999             }
1000         };
1001 
1002         /**
1003          * Determine if this current browser is IE9 or greater
1004          * @param node
1005          * @ignore
1006          */
1007         var isIE9Plus = function isIE9Plus() {
1008             var iev = getIEVersion();
1009             if (iev >= 9) {
1010                 return true;
1011             } else {
1012                 return false;
1013             }
1014         }
1015 
1016 
1017         /**
1018          * Deletes node
1019          * @param node
1020          * @ignore
1021          */
1022         var deleteNode = function deleteNode(node) {
1023             if (!node) {
1024                 return;
1025             }
1026             if (!node.parentNode) {
1027                 // if there's no parent, there's nothing to do
1028                 return;
1029             }
1030             if (!isIE() || (isIE() && isIE9Plus())) {
1031                 // nothing special required
1032                 node.parentNode.removeChild(node);
1033                 return;
1034             }
1035             // The rest of this code is specialcasing for IE
1036             if (node.nodeName.toLowerCase() === "body") {
1037                 // special case for removing body under IE.
1038                 deleteChildren(node);
1039                 try {
1040                     node.outerHTML = '';
1041                 } catch (ex) {
1042                     // fails under some circumstances, but not in RI
1043                     // supplied responses.  If we've gotten here, it's
1044                     // fairly safe to leave a lingering body tag rather than
1045                     // fail outright
1046                 }
1047                 return;
1048             }
1049             var temp = node.ownerDocument.createElement('div');
1050             var parent = node.parentNode;
1051             temp.appendChild(parent.removeChild(node));
1052             // Now clean up the temporary element
1053             try {
1054                 temp.outerHTML = ''; //prevent leak in IE
1055             } catch (ex) {
1056                 // at least we tried.  Fails in some circumstances,
1057                 // but not in RI supplied responses.  Better to leave a lingering
1058                 // temporary div than to fail outright.
1059             }
1060         };
1061 
1062         /**
1063          * Deletes all children of a node
1064          * @param node
1065          * @ignore
1066          */
1067         var deleteChildren = function deleteChildren(node) {
1068             if (!node) {
1069                 return;
1070             }
1071             for (var x = node.childNodes.length - 1; x >= 0; x--) { //delete all of node's children
1072                 var childNode = node.childNodes[x];
1073                 deleteNode(childNode);
1074             }
1075         };
1076 
1077         /**
1078          * <p> Copies the childNodes of nodeFrom to nodeTo</p>
1079          *
1080          * @param  nodeFrom the Node to copy the childNodes from
1081          * @param  nodeTo the Node to copy the childNodes to
1082          * @ignore
1083          * Note:  This code originally from Sarissa:  http://dev.abiss.gr/sarissa
1084          * It has been modified to fit into the overall codebase
1085          */
1086         var copyChildNodes = function copyChildNodes(nodeFrom, nodeTo) {
1087 
1088             if ((!nodeFrom) || (!nodeTo)) {
1089                 throw "Both source and destination nodes must be provided";
1090             }
1091 
1092             deleteChildren(nodeTo);
1093             var nodes = nodeFrom.childNodes;
1094             // if within the same doc, just move, else copy and delete
1095             if (nodeFrom.ownerDocument == nodeTo.ownerDocument) {
1096                 while (nodeFrom.firstChild) {
1097                     nodeTo.appendChild(nodeFrom.firstChild);
1098                 }
1099             } else {
1100                 var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;
1101                 var i;
1102                 if (typeof(ownerDoc.importNode) != "undefined") {
1103                     for (i = 0; i < nodes.length; i++) {
1104                         nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));
1105                     }
1106                 } else {
1107                     for (i = 0; i < nodes.length; i++) {
1108                         nodeTo.appendChild(nodes[i].cloneNode(true));
1109                     }
1110                 }
1111             }
1112         };
1113 
1114 
1115         /**
1116          * Replace one node with another.  Necessary for handling IE memory leak.
1117          * @param node
1118          * @param newNode
1119          * @ignore
1120          */
1121         var replaceNode = function replaceNode(newNode, node) {
1122                if(isIE()){
1123                     node.parentNode.insertBefore(newNode, node);
1124                     deleteNode(node);
1125                } else {
1126                     node.parentNode.replaceChild(newNode, node);
1127                }
1128         };
1129 
1130         /**
1131          * @ignore
1132          */
1133         var propertyToAttribute = function propertyToAttribute(name) {
1134             if (name === 'className') {
1135                 return 'class';
1136             } else if (name === 'xmllang') {
1137                 return 'xml:lang';
1138             } else {
1139                 return name.toLowerCase();
1140             }
1141         };
1142 
1143         /**
1144          * @ignore
1145          */
1146         var isFunctionNative = function isFunctionNative(func) {
1147             return /^\s*function[^{]+{\s*\[native code\]\s*}\s*$/.test(String(func));
1148         };
1149 
1150         /**
1151          * @ignore
1152          */
1153         var detectAttributes = function detectAttributes(element) {
1154             //test if 'hasAttribute' method is present and its native code is intact
1155             //for example, Prototype can add its own implementation if missing
1156             if (element.hasAttribute && isFunctionNative(element.hasAttribute)) {
1157                 return function(name) {
1158                     return element.hasAttribute(name);
1159                 }
1160             } else {
1161                 try {
1162                     //when accessing .getAttribute method without arguments does not throw an error then the method is not available
1163                     element.getAttribute;
1164 
1165                     var html = element.outerHTML;
1166                     var startTag = html.match(/^<[^>]*>/)[0];
1167                     return function(name) {
1168                         return startTag.indexOf(name + '=') > -1;
1169                     }
1170                 } catch (ex) {
1171                     return function(name) {
1172                         return element.getAttribute(name);
1173                     }
1174                 }
1175             }
1176         };
1177 
1178         /**
1179          * copy all attributes from one element to another - except id
1180          * @param target element to copy attributes to
1181          * @param source element to copy attributes from
1182          * @ignore
1183          */
1184         var cloneAttributes = function cloneAttributes(target, source) {
1185 
1186             // enumerate core element attributes - without 'dir' as special case
1187             var coreElementProperties = ['className', 'title', 'lang', 'xmllang'];
1188             // enumerate additional input element attributes
1189             var inputElementProperties = [
1190                 'name', 'value', 'size', 'maxLength', 'src', 'alt', 'useMap', 'tabIndex', 'accessKey', 'accept', 'type'
1191             ];
1192             // enumerate additional boolean input attributes
1193             var inputElementBooleanProperties = [
1194                 'checked', 'disabled', 'readOnly'
1195             ];
1196 
1197             // Enumerate all the names of the event listeners
1198             var listenerNames =
1199                 [ 'onclick', 'ondblclick', 'onmousedown', 'onmousemove', 'onmouseout',
1200                     'onmouseover', 'onmouseup', 'onkeydown', 'onkeypress', 'onkeyup',
1201                     'onhelp', 'onblur', 'onfocus', 'onchange', 'onload', 'onunload', 'onabort',
1202                     'onreset', 'onselect', 'onsubmit'
1203                 ];
1204 
1205             var sourceAttributeDetector = detectAttributes(source);
1206             var targetAttributeDetector = detectAttributes(target);
1207 
1208             var isInputElement = target.nodeName.toLowerCase() === 'input';
1209             var propertyNames = isInputElement ? coreElementProperties.concat(inputElementProperties) : coreElementProperties;
1210             var isXML = !source.ownerDocument.contentType || source.ownerDocument.contentType == 'text/xml';
1211             for (var iIndex = 0, iLength = propertyNames.length; iIndex < iLength; iIndex++) {
1212                 var propertyName = propertyNames[iIndex];
1213                 var attributeName = propertyToAttribute(propertyName);
1214                 if (sourceAttributeDetector(attributeName)) {
1215                 
1216                     //With IE 7 (quirks or standard mode) and IE 8/9 (quirks mode only), 
1217                     //you cannot get the attribute using 'class'. You must use 'className'
1218                     //which is the same value you use to get the indexed property. The only 
1219                     //reliable way to detect this (without trying to evaluate the browser
1220                     //mode and version) is to compare the two return values using 'className' 
1221                     //to see if they exactly the same.  If they are, then use the property
1222                     //name when using getAttribute.
1223                     if( attributeName == 'class'){
1224                         if( isIE() && (source.getAttribute(propertyName) === source[propertyName]) ){
1225                             attributeName = propertyName;
1226                         }
1227                     }
1228 
1229                     var newValue = isXML ? source.getAttribute(attributeName) : source[propertyName];
1230                     var oldValue = target[propertyName];
1231                     if (oldValue != newValue) {
1232                         target[propertyName] = newValue;
1233                     }
1234                 } else {
1235                     //setting property to '' seems to be the only cross-browser method for removing an attribute
1236                     //avoid setting 'value' property to '' for checkbox and radio input elements because then the
1237                     //'value' is used instead of the 'checked' property when the form is serialized by the browser
1238                     if (attributeName == "value" && (target.type != 'checkbox' && target.type != 'radio')) {
1239                          target[propertyName] = '';
1240                     }
1241                     target.removeAttribute(attributeName);
1242                 }
1243             }
1244 
1245             var booleanPropertyNames = isInputElement ? inputElementBooleanProperties : [];
1246             for (var jIndex = 0, jLength = booleanPropertyNames.length; jIndex < jLength; jIndex++) {
1247                 var booleanPropertyName = booleanPropertyNames[jIndex];
1248                 var newBooleanValue = source[booleanPropertyName];
1249                 var oldBooleanValue = target[booleanPropertyName];
1250                 if (oldBooleanValue != newBooleanValue) {
1251                     target[booleanPropertyName] = newBooleanValue;
1252                 }
1253             }
1254 
1255             //'style' attribute special case
1256             if (sourceAttributeDetector('style')) {
1257                 var newStyle;
1258                 var oldStyle;
1259                 if (isIE()) {
1260                     newStyle = source.style.cssText;
1261                     oldStyle = target.style.cssText;
1262                     if (newStyle != oldStyle) {
1263                         target.style.cssText = newStyle;
1264                     }
1265                 } else {
1266                     newStyle = source.getAttribute('style');
1267                     oldStyle = target.getAttribute('style');
1268                     if (newStyle != oldStyle) {
1269                         target.setAttribute('style', newStyle);
1270                     }
1271                 }
1272             } else if (targetAttributeDetector('style')){
1273                 target.removeAttribute('style');
1274             }
1275 
1276             // Special case for 'dir' attribute
1277             if (!isIE() && source.dir != target.dir) {
1278                 if (sourceAttributeDetector('dir')) {
1279                     target.dir = source.dir;
1280                 } else if (targetAttributeDetector('dir')) {
1281                     target.dir = '';
1282                 }
1283             }
1284 
1285             for (var lIndex = 0, lLength = listenerNames.length; lIndex < lLength; lIndex++) {
1286                 var name = listenerNames[lIndex];
1287                 target[name] = source[name] ? source[name] : null;
1288                 if (source[name]) {
1289                     source[name] = null;
1290                 }
1291             }
1292 
1293             //clone HTML5 data-* attributes
1294             try{
1295                 var targetDataset = target.dataset;
1296                 var sourceDataset = source.dataset;
1297                 if (targetDataset || sourceDataset) {
1298                     //cleanup the dataset
1299                     for (var tp in targetDataset) {
1300                         delete targetDataset[tp];
1301                     }
1302                     //copy dataset's properties
1303                     for (var sp in sourceDataset) {
1304                         targetDataset[sp] = sourceDataset[sp];
1305                     }
1306                 }
1307             } catch (ex) {
1308                 //most probably dataset properties are not supported
1309             }
1310         };
1311 
1312         /**
1313          * Replace an element from one document into another
1314          * @param newElement new element to put in document
1315          * @param origElement original element to replace
1316          * @ignore
1317          */
1318         var elementReplace = function elementReplace(newElement, origElement) {
1319             copyChildNodes(newElement, origElement);
1320             // sadly, we have to reparse all over again
1321             // to reregister the event handlers and styles
1322             // PENDING do some performance tests on large pages
1323             origElement.innerHTML = origElement.innerHTML;
1324 
1325             try {
1326                 cloneAttributes(origElement, newElement);
1327             } catch (ex) {
1328                 // if in dev mode, report an error, else try to limp onward
1329                 if (jsf.getProjectStage() == "Development") {
1330                     throw new Error("Error updating attributes");
1331                 }
1332             }
1333             deleteNode(newElement);
1334 
1335         };
1336 
1337         /**
1338          * Create a new document, then select the body element within it
1339          * @param docStr Stringified version of document to create
1340          * @return element the body element
1341          * @ignore
1342          */
1343         var getBodyElement = function getBodyElement(docStr) {
1344 
1345             var doc;  // intermediate document we'll create
1346             var body; // Body element to return
1347 
1348             if (typeof DOMParser !== "undefined") {  // FF, S, Chrome
1349                 doc = (new DOMParser()).parseFromString(docStr, "text/xml");
1350             } else if (typeof ActiveXObject !== "undefined") { // IE
1351                 doc = new ActiveXObject("MSXML2.DOMDocument");
1352                 doc.loadXML(docStr);
1353             } else {
1354                 throw new Error("You don't seem to be running a supported browser");
1355             }
1356 
1357             if (getParseErrorText(doc) !== PARSED_OK) {
1358                 throw new Error(getParseErrorText(doc));
1359             }
1360 
1361             body = doc.getElementsByTagName("body")[0];
1362 
1363             if (!body) {
1364                 throw new Error("Can't find body tag in returned document.");
1365             }
1366 
1367             return body;
1368         };
1369 
1370         /**
1371          * Find encoded url field for a given form.
1372          * @param form
1373          * @ignore
1374          */
1375         var getEncodedUrlElement = function getEncodedUrlElement(form) {
1376             var encodedUrlElement = form['javax.faces.encodedURL'];
1377 
1378             if (encodedUrlElement) {
1379                 return encodedUrlElement;
1380             } else {
1381                 var formElements = form.elements;
1382                 for (var i = 0, length = formElements.length; i < length; i++) {
1383                     var formElement = formElements[i];
1384                     if (formElement.name && (formElement.name.indexOf('javax.faces.encodedURL') >= 0)) {
1385                         return formElement;
1386                     }
1387                 }
1388             }
1389 
1390             return undefined;
1391         };
1392 
1393         /**
1394          * Update hidden state fields from the server into the DOM for any JSF forms which need to be updated.
1395          * This covers at least the form that submitted the request and any form that is covered in the render target list.
1396          * 
1397          * @param updateElement The update element of partial response holding the state value.
1398          * @param context An object containing the request context, including the following properties:
1399          * the source element, per call onerror callback function, per call onevent callback function, the render
1400          * instructions, the submitting form ID, the naming container ID and naming container prefix.
1401          * @param hiddenStateFieldName The hidden state field name, e.g. javax.faces.ViewState or javax.faces.ClientWindow 
1402          * @ignore
1403          */
1404         var updateHiddenStateFields = function updateHiddenStateFields(updateElement, context, hiddenStateFieldName) {
1405             var firstChild = updateElement.firstChild;
1406             var state = (typeof firstChild.wholeText !== 'undefined') ? firstChild.wholeText : firstChild.nodeValue;
1407             var formsToUpdate = getFormsToUpdate(context);
1408 
1409             for (var i = 0; i < formsToUpdate.length; i++) {
1410                 var formToUpdate = formsToUpdate[i];
1411                 var field = getHiddenStateField(formToUpdate, hiddenStateFieldName, context.namingContainerPrefix);
1412                 if (typeof field == "undefined") {
1413                     field = document.createElement("input");
1414                     field.type = "hidden";
1415                     field.name = context.namingContainerPrefix + hiddenStateFieldName;
1416                     formToUpdate.appendChild(field);
1417                 }
1418                 field.value = state;
1419             }
1420         }
1421 
1422         /**
1423          * Find hidden state field for a given form.
1424          * @param form The form to find hidden state field in.
1425          * @param hiddenStateFieldName The hidden state field name, e.g. javax.faces.ViewState or javax.faces.ClientWindow 
1426          * @param namingContainerPrefix The naming container prefix, if any (the view root ID suffixed with separator character).
1427          * @ignore
1428          */
1429         var getHiddenStateField = function getHiddenStateField(form, hiddenStateFieldName, namingContainerPrefix) {
1430             namingContainerPrefix = namingContainerPrefix || "";
1431             var field = form[namingContainerPrefix + hiddenStateFieldName];
1432 
1433             if (field) {
1434                 return field;
1435             }
1436             else {
1437                 var formElements = form.elements;
1438 
1439                 for (var i = 0, length = formElements.length; i < length; i++) {
1440                     var formElement = formElements[i];
1441 
1442                     if (formElement.name && (formElement.name.indexOf(hiddenStateFieldName) >= 0)) {
1443                         return formElement;
1444                     }
1445                 }
1446             }
1447 
1448             return undefined;
1449         };
1450 
1451         /**
1452          * Do update.
1453          * @param updateElement The update element of partial response.
1454          * @param context An object containing the request context, including the following properties:
1455          * the source element, per call onerror callback function, per call onevent callback function, the render
1456          * instructions, the submitting form ID, the naming container ID and naming container prefix.
1457          * @ignore
1458          */
1459         var doUpdate = function doUpdate(updateElement, context) {
1460             var id, content, markup;
1461             var scripts = []; // temp holding value for array of script nodes
1462 
1463             id = updateElement.getAttribute('id');
1464             var viewStateRegex = new RegExp(context.namingContainerPrefix + "javax.faces.ViewState" + jsf.separatorchar + ".+$");
1465             var windowIdRegex = new RegExp(context.namingContainerPrefix + "javax.faces.ClientWindow" + jsf.separatorchar + ".+$");
1466 
1467             if (id.match(viewStateRegex)) {
1468                 updateHiddenStateFields(updateElement, context, "javax.faces.ViewState");
1469                 return;
1470             } else if (id.match(windowIdRegex)) {
1471                 updateHiddenStateFields(updateElement, context, "javax.faces.ClientWindow");
1472                 return;
1473             }
1474 
1475             // join the CDATA sections in the markup
1476             markup = '';
1477             for (var j = 0; j < updateElement.childNodes.length; j++) {
1478                 content = updateElement.childNodes[j];
1479                 markup += content.nodeValue;
1480             }
1481 
1482             var src = markup;
1483 
1484             // If our special render all markup is present..
1485             if (id === "javax.faces.ViewRoot" || id === "javax.faces.ViewBody") {
1486 
1487                 // spec790: If UIViewRoot is currently being updated,
1488                 // then it means that ajax navigation has taken place.
1489                 // So, ensure that context.render has correct value for this condition,
1490                 // because this is not necessarily correclty specified during the request.
1491                 context.render = "@all";
1492 
1493                 var bodyStartEx = new RegExp("< *body[^>]*>", "gi");
1494                 var bodyEndEx = new RegExp("< */ *body[^>]*>", "gi");
1495                 var newsrc;
1496 
1497                 var docBody = document.getElementsByTagName("body")[0];
1498                 var bodyStart = bodyStartEx.exec(src);
1499 
1500                 if (bodyStart !== null) { // replace body tag
1501                     // First, try with XML manipulation
1502                     try {
1503                         runStylesheets(src);
1504                         // Get scripts from text
1505                         scripts = getScripts(src);
1506                         // Remove scripts from text
1507                         newsrc = removeScripts(src);
1508                         elementReplace(getBodyElement(newsrc), docBody);
1509                         runScripts(scripts);
1510                     } catch (e) {
1511                         // OK, replacing the body didn't work with XML - fall back to quirks mode insert
1512                         var srcBody, bodyEnd;
1513                         // if src contains </body>
1514                         bodyEnd = bodyEndEx.exec(src);
1515                         if (bodyEnd !== null) {
1516                             srcBody = src.substring(bodyStartEx.lastIndex, bodyEnd.index);
1517                         } else { // can't find the </body> tag, punt
1518                             srcBody = src.substring(bodyStartEx.lastIndex);
1519                         }
1520                         // replace body contents with innerHTML - note, script handling happens within function
1521                         elementReplaceStr(docBody, "body", srcBody);
1522 
1523                     }
1524 
1525                 } else {  // replace body contents with innerHTML - note, script handling happens within function
1526                     elementReplaceStr(docBody, "body", src);
1527                 }
1528             } else if (id === "javax.faces.ViewHead") {
1529                 throw new Error("javax.faces.ViewHead not supported - browsers cannot reliably replace the head's contents");
1530             } else if (id === "javax.faces.Resource") {
1531                 runStylesheets(src);
1532                 scripts = getScripts(src);
1533                 runScripts(scripts);
1534             } else {
1535                 var element = $(id);
1536                 if (!element) {
1537                     throw new Error("During update: " + id + " not found");
1538                 }
1539 
1540                 if (context.namingContainerId && id == context.namingContainerId) {
1541                     // spec790: If UIViewRoot is a NamingContainer and this is currently being updated,
1542                     // then it means that ajax navigation has taken place.
1543                     // So, ensure that context.render has correct value for this condition,
1544                     // because this is not necessarily correclty specified during the request.
1545                     context.render = context.namingContainerId;
1546                 }
1547 
1548                 var parent = element.parentNode;
1549                 // Trim space padding before assigning to innerHTML
1550                 var html = src.replace(/^\s+/g, '').replace(/\s+$/g, '');
1551                 var parserElement = document.createElement('div');
1552                 var tag = element.nodeName.toLowerCase();
1553                 var tableElements = ['td', 'th', 'tr', 'tbody', 'thead', 'tfoot'];
1554                 var isInTable = false;
1555                 for (var tei = 0, tel = tableElements.length; tei < tel; tei++) {
1556                     if (tableElements[tei] == tag) {
1557                         isInTable = true;
1558                         break;
1559                     }
1560                 }
1561                 if (isInTable) {
1562 
1563                     if (isAutoExec()) {
1564                         // Create html
1565                         parserElement.innerHTML = '<table>' + html + '</table>';
1566                     } else {
1567                         // Get the scripts from the text
1568                         scripts = getScripts(html);
1569                         // Remove scripts from text
1570                         html = removeScripts(html);
1571                         parserElement.innerHTML = '<table>' + html + '</table>';
1572                     }
1573                     var newElement = parserElement.firstChild;
1574                     //some browsers will also create intermediary elements such as table>tbody>tr>td
1575                     while ((null !== newElement) && (id !== newElement.id)) {
1576                         newElement = newElement.firstChild;
1577                     }
1578                     parent.replaceChild(newElement, element);
1579                     runScripts(scripts);
1580                 } else if (element.nodeName.toLowerCase() === 'input') {
1581                     // special case handling for 'input' elements
1582                     // in order to not lose focus when updating,
1583                     // input elements need to be added in place.
1584                     parserElement = document.createElement('div');
1585                     parserElement.innerHTML = html;
1586                     newElement = parserElement.firstChild;
1587 
1588                     cloneAttributes(element, newElement);
1589                     deleteNode(parserElement);
1590                 } else if (html.length > 0) {
1591                     if (isAutoExec()) {
1592                         // Create html
1593                         parserElement.innerHTML = html;
1594                     } else {
1595                         // Get the scripts from the text
1596                         scripts = getScripts(html);
1597                         // Remove scripts from text
1598                         html = removeScripts(html);
1599                         parserElement.innerHTML = html;
1600                     }
1601                     replaceNode(parserElement.firstChild, element);
1602                     deleteNode(parserElement);
1603                     runScripts(scripts);
1604                 }
1605             }
1606         };
1607 
1608         /**
1609          * Delete a node specified by the element.
1610          * @param element
1611          * @ignore
1612          */
1613         var doDelete = function doDelete(element) {
1614             var id = element.getAttribute('id');
1615             var target = $(id);
1616             deleteNode(target);
1617         };
1618 
1619         /**
1620          * Insert a node specified by the element.
1621          * @param element
1622          * @ignore
1623          */
1624         var doInsert = function doInsert(element) {
1625             var tablePattern = new RegExp("<\\s*(td|th|tr|tbody|thead|tfoot)", "i");
1626             var scripts = [];
1627             var target = $(element.firstChild.getAttribute('id'));
1628             var parent = target.parentNode;
1629             var html = element.firstChild.firstChild.nodeValue;
1630             var isInTable = tablePattern.test(html);
1631 
1632             if (!isAutoExec())  {
1633                 // Get the scripts from the text
1634                 scripts = getScripts(html);
1635                 // Remove scripts from text
1636                 html = removeScripts(html);
1637             }
1638             var tempElement = document.createElement('div');
1639             var newElement = null;
1640             if (isInTable)  {
1641                 tempElement.innerHTML = '<table>' + html + '</table>';
1642                 newElement = tempElement.firstChild;
1643                 //some browsers will also create intermediary elements such as table>tbody>tr>td
1644                 //test for presence of id on the new element since we do not have it directly
1645                 while ((null !== newElement) && ("" == newElement.id)) {
1646                     newElement = newElement.firstChild;
1647                 }
1648             } else {
1649                 tempElement.innerHTML = html;
1650                 newElement = tempElement.firstChild;
1651             }
1652 
1653             if (element.firstChild.nodeName === 'after') {
1654                 // Get the next in the list, to insert before
1655                 target = target.nextSibling;
1656             }  // otherwise, this is a 'before' element
1657             if (!!tempElement.innerHTML) { // check if only scripts were inserted - if so, do nothing here
1658                 parent.insertBefore(newElement, target);
1659             }
1660             runScripts(scripts);
1661             deleteNode(tempElement);
1662         };
1663 
1664         /**
1665          * Modify attributes of given element id.
1666          * @param element
1667          * @ignore
1668          */
1669         var doAttributes = function doAttributes(element) {
1670 
1671             // Get id of element we'll act against
1672             var id = element.getAttribute('id');
1673 
1674             var target = $(id);
1675 
1676             if (!target) {
1677                 throw new Error("The specified id: " + id + " was not found in the page.");
1678             }
1679 
1680             // There can be multiple attributes modified.  Loop through the list.
1681             var nodes = element.childNodes;
1682             for (var i = 0; i < nodes.length; i++) {
1683                 var name = nodes[i].getAttribute('name');
1684                 var value = nodes[i].getAttribute('value');
1685 
1686                 //boolean attribute handling code for all browsers
1687                 if (name === 'disabled') {
1688                     target.disabled = value === 'disabled' || value === 'true';
1689                     return;
1690                 } else if (name === 'checked') {
1691                     target.checked = value === 'checked' || value === 'on' || value === 'true';
1692                     return;
1693                 } else if (name == 'readonly') {
1694                     target.readOnly = value === 'readonly' || value === 'true';
1695                     return;
1696                 }
1697 
1698                 if (!isIE()) {
1699                     if (name === 'value') {
1700                         target.value = value;
1701                     } else {
1702                         target.setAttribute(name, value);
1703                     }
1704                 } else { // if it's IE, then quite a bit more work is required
1705                     if (name === 'class') {
1706                         target.className = value;
1707                     } else if (name === "for") {
1708                         name = 'htmlFor';
1709                         target.setAttribute(name, value, 0);
1710                     } else if (name === 'style') {
1711                         target.style.setAttribute('cssText', value, 0);
1712                     } else if (name.substring(0, 2) === 'on') {
1713                         var c = document.body.appendChild(document.createElement('span'));
1714                         try {
1715                             c.innerHTML = '<span ' + name + '="' + value + '"/>';
1716                             target[name] = c.firstChild[name];
1717                         } finally {
1718                             document.body.removeChild(c);
1719                         }
1720                     } else if (name === 'dir') {
1721                         if (jsf.getProjectStage() == 'Development') {
1722                             throw new Error("Cannot set 'dir' attribute in IE");
1723                         }
1724                     } else {
1725                         target.setAttribute(name, value, 0);
1726                     }
1727                 }
1728             }
1729         };
1730 
1731         /**
1732          * Eval the CDATA of the element.
1733          * @param element to eval
1734          * @ignore
1735          */
1736         var doEval = function doEval(element) {
1737             var evalText = '';
1738             var childNodes = element.childNodes;
1739             for (var i = 0; i < childNodes.length; i++) {
1740                 evalText += childNodes[i].nodeValue;
1741             }
1742             globalEval(evalText);
1743         };
1744 
1745         /**
1746          * Ajax Request Queue
1747          * @ignore
1748          */
1749         var Queue = new function Queue() {
1750 
1751             // Create the internal queue
1752             var queue = [];
1753 
1754 
1755             // the amount of space at the front of the queue, initialised to zero
1756             var queueSpace = 0;
1757 
1758             /** Returns the size of this Queue. The size of a Queue is equal to the number
1759              * of elements that have been enqueued minus the number of elements that have
1760              * been dequeued.
1761              * @ignore
1762              */
1763             this.getSize = function getSize() {
1764                 return queue.length - queueSpace;
1765             };
1766 
1767             /** Returns true if this Queue is empty, and false otherwise. A Queue is empty
1768              * if the number of elements that have been enqueued equals the number of
1769              * elements that have been dequeued.
1770              * @ignore
1771              */
1772             this.isEmpty = function isEmpty() {
1773                 return (queue.length === 0);
1774             };
1775 
1776             /** Enqueues the specified element in this Queue.
1777              *
1778              * @param element - the element to enqueue
1779              * @ignore
1780              */
1781             this.enqueue = function enqueue(element) {
1782                 // Queue the request
1783                 queue.push(element);
1784             };
1785 
1786 
1787             /** Dequeues an element from this Queue. The oldest element in this Queue is
1788              * removed and returned. If this Queue is empty then undefined is returned.
1789              *
1790              * @returns Object The element that was removed from the queue.
1791              * @ignore
1792              */
1793             this.dequeue = function dequeue() {
1794                 // initialise the element to return to be undefined
1795                 var element = undefined;
1796 
1797                 // check whether the queue is empty
1798                 if (queue.length) {
1799                     // fetch the oldest element in the queue
1800                     element = queue[queueSpace];
1801 
1802                     // update the amount of space and check whether a shift should occur
1803                     if (++queueSpace * 2 >= queue.length) {
1804                         // set the queue equal to the non-empty portion of the queue
1805                         queue = queue.slice(queueSpace);
1806                         // reset the amount of space at the front of the queue
1807                         queueSpace = 0;
1808                     }
1809                 }
1810                 // return the removed element
1811                 try {
1812                     return element;
1813                 } finally {
1814                     element = null; // IE 6 leak prevention
1815                 }
1816             };
1817 
1818             /** Returns the oldest element in this Queue. If this Queue is empty then
1819              * undefined is returned. This function returns the same value as the dequeue
1820              * function, but does not remove the returned element from this Queue.
1821              * @ignore
1822              */
1823             this.getOldestElement = function getOldestElement() {
1824                 // initialise the element to return to be undefined
1825                 var element = undefined;
1826 
1827                 // if the queue is not element then fetch the oldest element in the queue
1828                 if (queue.length) {
1829                     element = queue[queueSpace];
1830                 }
1831                 // return the oldest element
1832                 try {
1833                     return element;
1834                 } finally {
1835                     element = null; //IE 6 leak prevention
1836                 }
1837             };
1838         }();
1839 
1840 
1841         /**
1842          * AjaxEngine handles Ajax implementation details.
1843          * @ignore
1844          */
1845         var AjaxEngine = function AjaxEngine(context) {
1846 
1847             var req = {};                  // Request Object
1848             req.url = null;                // Request URL
1849             req.context = context;              // Context of request and response
1850             req.context.sourceid = null;   // Source of this request
1851             req.context.onerror = null;    // Error handler for request
1852             req.context.onevent = null;    // Event handler for request
1853             req.context.namingContainerId = null;   // If UIViewRoot is an instance of NamingContainer this represents its ID.
1854             req.context.namingContainerPrefix = null;   // If UIViewRoot is an instance of NamingContainer this represents its ID suffixed with separator character, else an empty string.
1855             req.xmlReq = null;             // XMLHttpRequest Object
1856             req.async = true;              // Default - Asynchronous
1857             req.parameters = {};           // Parameters For GET or POST
1858             req.queryString = null;        // Encoded Data For GET or POST
1859             req.method = null;             // GET or POST
1860             req.status = null;             // Response Status Code From Server
1861             req.fromQueue = false;         // Indicates if the request was taken off the queue before being sent. This prevents the request from entering the queue redundantly.
1862 
1863             req.que = Queue;
1864             
1865             // Get a transport Handle
1866             // The transport will be an iframe transport if the form
1867             // has multipart encoding type.  This is where we could
1868             // handle XMLHttpRequest Level2 as well (perhaps 
1869             // something like:  if ('upload' in req.xmlReq)'
1870             req.xmlReq = getTransport(context);
1871 
1872             if (req.xmlReq === null) {
1873                 return null;
1874             }
1875 
1876             /**
1877              * @ignore
1878              */
1879             function noop() {}
1880             
1881             // Set up request/response state callbacks
1882             /**
1883              * @ignore
1884              */
1885             req.xmlReq.onreadystatechange = function() {
1886                 if (req.xmlReq.readyState === 4) {
1887                     req.onComplete();
1888                     // next two lines prevent closure/ciruclar reference leaks
1889                     // of XHR instances in IE
1890                     req.xmlReq.onreadystatechange = noop;
1891                     req.xmlReq = null;
1892                 }
1893             };
1894 
1895             /**
1896              * This function is called when the request/response interaction
1897              * is complete.  If the return status code is successfull,
1898              * dequeue all requests from the queue that have completed.  If a
1899              * request has been found on the queue that has not been sent,
1900              * send the request.
1901              * @ignore
1902              */
1903             req.onComplete = function onComplete() {
1904                 if (req.xmlReq.status && (req.xmlReq.status >= 200 && req.xmlReq.status < 300)) {
1905                     sendEvent(req.xmlReq, req.context, "complete");
1906                     jsf.ajax.response(req.xmlReq, req.context);
1907                 } else {
1908                     sendEvent(req.xmlReq, req.context, "complete");
1909                     sendError(req.xmlReq, req.context, "httpError");
1910                 }
1911 
1912                 // Regardless of whether the request completed successfully (or not),
1913                 // dequeue requests that have been completed (readyState 4) and send
1914                 // requests that ready to be sent (readyState 0).
1915 
1916                 var nextReq = req.que.getOldestElement();
1917                 if (nextReq === null || typeof nextReq === 'undefined') {
1918                     return;
1919                 }
1920                 while ((typeof nextReq.xmlReq !== 'undefined' && nextReq.xmlReq !== null) &&
1921                        nextReq.xmlReq.readyState === 4) {
1922                     req.que.dequeue();
1923                     nextReq = req.que.getOldestElement();
1924                     if (nextReq === null || typeof nextReq === 'undefined') {
1925                         break;
1926                     }
1927                 }
1928                 if (nextReq === null || typeof nextReq === 'undefined') {
1929                     return;
1930                 }
1931                 if ((typeof nextReq.xmlReq !== 'undefined' && nextReq.xmlReq !== null) &&
1932                     nextReq.xmlReq.readyState === 0) {
1933                     nextReq.fromQueue = true;
1934                     nextReq.sendRequest();
1935                 }
1936             };
1937 
1938             /**
1939              * Utility method that accepts additional arguments for the AjaxEngine.
1940              * If an argument is passed in that matches an AjaxEngine property, the
1941              * argument value becomes the value of the AjaxEngine property.
1942              * Arguments that don't match AjaxEngine properties are added as
1943              * request parameters.
1944              * @ignore
1945              */
1946             req.setupArguments = function(args) {
1947                 for (var i in args) {
1948                     if (args.hasOwnProperty(i)) {
1949                         if (typeof req[i] === 'undefined') {
1950                             req.parameters[i] = args[i];
1951                         } else {
1952                             req[i] = args[i];
1953                         }
1954                     }
1955                 }
1956             };
1957 
1958             /**
1959              * This function does final encoding of parameters, determines the request method
1960              * (GET or POST) and sends the request using the specified url.
1961              * @ignore
1962              */
1963             req.sendRequest = function() {
1964                 if (req.xmlReq !== null) {
1965                     // if there is already a request on the queue waiting to be processed..
1966                     // just queue this request
1967                     if (!req.que.isEmpty()) {
1968                         if (!req.fromQueue) {
1969                             req.que.enqueue(req);
1970                             return;
1971                         }
1972                     }
1973                     // If the queue is empty, queue up this request and send
1974                     if (!req.fromQueue) {
1975                         req.que.enqueue(req);
1976                     }
1977                     // Some logic to get the real request URL
1978                     if (req.generateUniqueUrl && req.method == "GET") {
1979                         req.parameters["AjaxRequestUniqueId"] = new Date().getTime() + "" + req.requestIndex;
1980                     }
1981                     var content = null; // For POST requests, to hold query string
1982                     for (var i in req.parameters) {
1983                         if (req.parameters.hasOwnProperty(i)) {
1984                             if (req.queryString.length > 0) {
1985                                 req.queryString += "&";
1986                             }
1987                             req.queryString += encodeURIComponent(i) + "=" + encodeURIComponent(req.parameters[i]);
1988                         }
1989                     }
1990                     if (req.method === "GET") {
1991                         if (req.queryString.length > 0) {
1992                             req.url += ((req.url.indexOf("?") > -1) ? "&" : "?") + req.queryString;
1993                         }
1994                     }
1995                     req.xmlReq.open(req.method, req.url, req.async);
1996                     // note that we are including the charset=UTF-8 as part of the content type (even
1997                     // if encodeURIComponent encodes as UTF-8), because with some
1998                     // browsers it will not be set in the request.  Some server implementations need to 
1999                     // determine the character encoding from the request header content type.
2000                     if (req.method === "POST") {
2001                         if (typeof req.xmlReq.setRequestHeader !== 'undefined') {
2002                             req.xmlReq.setRequestHeader('Faces-Request', 'partial/ajax');
2003                             req.xmlReq.setRequestHeader('Content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
2004                         }
2005                         content = req.queryString;
2006                     }
2007                     // note that async == false is not a supported feature.  We may change it in ways
2008                     // that break existing programs at any time, with no warning.
2009                     if(!req.async) {
2010                         req.xmlReq.onreadystatechange = null; // no need for readystate change listening
2011                     }
2012                     sendEvent(req.xmlReq, req.context, "begin");
2013                     req.xmlReq.send(content);
2014                     if(!req.async){
2015                         req.onComplete();
2016                 }
2017                 }
2018             };
2019 
2020             return req;
2021         };
2022 
2023         /**
2024          * Error handling callback.
2025          * Assumes that the request has completed.
2026          * @ignore
2027          */
2028         var sendError = function sendError(request, context, status, description, serverErrorName, serverErrorMessage) {
2029 
2030             // Possible errornames:
2031             // httpError
2032             // emptyResponse
2033             // serverError
2034             // malformedXML
2035 
2036             var sent = false;
2037             var data = {};  // data payload for function
2038             data.type = "error";
2039             data.status = status;
2040             data.source = context.sourceid;
2041             data.responseCode = request.status;
2042             data.responseXML = request.responseXML;
2043             data.responseText = request.responseText;
2044 
2045             // ensure data source is the dom element and not the ID
2046             // per 14.4.1 of the 2.0 specification.
2047             if (typeof data.source === 'string') {
2048                 data.source = document.getElementById(data.source);
2049             }
2050 
2051             if (description) {
2052                 data.description = description;
2053             } else if (status == "httpError") {
2054                 if (data.responseCode === 0) {
2055                     data.description = "The Http Transport returned a 0 status code.  This is usually the result of mixing ajax and full requests.  This is usually undesired, for both performance and data integrity reasons.";
2056                 } else {
2057                     data.description = "There was an error communicating with the server, status: " + data.responseCode;
2058                 }
2059             } else if (status == "serverError") {
2060                 data.description = serverErrorMessage;
2061             } else if (status == "emptyResponse") {
2062                 data.description = "An empty response was received from the server.  Check server error logs.";
2063             } else if (status == "malformedXML") {
2064                 if (getParseErrorText(data.responseXML) !== PARSED_OK) {
2065                     data.description = getParseErrorText(data.responseXML);
2066                 } else {
2067                     data.description = "An invalid XML response was received from the server.";
2068                 }
2069             }
2070 
2071             if (status == "serverError") {
2072                 data.errorName = serverErrorName;
2073                 data.errorMessage = serverErrorMessage;
2074             }
2075 
2076             // If we have a registered callback, send the error to it.
2077             if (context.onerror) {
2078                 context.onerror.call(null, data);
2079                 sent = true;
2080             }
2081 
2082             for (var i in errorListeners) {
2083                 if (errorListeners.hasOwnProperty(i)) {
2084                     errorListeners[i].call(null, data);
2085                     sent = true;
2086                 }
2087             }
2088 
2089             if (!sent && jsf.getProjectStage() === "Development") {
2090                 if (status == "serverError") {
2091                     alert("serverError: " + serverErrorName + " " + serverErrorMessage);
2092                 } else {
2093                     alert(status + ": " + data.description);
2094                 }
2095             }
2096         };
2097 
2098         /**
2099          * Event handling callback.
2100          * Request is assumed to have completed, except in the case of event = 'begin'.
2101          * @ignore
2102          */
2103         var sendEvent = function sendEvent(request, context, status) {
2104 
2105             var data = {};
2106             data.type = "event";
2107             data.status = status;
2108             data.source = context.sourceid;
2109             // ensure data source is the dom element and not the ID
2110             // per 14.4.1 of the 2.0 specification.
2111             if (typeof data.source === 'string') {
2112                 data.source = document.getElementById(data.source);
2113             }
2114             if (status !== 'begin') {
2115                 data.responseCode = request.status;
2116                 data.responseXML = request.responseXML;
2117                 data.responseText = request.responseText;
2118             }
2119 
2120             if (context.onevent) {
2121                 context.onevent.call(null, data);
2122             }
2123 
2124             for (var i in eventListeners) {
2125                 if (eventListeners.hasOwnProperty(i)) {
2126                     eventListeners[i].call(null, data);
2127                 }
2128             }
2129         };
2130 
2131         var unescapeHTML = function unescapeHTML(escapedHTML) {
2132             return escapedHTML
2133                 .replace(/'/g, "'")
2134                 .replace(/"/g, '"')
2135                 .replace(/>/g, '>')
2136                 .replace(/</g, '<')
2137                 .replace(/&/g, '&');
2138         };
2139 
2140         // Use module pattern to return the functions we actually expose
2141         return {
2142             /**
2143              * Register a callback for error handling.
2144              * <p><b>Usage:</b></p>
2145              * <pre><code>
2146              * jsf.ajax.addOnError(handleError);
2147              * ...
2148              * var handleError = function handleError(data) {
2149              * ...
2150              * }
2151              * </pre></code>
2152              * <p><b>Implementation Requirements:</b></p>
2153              * This function must accept a reference to an existing JavaScript function.
2154              * The JavaScript function reference must be added to a list of callbacks, making it possible
2155              * to register more than one callback by invoking <code>jsf.ajax.addOnError</code>
2156              * more than once.  This function must throw an error if the <code>callback</code>
2157              * argument is not a function.
2158              *
2159              * @member jsf.ajax
2160              * @param callback a reference to a function to call on an error
2161              */
2162             addOnError: function addOnError(callback) {
2163                 if (typeof callback === 'function') {
2164                     errorListeners[errorListeners.length] = callback;
2165                 } else {
2166                     throw new Error("jsf.ajax.addOnError:  Added a callback that was not a function.");
2167                 }
2168             },
2169             /**
2170              * Register a callback for event handling.
2171              * <p><b>Usage:</b></p>
2172              * <pre><code>
2173              * jsf.ajax.addOnEvent(statusUpdate);
2174              * ...
2175              * var statusUpdate = function statusUpdate(data) {
2176              * ...
2177              * }
2178              * </pre></code>
2179              * <p><b>Implementation Requirements:</b></p>
2180              * This function must accept a reference to an existing JavaScript function.
2181              * The JavaScript function reference must be added to a list of callbacks, making it possible
2182              * to register more than one callback by invoking <code>jsf.ajax.addOnEvent</code>
2183              * more than once.  This function must throw an error if the <code>callback</code>
2184              * argument is not a function.
2185              *
2186              * @member jsf.ajax
2187              * @param callback a reference to a function to call on an event
2188              */
2189             addOnEvent: function addOnEvent(callback) {
2190                 if (typeof callback === 'function') {
2191                     eventListeners[eventListeners.length] = callback;
2192                 } else {
2193                     throw new Error("jsf.ajax.addOnEvent: Added a callback that was not a function");
2194                 }
2195             },
2196             /**
2197 
2198              * <p><span class="changed_modified_2_2">Send</span> an
2199              * asynchronous Ajax req uest to the server.
2200 
2201              * <p><b>Usage:</b></p>
2202              * <pre><code>
2203              * Example showing all optional arguments:
2204              *
2205              * <commandButton id="button1" value="submit"
2206              *     onclick="jsf.ajax.request(this,event,
2207              *       {execute:'button1',render:'status',onevent: handleEvent,onerror: handleError});return false;"/>
2208              * </commandButton/>
2209              * </pre></code>
2210              * <p><b>Implementation Requirements:</b></p>
2211              * This function must:
2212              * <ul>
2213              * <li>Be used within the context of a <code>form</code><span class="changed_added_2_3">,
2214              * else throw an error</span>.</li>
2215              * <li>Capture the element that triggered this Ajax request
2216              * (from the <code>source</code> argument, also known as the
2217              * <code>source</code> element.</li>
2218              * <li>If the <code>source</code> element is <code>null</code> or
2219              * <code>undefined</code> throw an error.</li>
2220              * <li>If the <code>source</code> argument is not a <code>string</code> or
2221              * DOM element object, throw an error.</li>
2222              * <li>If the <code>source</code> argument is a <code>string</code>, find the
2223              * DOM element for that <code>string</code> identifier.
2224              * <li>If the DOM element could not be determined, throw an error.</li>
2225              * <li class="changed_added_2_3">If the <code>javax.faces.ViewState</code> 
2226              * element could not be found, throw an error.</li>
2227              * <li class="changed_added_2_3">If the ID of the <code>javax.faces.ViewState</code> 
2228              * element has a <code><VIEW_ROOT_CONTAINER_CLIENT_ID><SEP></code>
2229              * prefix, where <SEP> is the currently configured
2230              * <code>UINamingContainer.getSeparatorChar()</code> and
2231              * <VIEW_ROOT_CONTAINER_CLIENT_ID> is the return from
2232              * <code>UIViewRoot.getContainerClientId()</code> on the
2233              * view from whence this state originated, then remember it as <i>namespace prefix</i>.
2234              * This is needed during encoding of the set of post data arguments.</li>
2235              * <li>If the <code>onerror</code> and <code>onevent</code> arguments are set,
2236              * they must be functions, or throw an error.
2237              * <li>Determine the <code>source</code> element's <code>form</code>
2238              * element.</li>
2239              * <li>Get the <code>form</code> view state by calling
2240              * {@link jsf.getViewState} passing the
2241              * <code>form</code> element as the argument.</li>
2242              * <li>Collect post data arguments for the Ajax request.
2243              * <ul>
2244              * <li>The following name/value pairs are required post data arguments:
2245              * <table border="1">
2246              * <tr>
2247              * <th>name</th>
2248              * <th>value</th>
2249              * </tr>
2250              * <tr>
2251              * <td><code>javax.faces.ViewState</code></td>
2252              * <td><code>Contents of javax.faces.ViewState hidden field.  This is included when
2253              * {@link jsf.getViewState} is used.</code></td>
2254              * </tr>
2255              * <tr>
2256              * <td><code>javax.faces.partial.ajax</code></td>
2257              * <td><code>true</code></td>
2258              * </tr>
2259              * <tr>
2260              * <td><code>javax.faces.source</code></td>
2261              * <td><code>The identifier of the element that triggered this request.</code></td>
2262              * </tr>
2263              * <tr class="changed_added_2_2">
2264              * <td><code>javax.faces.ClientWindow</code></td>
2265 
2266              * <td><code>Call jsf.getClientWindow(), passing the current
2267              * form.  If the return is non-null, it must be set as the
2268              * value of this name/value pair, otherwise, a name/value
2269              * pair for client window must not be sent.</code></td>
2270 
2271              * </tr>
2272              * </table>
2273              * </li>
2274              * </ul>
2275              * </li>
2276              * <li>Collect optional post data arguments for the Ajax request.
2277              * <ul>
2278              * <li>Determine additional arguments (if any) from the <code>options</code>
2279              * argument. If <code>options.execute</code> exists:
2280              * <ul>
2281              * <li>If the keyword <code>@none</code> is present, do not create and send
2282              * the post data argument <code>javax.faces.partial.execute</code>.</li>
2283              * <li>If the keyword <code>@all</code> is present, create the post data argument with
2284              * the name <code>javax.faces.partial.execute</code> and the value <code>@all</code>.</li>
2285              * <li>Otherwise, there are specific identifiers that need to be sent.  Create the post
2286              * data argument with the name <code>javax.faces.partial.execute</code> and the value as a
2287              * space delimited <code>string</code> of client identifiers.</li>
2288              * </ul>
2289              * </li>
2290              * <li>If <code>options.execute</code> does not exist, create the post data argument with the
2291              * name <code>javax.faces.partial.execute</code> and the value as the identifier of the
2292              * element that caused this request.</li>
2293              * <li>If <code>options.render</code> exists:
2294              * <ul>
2295              * <li>If the keyword <code>@none</code> is present, do not create and send
2296              * the post data argument <code>javax.faces.partial.render</code>.</li>
2297              * <li>If the keyword <code>@all</code> is present, create the post data argument with
2298              * the name <code>javax.faces.partial.render</code> and the value <code>@all</code>.</li>
2299              * <li>Otherwise, there are specific identifiers that need to be sent.  Create the post
2300              * data argument with the name <code>javax.faces.partial.render</code> and the value as a
2301              * space delimited <code>string</code> of client identifiers.</li>
2302              * </ul>
2303              * <li>If <code>options.render</code> does not exist do not create and send the
2304              * post data argument <code>javax.faces.partial.render</code>.</li>
2305 
2306              * <li class="changed_added_2_2">If
2307              * <code>options.delay</code> exists let it be the value
2308              * <em>delay</em>, for this discussion.  If
2309              * <code>options.delay</code> does not exist, or is the
2310              * literal string <code>'none'</code>, without the quotes,
2311              * no delay is used.  If less than <em>delay</em>
2312              * milliseconds elapses between calls to <em>request()</em>
2313              * only the most recent one is sent and all other requests
2314              * are discarded.</li>
2315 
2316 
2317              * <li class="changed_added_2_2">If
2318              * <code>options.resetValues</code> exists and its value is
2319              * <code>true</code>, ensure a post data argument with the
2320              * name <code>javax.faces.partial.resetValues</code> and the
2321              * value <code>true</code> is sent in addition to the other
2322              * post data arguments.  This will cause
2323              * <code>UIViewRoot.resetValues()</code> to be called,
2324              * passing the value of the "render" attribute.  Note: do
2325              * not use any of the <code>@</code> keywords such as
2326              * <code>@form</code> or <code>@this</code> with this option
2327              * because <code>UIViewRoot.resetValues()</code> does not
2328              * descend into the children of the listed components.</li>
2329 
2330 
2331              * <li>Determine additional arguments (if any) from the <code>event</code>
2332              * argument.  The following name/value pairs may be used from the
2333              * <code>event</code> object:
2334              * <ul>
2335              * <li><code>target</code> - the ID of the element that triggered the event.</li>
2336              * <li><code>captured</code> - the ID of the element that captured the event.</li>
2337              * <li><code>type</code> - the type of event (ex: onkeypress)</li>
2338              * <li><code>alt</code> - <code>true</code> if ALT key was pressed.</li>
2339              * <li><code>ctrl</code> - <code>true</code> if CTRL key was pressed.</li>
2340              * <li><code>shift</code> - <code>true</code> if SHIFT key was pressed. </li>
2341              * <li><code>meta</code> - <code>true</code> if META key was pressed. </li>
2342              * <li><code>right</code> - <code>true</code> if right mouse button
2343              * was pressed. </li>
2344              * <li><code>left</code> - <code>true</code> if left mouse button
2345              * was pressed. </li>
2346              * <li><code>keycode</code> - the key code.
2347              * </ul>
2348              * </li>
2349              * </ul>
2350              * </li>
2351              * <li>Encode the set of post data arguments. <span class="changed_added_2_3">
2352              * If the <code>javax.faces.ViewState</code> element has a namespace prefix, then
2353              * make sure that all post data arguments are prefixed with this namespace prefix.
2354              * </span></li>
2355              * <li>Join the encoded view state with the encoded set of post data arguments
2356              * to form the <code>query string</code> that will be sent to the server.</li>
2357              * <li>Create a request <code>context</code> object and set the properties:
2358              * <ul><li><code>source</code> (the source DOM element for this request)</li>
2359              * <li><code>onerror</code> (the error handler for this request)</li>
2360              * <li><code>onevent</code> (the event handler for this request)</li></ul>
2361              * The request context will be used during error/event handling.</li>
2362              * <li>Send a <code>begin</code> event following the procedure as outlined
2363              * in the Chapter 13 "Sending Events" section of the spec prose document <a
2364              *  href="../../javadocs/overview-summary.html#prose_document">linked in the
2365              *  overview summary</a></li>
2366              * <li>Set the request header with the name: <code>Faces-Request</code> and the
2367              * value: <code>partial/ajax</code>.</li>
2368              * <li>Determine the <code>posting URL</code> as follows: If the hidden field
2369              * <code>javax.faces.encodedURL</code> is present in the submitting form, use its
2370              * value as the <code>posting URL</code>.  Otherwise, use the <code>action</code>
2371              * property of the <code>form</code> element as the <code>URL</code>.</li>
2372 
2373              * <li> 
2374 
2375              * <p><span class="changed_modified_2_2">Determine whether
2376              * or not the submitting form is using 
2377              * <code>multipart/form-data</code> as its
2378              * <code>enctype</code> attribute.  If not, send the request
2379              * as an <code>asynchronous POST</code> using the
2380              * <code>posting URL</code> that was determined in the
2381              * previous step.</span> <span
2382              * class="changed_added_2_2">Otherwise, send the request
2383              * using a multi-part capable transport layer, such as a
2384              * hidden inline frame.  Note that using a hidden inline
2385              * frame does <strong>not</strong> use
2386              * <code>XMLHttpRequest</code>, but the request must be sent
2387              * with all the parameters that a JSF
2388              * <code>XMLHttpRequest</code> would have been sent with.
2389              * In this way, the server side processing of the request
2390              * will be identical whether or the request is multipart or
2391              * not.</span></p>
2392             
2393              * <div class="changed_added_2_2">
2394 
2395              * <p>The <code>begin</code>, <code>complete</code>, and
2396              * <code>success</code> events must be emulated when using
2397              * the multipart transport.  This allows any listeners to
2398              * behave uniformly regardless of the multipart or
2399              * <code>XMLHttpRequest</code> nature of the transport.</p>
2400 
2401              * </div></li>
2402              * </ul>
2403              * Form serialization should occur just before the request is sent to minimize 
2404              * the amount of time between the creation of the serialized form data and the 
2405              * sending of the serialized form data (in the case of long requests in the queue).
2406              * Before the request is sent it must be put into a queue to ensure requests
2407              * are sent in the same order as when they were initiated.  The request callback function
2408              * must examine the queue and determine the next request to be sent.  The behavior of the
2409              * request callback function must be as follows:
2410              * <ul>
2411              * <li>If the request completed successfully invoke {@link jsf.ajax.response}
2412              * passing the <code>request</code> object.</li>
2413              * <li>If the request did not complete successfully, notify the client.</li>
2414              * <li>Regardless of the outcome of the request (success or error) every request in the
2415              * queue must be handled.  Examine the status of each request in the queue starting from
2416              * the request that has been in the queue the longest.  If the status of the request is
2417              * <code>complete</code> (readyState 4), dequeue the request (remove it from the queue).
2418              * If the request has not been sent (readyState 0), send the request.  Requests that are
2419              * taken off the queue and sent should not be put back on the queue.</li>
2420              * </ul>
2421              *
2422              * </p>
2423              *
2424              * @param source The DOM element that triggered this Ajax request, or an id string of the
2425              * element to use as the triggering element.
2426              * @param event The DOM event that triggered this Ajax request.  The
2427              * <code>event</code> argument is optional.
2428              * @param options The set of available options that can be sent as
2429              * request parameters to control client and/or server side
2430              * request processing. Acceptable name/value pair options are:
2431              * <table border="1">
2432              * <tr>
2433              * <th>name</th>
2434              * <th>value</th>
2435              * </tr>
2436              * <tr>
2437              * <td><code>execute</code></td>
2438              * <td><code>space seperated list of client identifiers</code></td>
2439              * </tr>
2440              * <tr>
2441              * <td><code>render</code></td>
2442              * <td><code>space seperated list of client identifiers</code></td>
2443              * </tr>
2444              * <tr>
2445              * <td><code>onevent</code></td>
2446              * <td><code>function to callback for event</code></td>
2447              * </tr>
2448              * <tr>
2449              * <td><code>onerror</code></td>
2450              * <td><code>function to callback for error</code></td>
2451              * </tr>
2452              * <tr>
2453              * <td><code>params</code></td>
2454              * <td><code>object containing parameters to include in the request</code></td>
2455              * </tr>
2456 
2457              * <tr class="changed_added_2_2">
2458 
2459              * <td><code>delay</code></td>
2460 
2461              * <td>If less than <em>delay</em> milliseconds elapses
2462              * between calls to <em>request()</em> only the most recent
2463              * one is sent and all other requests are discarded. If the
2464              * value of <em>delay</em> is the literal string
2465              * <code>'none'</code> without the quotes, or no delay is
2466              * specified, no delay is used. </td>
2467 
2468              * </tr>
2469 
2470              * <tr class="changed_added_2_2">
2471 
2472              * <td><code>resetValues</code></td>
2473 
2474              * <td>If true, ensure a post data argument with the name
2475              * javax.faces.partial.resetValues and the value true is
2476              * sent in addition to the other post data arguments. This
2477              * will cause UIViewRoot.resetValues() to be called, passing
2478              * the value of the "render" attribute. Note: do not use any
2479              * of the @ keywords such as @form or @this with this option
2480              * because UIViewRoot.resetValues() does not descend into
2481              * the children of the listed components.</td>
2482 
2483              * </tr>
2484 
2485 
2486              * </table>
2487              * The <code>options</code> argument is optional.
2488              * @member jsf.ajax
2489              * @function jsf.ajax.request
2490 
2491              * @throws Error if first required argument
2492              * <code>element</code> is not specified, or if one or more
2493              * of the components in the <code>options.execute</code>
2494              * list is a file upload component, but the form's enctype
2495              * is not set to <code>multipart/form-data</code>
2496              */
2497 
2498             request: function request(source, event, options) {
2499 
2500                 var element, form, viewStateElement;   //  Element variables
2501                 var all, none;
2502                 
2503                 var context = {};
2504 
2505                 if (typeof source === 'undefined' || source === null) {
2506                     throw new Error("jsf.ajax.request: source not set");
2507                 }
2508                 if(delayHandler) {
2509                     clearTimeout(delayHandler);
2510                     delayHandler = null;
2511                 }
2512 
2513                 // set up the element based on source
2514                 if (typeof source === 'string') {
2515                     element = document.getElementById(source);
2516                 } else if (typeof source === 'object') {
2517                     element = source;
2518                 } else {
2519                     throw new Error("jsf.ajax.request: source must be object or string");
2520                 }
2521                 // attempt to handle case of name unset
2522                 // this might be true in a badly written composite component
2523                 if (!element.name) {
2524                     element.name = element.id;
2525                 }
2526                 
2527                 context.element = element;
2528 
2529                 if (typeof(options) === 'undefined' || options === null) {
2530                     options = {};
2531                 }
2532 
2533                 // Error handler for this request
2534                 var onerror = false;
2535 
2536                 if (options.onerror && typeof options.onerror === 'function') {
2537                     onerror = options.onerror;
2538                 } else if (options.onerror && typeof options.onerror !== 'function') {
2539                     throw new Error("jsf.ajax.request: Added an onerror callback that was not a function");
2540                 }
2541 
2542                 // Event handler for this request
2543                 var onevent = false;
2544 
2545                 if (options.onevent && typeof options.onevent === 'function') {
2546                     onevent = options.onevent;
2547                 } else if (options.onevent && typeof options.onevent !== 'function') {
2548                     throw new Error("jsf.ajax.request: Added an onevent callback that was not a function");
2549                 }
2550 
2551                 form = getForm(element);
2552                 if (!form) {
2553                     throw new Error("jsf.ajax.request: Method must be called within a form");
2554                 }
2555 
2556                 viewStateElement = getHiddenStateField(form, "javax.faces.ViewState");
2557                 if (!viewStateElement) {
2558                     throw new Error("jsf.ajax.request: Form has no view state element");
2559                 }
2560                 
2561                 context.form = form;
2562                 context.formId = form.id;
2563                 
2564                 var viewState = jsf.getViewState(form);
2565 
2566                 // Set up additional arguments to be used in the request..
2567                 // Make sure "javax.faces.source" is set up.
2568                 // If there were "execute" ids specified, make sure we
2569                 // include the identifier of the source element in the
2570                 // "execute" list.  If there were no "execute" ids
2571                 // specified, determine the default.
2572 
2573                 var args = {};
2574 
2575                 var namingContainerPrefix = viewStateElement.name.substring(0, viewStateElement.name.indexOf("javax.faces.ViewState"));
2576 
2577                 args[namingContainerPrefix + "javax.faces.source"] = element.id;
2578 
2579                 if (event && !!event.type) {
2580                     args[namingContainerPrefix + "javax.faces.partial.event"] = event.type;
2581                 }
2582 
2583                 if ("resetValues" in options) {
2584                     args[namingContainerPrefix + "javax.faces.partial.resetValues"] = options.resetValues;
2585                 }
2586 
2587                 // If we have 'execute' identifiers:
2588                 // Handle any keywords that may be present.
2589                 // If @none present anywhere, do not send the
2590                 // "javax.faces.partial.execute" parameter.
2591                 // The 'execute' and 'render' lists must be space
2592                 // delimited.
2593 
2594                 if (options.execute) {
2595                     none = options.execute.indexOf("@none");
2596                     if (none < 0) {
2597                         all = options.execute.indexOf("@all");
2598                         if (all < 0) {
2599                             options.execute = options.execute.replace("@this", element.id);
2600                             options.execute = options.execute.replace("@form", form.id);
2601                             var temp = options.execute.split(' ');
2602                             if (!isInArray(temp, element.name)) {
2603                                 options.execute = element.name + " " + options.execute;
2604                             }
2605                             if (namingContainerPrefix) {
2606                                 options.execute = namespaceParametersIfNecessary(options.execute, element.name, namingContainerPrefix);
2607                             }
2608                         } else {
2609                             options.execute = "@all";
2610                         }
2611                         args[namingContainerPrefix + "javax.faces.partial.execute"] = options.execute;
2612                     }
2613                 } else {
2614                     options.execute = element.name + " " + element.id;
2615                     args[namingContainerPrefix + "javax.faces.partial.execute"] = options.execute;
2616                 }
2617 
2618                 if (options.render) {
2619                     none = options.render.indexOf("@none");
2620                     if (none < 0) {
2621                         all = options.render.indexOf("@all");
2622                         if (all < 0) {
2623                             options.render = options.render.replace("@this", element.id);
2624                             options.render = options.render.replace("@form", form.id);
2625                             if (namingContainerPrefix) {
2626                                 options.render = namespaceParametersIfNecessary(options.render, element.name, namingContainerPrefix);
2627                             }
2628                         } else {
2629                             options.render = "@all";
2630                         }
2631                         args[namingContainerPrefix + "javax.faces.partial.render"] = options.render;
2632                     }
2633                 }
2634                 var explicitlyDoNotDelay = ((typeof options.delay == 'undefined') || (typeof options.delay == 'string') &&
2635                                             (options.delay.toLowerCase() == 'none'));
2636                 var delayValue;
2637                 if (typeof options.delay == 'number') {
2638                     delayValue = options.delay;
2639                 } else  {
2640                     var converted = parseInt(options.delay);
2641                     
2642                     if (!explicitlyDoNotDelay && isNaN(converted)) {
2643                         throw new Error('invalid value for delay option: ' + options.delay);
2644                     }
2645                     delayValue = converted;
2646                 }
2647 
2648                 var checkForTypeFile
2649 
2650                 // check the execute ids to see if any include an input of type "file"
2651                 context.includesInputFile = false;
2652                 var ids = options.execute.split(" ");
2653                 if (ids == "@all") { ids = [ form.id ]; }
2654                 if (ids) {
2655                     for (i = 0; i < ids.length; i++) {
2656                         var elem = document.getElementById(ids[i]);
2657                         if (elem) {
2658                             var nodeType = elem.nodeType;
2659                             if (nodeType == Node.ELEMENT_NODE) {
2660                                 var elemAttributeDetector = detectAttributes(elem);
2661                                 if (elemAttributeDetector("type")) {
2662                                     if (elem.getAttribute("type") === "file") {
2663                                         context.includesInputFile = true;
2664                                         break;
2665                                     }
2666                                 } else {
2667                                     if (hasInputFileControl(elem)) {
2668                                         context.includesInputFile = true;
2669                                         break;
2670                                     }
2671                                 }
2672                             }
2673                         }
2674                     }
2675                 }
2676 
2677                 // copy all params to args
2678                 var params = options.params || {};
2679                 for (var property in params) {
2680                     if (params.hasOwnProperty(property)) {
2681                         args[namingContainerPrefix + property] = params[property];
2682                     }
2683                 }
2684 
2685                 // remove non-passthrough options
2686                 delete options.execute;
2687                 delete options.render;
2688                 delete options.onerror;
2689                 delete options.onevent;
2690                 delete options.delay;
2691                 delete options.resetValues;
2692                 delete options.params;
2693 
2694                 // copy all other options to args (for backwards compatibility on issue 4115)
2695                 for (var property in options) {
2696                     if (options.hasOwnProperty(property)) {
2697                         args[namingContainerPrefix + property] = options[property];
2698                     }
2699                 }
2700 
2701                 args[namingContainerPrefix + "javax.faces.partial.ajax"] = "true";
2702                 args["method"] = "POST";
2703 
2704                 // Determine the posting url
2705 
2706                 var encodedUrlField = getEncodedUrlElement(form);
2707                 if (typeof encodedUrlField == 'undefined') {
2708                     args["url"] = form.action;
2709                 } else {
2710                     args["url"] = encodedUrlField.value;
2711                 }
2712                 var sendRequest = function() {
2713                     var ajaxEngine = new AjaxEngine(context);
2714                     ajaxEngine.setupArguments(args);
2715                     ajaxEngine.queryString = viewState;
2716                     ajaxEngine.context.onevent = onevent;
2717                     ajaxEngine.context.onerror = onerror;
2718                     ajaxEngine.context.sourceid = element.id;
2719                     ajaxEngine.context.render = args[namingContainerPrefix + "javax.faces.partial.render"] || "";
2720                     ajaxEngine.context.namingContainerPrefix = namingContainerPrefix;
2721                     ajaxEngine.sendRequest();
2722 
2723                     // null out element variables to protect against IE memory leak
2724                     element = null;
2725                     form = null;
2726                     sendRequest = null;
2727                     context = null;
2728                 };
2729 
2730                 if (explicitlyDoNotDelay) {
2731                     sendRequest();
2732                 } else {
2733                     delayHandler = setTimeout(sendRequest, delayValue);
2734                 }
2735 
2736             },
2737             /**
2738              * <p><span class="changed_modified_2_2">Receive</span> an Ajax response 
2739              * from the server.
2740              * <p><b>Usage:</b></p>
2741              * <pre><code>
2742              * jsf.ajax.response(request, context);
2743              * </pre></code>
2744              * <p><b>Implementation Requirements:</b></p>
2745              * This function must evaluate the markup returned in the
2746              * <code>request.responseXML</code> object and perform the following action:
2747              * <ul>
2748              * <p>If there is no XML response returned, signal an <code>emptyResponse</code>
2749              * error. If the XML response does not follow the format as outlined
2750              * in Appendix A of the spec prose document <a
2751              *  href="../../javadocs/overview-summary.html#prose_document">linked in the
2752              *  overview summary</a> signal a <code>malformedError</code> error.  Refer to
2753              * section "Signaling Errors" in Chapter 13 of the spec prose document <a
2754              *  href="../../javadocs/overview-summary.html#prose_document">linked in the
2755              *  overview summary</a>.</p>
2756              * <p>If the response was successfully processed, send a <code>success</code>
2757              * event as outlined in Chapter 13 "Sending Events" section of the spec prose
2758              * document <a
2759              * href="../../javadocs/overview-summary.html#prose_document">linked in the
2760              * overview summary</a>.</p>
2761              * <p><i>Update Element Processing</i></p>
2762              * The <code>update</code> element is used to update a single DOM element.  The
2763              * "id" attribute of the <code>update</code> element refers to the DOM element that
2764              * will be updated.  The contents of the <code>CDATA</code> section is the data that 
2765              * will be used when updating the contents of the DOM element as specified by the
2766              * <code><update></code> element identifier.
2767              * <li>If an <code><update></code> element is found in the response
2768              * with the identifier <code>javax.faces.ViewRoot</code>:
2769              * <pre><code><update id="javax.faces.ViewRoot">
2770              *    <![CDATA[...]]>
2771              * </update></code></pre>
2772              * Update the entire DOM replacing the appropriate <code>head</code> and/or
2773              * <code>body</code> sections with the content from the response.</li>
2774 
2775              * <li class="changed_modified_2_2">If an
2776              * <code><update></code> element is found in the 
2777              * response with an identifier containing
2778              * <code>javax.faces.ViewState</code>:
2779 
2780              * <pre><code><update id="<VIEW_ROOT_CONTAINER_CLIENT_ID><SEP>javax.faces.ViewState<SEP><UNIQUE_PER_VIEW_NUMBER>">
2781              *    <![CDATA[...]]>
2782              * </update></code></pre>
2783 
2784              * locate and update the submitting form's
2785              * <code>javax.faces.ViewState</code> value with the
2786              * <code>CDATA</code> contents from the response.
2787              * <SEP> is the currently configured
2788              * <code>UINamingContainer.getSeparatorChar()</code>.
2789              * <VIEW_ROOT_CONTAINER_CLIENT_ID> is the return from
2790              * <code>UIViewRoot.getContainerClientId()</code> on the
2791              * view from whence this state originated.
2792              * <UNIQUE_PER_VIEW_NUMBER> is a number that must be
2793              * unique within this view, but must not be included in the
2794              * view state.  This requirement is simply to satisfy XML
2795              * correctness in parity with what is done in the
2796              * corresponding non-partial JSF view.  Locate and update
2797              * the <code>javax.faces.ViewState</code> value for all
2798              * JSF forms covered in the <code>render</code> target
2799              * list whose ID starts with the same 
2800              * <VIEW_ROOT_CONTAINER_CLIENT_ID> value.</li>
2801 
2802              * <li class="changed_added_2_2">If an
2803              * <code>update</code> element is found in the response with
2804              * an identifier containing
2805              * <code>javax.faces.ClientWindow</code>:
2806 
2807              * <pre><code><update id="<VIEW_ROOT_CONTAINER_CLIENT_ID><SEP>javax.faces.ClientWindow<SEP><UNIQUE_PER_VIEW_NUMBER>">
2808              *    <![CDATA[...]]>
2809              * </update></code></pre>
2810 
2811              * locate and update the submitting form's
2812              * <code>javax.faces.ClientWindow</code> value with the
2813              * <code>CDATA</code> contents from the response.
2814              * <SEP> is the currently configured
2815              * <code>UINamingContainer.getSeparatorChar()</code>.
2816              * <VIEW_ROOT_CONTAINER_CLIENT_ID> is the return from
2817              * <code>UIViewRoot.getContainerClientId()</code> on the
2818              * view from whence this state originated.             
2819              * <UNIQUE_PER_VIEW_NUMBER> is a number that must be
2820              * unique within this view, but must not be included in the
2821              * view state.  This requirement is simply to satisfy XML
2822              * correctness in parity with what is done in the
2823              * corresponding non-partial JSF view.  Locate and update
2824              * the <code>javax.faces.ClientWindow</code> value for all
2825              * JSF forms covered in the <code>render</code> target
2826              * list whose ID starts with the same 
2827              * <VIEW_ROOT_CONTAINER_CLIENT_ID> value.</li>
2828 
2829              * <li class="changed_added_2_3">If an <code>update</code> element is found in the response with the
2830              * identifier <code>javax.faces.Resource</code>:
2831              * <pre><code><update id="javax.faces.Resource">
2832              *    <![CDATA[...]]>
2833              * </update></code></pre>
2834              * append any element found in the <code>CDATA</code> contents which is absent in the document to the
2835              * document's <code>head</code> section.
2836              * </li>
2837 
2838              * <li>If an <code>update</code> element is found in the response with the identifier
2839              * <code>javax.faces.ViewHead</code>:
2840              * <pre><code><update id="javax.faces.ViewHead">
2841              *    <![CDATA[...]]>
2842              * </update></code></pre>
2843              * update the document's <code>head</code> section with the <code>CDATA</code>
2844              * contents from the response.</li>
2845              * <li>If an <code>update</code> element is found in the response with the identifier
2846              * <code>javax.faces.ViewBody</code>:
2847              * <pre><code><update id="javax.faces.ViewBody">
2848              *    <![CDATA[...]]>
2849              * </update></code></pre>
2850              * update the document's <code>body</code> section with the <code>CDATA</code>
2851              * contents from the response.</li>
2852              * <li>For any other <code><update></code> element:
2853              * <pre><code><update id="update id">
2854              *    <![CDATA[...]]>
2855              * </update></code></pre>
2856              * Find the DOM element with the identifier that matches the
2857              * <code><update></code> element identifier, and replace its contents with
2858              * the <code><update></code> element's <code>CDATA</code> contents.</li>
2859              * </li>
2860              * <p><i>Insert Element Processing</i></p>
2861     
2862              * <li>If an <code><insert></code> element is found in
2863              * the response with a nested <code><before></code>
2864              * element:
2865             
2866              * <pre><code><insert>
2867              *     <before id="before id">
2868              *        <![CDATA[...]]>
2869              *     </before>
2870              * </insert></code></pre>
2871              * 
2872              * <ul>
2873              * <li>Extract this <code><before></code> element's <code>CDATA</code> contents
2874              * from the response.</li>
2875              * <li>Find the DOM element whose identifier matches <code>before id</code> and insert
2876              * the <code><before></code> element's <code>CDATA</code> content before
2877              * the DOM element in the document.</li>
2878              * </ul>
2879              * </li>
2880              * 
2881              * <li>If an <code><insert></code> element is found in 
2882              * the response with a nested <code><after></code>
2883              * element:
2884              * 
2885              * <pre><code><insert>
2886              *     <after id="after id">
2887              *        <![CDATA[...]]>
2888              *     </after>
2889              * </insert></code></pre>
2890              * 
2891              * <ul>
2892              * <li>Extract this <code><after></code> element's <code>CDATA</code> contents
2893              * from the response.</li>
2894              * <li>Find the DOM element whose identifier matches <code>after id</code> and insert
2895              * the <code><after></code> element's <code>CDATA</code> content after
2896              * the DOM element in the document.</li>
2897              * </ul>
2898              * </li>
2899              * <p><i>Delete Element Processing</i></p>
2900              * <li>If a <code><delete></code> element is found in the response:
2901              * <pre><code><delete id="delete id"/></code></pre>
2902              * Find the DOM element whose identifier matches <code>delete id</code> and remove it
2903              * from the DOM.</li>
2904              * <p><i>Element Attribute Update Processing</i></p>
2905              * <li>If an <code><attributes></code> element is found in the response:
2906              * <pre><code><attributes id="id of element with attribute">
2907              *    <attribute name="attribute name" value="attribute value">
2908              *    ...
2909              * </attributes></code></pre>
2910              * <ul>
2911              * <li>Find the DOM element that matches the <code><attributes></code> identifier.</li>
2912              * <li>For each nested <code><attribute></code> element in <code><attribute></code>,
2913              * update the DOM element attribute value (whose name matches <code>attribute name</code>),
2914              * with <code>attribute value</code>.</li>
2915              * </ul>
2916              * </li>
2917              * <p><i>JavaScript Processing</i></p>
2918              * <li>If an <code><eval></code> element is found in the response:
2919              * <pre><code><eval>
2920              *    <![CDATA[...JavaScript...]]>
2921              * </eval></code></pre>
2922              * <ul>
2923              * <li>Extract this <code><eval></code> element's <code>CDATA</code> contents
2924              * from the response and execute it as if it were JavaScript code.</li>
2925              * </ul>
2926              * </li>
2927              * <p><i>Redirect Processing</i></p>
2928              * <li>If a <code><redirect></code> element is found in the response:
2929              * <pre><code><redirect url="redirect url"/></code></pre>
2930              * Cause a redirect to the url <code>redirect url</code>.</li>
2931              * <p><i>Error Processing</i></p>
2932              * <li>If an <code><error></code> element is found in the response:
2933              * <pre><code><error>
2934              *    <error-name>..fully qualified class name string...<error-name>
2935              *    <error-message><![CDATA[...]]><error-message>
2936              * </error></code></pre>
2937              * Extract this <code><error></code> element's <code>error-name</code> contents
2938              * and the <code>error-message</code> contents. Signal a <code>serverError</code> passing
2939              * the <code>errorName</code> and <code>errorMessage</code>.  Refer to
2940              * section "Signaling Errors" in Chapter 13 of the spec prose document <a
2941              *  href="../../javadocs/overview-summary.html#prose_document">linked in the
2942              *  overview summary</a>.</li>
2943              * <p><i>Extensions</i></p>
2944              * <li>The <code><extensions></code> element provides a way for framework
2945              * implementations to provide their own information.</li>
2946              * <p><li>The implementation must check if <script> elements in the response can
2947              * be automatically run, as some browsers support this feature and some do not.  
2948              * If they can not be run, then scripts should be extracted from the response and
2949              * run separately.</li></p> 
2950              * </ul>
2951              *
2952              * </p>
2953              *
2954              * @param request The <code>XMLHttpRequest</code> instance that
2955              * contains the status code and response message from the server.
2956              *
2957              * @param context An object containing the request context, including the following properties:
2958              * the source element, per call onerror callback function, and per call onevent callback function.
2959              *
2960              * @throws  Error if request contains no data
2961              *
2962              * @function jsf.ajax.response
2963              */
2964             response: function response(request, context) {
2965                 if (!request) {
2966                     throw new Error("jsf.ajax.response: Request parameter is unset");
2967                 }
2968 
2969                 // ensure context source is the dom element and not the ID
2970                 // per 14.4.1 of the 2.0 specification.  We're doing it here
2971                 // *before* any errors or events are propagated becasue the
2972                 // DOM element may be removed after the update has been processed.
2973                 if (typeof context.sourceid === 'string') {
2974                     context.sourceid = document.getElementById(context.sourceid);
2975                 }
2976 
2977                 var xml = request.responseXML;
2978                 if (xml === null) {
2979                     sendError(request, context, "emptyResponse");
2980                     return;
2981                 }
2982 
2983                 if (getParseErrorText(xml) !== PARSED_OK) {
2984                     sendError(request, context, "malformedXML");
2985                     return;
2986                 }
2987 
2988                 var partialResponse = xml.getElementsByTagName("partial-response")[0];
2989                 var namingContainerId = partialResponse.getAttribute("id");
2990                 var namingContainerPrefix = namingContainerId ? (namingContainerId + jsf.separatorchar) : "";
2991                 var responseType = partialResponse.firstChild;
2992                 
2993                 context.namingContainerId = namingContainerId;
2994                 context.namingContainerPrefix = namingContainerPrefix;
2995 
2996                 for (var i = 0; i < partialResponse.childNodes.length; i++) {
2997                     if (partialResponse.childNodes[i].nodeName === "error") {
2998                         responseType = partialResponse.childNodes[i];
2999                         break;
3000                     }
3001                 }
3002 
3003                 if (responseType.nodeName === "error") { // it's an error
3004                     var errorName = "";
3005                     var errorMessage = "";
3006                     
3007                     var element = responseType.firstChild;
3008                     if (element.nodeName === "error-name") {
3009                         if (null != element.firstChild) {
3010                             errorName = element.firstChild.nodeValue;
3011                         }
3012                     }
3013                     
3014                     element = responseType.firstChild.nextSibling;
3015                     if (element.nodeName === "error-message") {
3016                         if (null != element.firstChild) {
3017                             errorMessage = element.firstChild.nodeValue;
3018                         }
3019                     }
3020                     sendError(request, context, "serverError", null, errorName, errorMessage);
3021                     sendEvent(request, context, "success");
3022                     return;
3023                 }
3024 
3025 
3026                 if (responseType.nodeName === "redirect") {
3027                     window.location = responseType.getAttribute("url");
3028                     return;
3029                 }
3030 
3031 
3032                 if (responseType.nodeName !== "changes") {
3033                     sendError(request, context, "malformedXML", "Top level node must be one of: changes, redirect, error, received: " + responseType.nodeName + " instead.");
3034                     return;
3035                 }
3036 
3037 
3038                 var changes = responseType.childNodes;
3039 
3040                 try {
3041                     for (var i = 0; i < changes.length; i++) {
3042                         switch (changes[i].nodeName) {
3043                             case "update":
3044                                 doUpdate(changes[i], context);
3045                                 break;
3046                             case "delete":
3047                                 doDelete(changes[i]);
3048                                 break;
3049                             case "insert":
3050                                 doInsert(changes[i]);
3051                                 break;
3052                             case "attributes":
3053                                 doAttributes(changes[i]);
3054                                 break;
3055                             case "eval":
3056                                 doEval(changes[i]);
3057                                 break;
3058                             case "extension":
3059                                 // no action
3060                                 break;
3061                             default:
3062                                 sendError(request, context, "malformedXML", "Changes allowed are: update, delete, insert, attributes, eval, extension.  Received " + changes[i].nodeName + " instead.");
3063                                 return;
3064                         }
3065                     }
3066                 } catch (ex) {
3067                     sendError(request, context, "malformedXML", ex.message);
3068                     return;
3069                 }
3070                 sendEvent(request, context, "success");
3071 
3072             }
3073         };
3074     }();
3075 
3076     /**
3077      *
3078      * <p>Return the value of <code>Application.getProjectStage()</code> for
3079      * the currently running application instance.  Calling this method must
3080      * not cause any network transaction to happen to the server.</p>
3081      * <p><b>Usage:</b></p>
3082      * <pre><code>
3083      * var stage = jsf.getProjectStage();
3084      * if (stage === ProjectStage.Development) {
3085      *  ...
3086      * } else if stage === ProjectStage.Production) {
3087      *  ...
3088      * }
3089      * </code></pre>
3090      *
3091      * @returns String <code>String</code> representing the current state of the
3092      * running application in a typical product development lifecycle.  Refer
3093      * to <code>javax.faces.application.Application.getProjectStage</code> and
3094      * <code>javax.faces.application.ProjectStage</code>.
3095      * @function jsf.getProjectStage
3096      */
3097     jsf.getProjectStage = function() {
3098         // First, return cached value if available
3099         if (typeof mojarra !== 'undefined' && typeof mojarra.projectStageCache !== 'undefined') {
3100             return mojarra.projectStageCache;
3101         }
3102         var scripts = document.getElementsByTagName("script"); // nodelist of scripts
3103         var script; // jsf.js script
3104         var s = 0; // incremental variable for for loop
3105         var stage; // temp value for stage
3106         var match; // temp value for match
3107         while (s < scripts.length) {
3108             if (typeof scripts[s].src === 'string' && scripts[s].src.match('\/javax\.faces\.resource\/jsf\.js\?.*ln=javax\.faces')) {
3109                 script = scripts[s].src;
3110                 break;
3111             }
3112             s++;
3113         }
3114         if (typeof script == "string") {
3115             match = script.match("stage=(.*)");
3116             if (match) {
3117                 stage = match[1];
3118             }
3119         }
3120         if (typeof stage === 'undefined' || !stage) {
3121             stage = "Production";
3122         }
3123 
3124         mojarra = mojarra || {};
3125         mojarra.projectStageCache = stage;
3126 
3127         return mojarra.projectStageCache;
3128     };
3129 
3130 
3131     /**
3132      * <p>Collect and encode state for input controls associated
3133      * with the specified <code>form</code> element.  This will include
3134      * all input controls of type <code>hidden</code>.</p>
3135      * <p><b>Usage:</b></p>
3136      * <pre><code>
3137      * var state = jsf.getViewState(form);
3138      * </pre></code>
3139      *
3140      * @param form The <code>form</code> element whose contained
3141      * <code>input</code> controls will be collected and encoded.
3142      * Only successful controls will be collected and encoded in
3143      * accordance with: <a href="http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2">
3144      * Section 17.13.2 of the HTML Specification</a>.
3145      *
3146      * @returns String The encoded state for the specified form's input controls.
3147      * @function jsf.getViewState
3148      */
3149     jsf.getViewState = function(form) {
3150         if (!form) {
3151             throw new Error("jsf.getViewState:  form must be set");
3152         }
3153         var els = form.elements;
3154         var len = els.length;
3155         // create an array which we'll use to hold all the intermediate strings
3156         // this bypasses a problem in IE when repeatedly concatenating very
3157         // large strings - we'll perform the concatenation once at the end
3158         var qString = [];
3159         var addField = function(name, value) {
3160             var tmpStr = "";
3161             if (qString.length > 0) {
3162                 tmpStr = "&";
3163             }
3164             tmpStr += encodeURIComponent(name) + "=" + encodeURIComponent(value);
3165             qString.push(tmpStr);
3166         };
3167         for (var i = 0; i < len; i++) {
3168             var el = els[i];
3169             if (el.name === "") {
3170                 continue;
3171             }
3172             if (!el.disabled) {
3173                 switch (el.type) {
3174                     case 'submit':
3175                     case 'reset':
3176                     case 'image':
3177                     case 'file':
3178                         break;
3179                     case 'select-one':
3180                         if (el.selectedIndex >= 0) {
3181                             addField(el.name, el.options[el.selectedIndex].value);
3182                         }
3183                         break;
3184                     case 'select-multiple':
3185                         for (var j = 0; j < el.options.length; j++) {
3186                             if (el.options[j].selected) {
3187                                 addField(el.name, el.options[j].value);
3188                             }
3189                         }
3190                         break;
3191                     case 'checkbox':
3192                     case 'radio':
3193                         if (el.checked) {
3194                             addField(el.name, el.value || 'on');
3195                         }
3196                         break;
3197                     default:
3198                         // this is for any input incl.  text', 'password', 'hidden', 'textarea'
3199                         var nodeName = el.nodeName.toLowerCase();
3200                         if (nodeName === "input" || nodeName === "select" ||
3201                             nodeName === "button" || nodeName === "object" ||
3202                             nodeName === "textarea") {                                 
3203                             addField(el.name, el.value);
3204                         }
3205                         break;
3206                 }
3207             }
3208         }
3209         // concatenate the array
3210         return qString.join("");
3211     };
3212 
3213     /**
3214      * <p class="changed_added_2_2">Return the windowId of the window
3215      * in which the argument form is rendered.</p>
3216 
3217      * @param {optional String|DomNode} node. Determine the nature of
3218      * the argument.  If not present, search for the windowId within
3219      * <code>document.forms</code>.  If present and the value is a
3220      * string, assume the string is a DOM id and get the element with
3221      * that id and start the search from there.  If present and the
3222      * value is a DOM element, start the search from there.
3223 
3224      * @returns String The windowId of the current window, or null 
3225      *  if the windowId cannot be determined.
3226 
3227      * @throws an error if more than one unique WindowId is found.
3228 
3229      * @function jsf.getClientWindow
3230      */
3231     jsf.getClientWindow = function(node) {
3232         var FORM = "form";
3233         var WIN_ID = "javax.faces.ClientWindow";
3234 
3235         /**
3236          * Find javax.faces.ClientWindow field for a given form.
3237          * @param form
3238          * @ignore
3239          */
3240         var getWindowIdElement = function getWindowIdElement(form) {
3241             var windowIdElement = form[WIN_ID];
3242 
3243             if (windowIdElement) {
3244                 return windowIdElement;
3245             } else {
3246                 var formElements = form.elements;
3247                 for (var i = 0, length = formElements.length; i < length; i++) {
3248                     var formElement = formElements[i];
3249                     if (formElement.name && (formElement.name.indexOf(WIN_ID) >= 0)) {
3250                         return formElement;
3251                     }
3252                 }
3253             }
3254 
3255             return undefined;
3256         };
3257 
3258         var fetchWindowIdFromForms = function (forms) {
3259             var result_idx = {};
3260             var result;
3261             var foundCnt = 0;
3262             for (var cnt = forms.length - 1; cnt >= 0; cnt--) {
3263                 var UDEF = 'undefined';
3264                 var currentForm = forms[cnt];
3265                 var windowIdElement = getWindowIdElement(currentForm);
3266                 var windowId = windowIdElement && windowIdElement.value;
3267                 if (UDEF != typeof windowId) {
3268                     if (foundCnt > 0 && UDEF == typeof result_idx[windowId]) throw Error("Multiple different windowIds found in document");
3269                     result = windowId;
3270                     result_idx[windowId] = true;
3271                     foundCnt++;
3272                 }
3273             }
3274             return result;
3275         }
3276 
3277         /**
3278          * @ignore
3279          */
3280         var getChildForms = function (currentElement) {
3281             //Special condition no element we return document forms
3282             //as search parameter, ideal would be to
3283             //have the viewroot here but the frameworks
3284             //can deal with that themselves by using
3285             //the viewroot as currentElement
3286             if (!currentElement) {
3287                 return document.forms;
3288             }
3289             
3290             var targetArr = [];
3291             if (!currentElement.tagName) return [];
3292             else if (currentElement.tagName.toLowerCase() == FORM) {
3293                 targetArr.push(currentElement);
3294                 return targetArr;
3295             }
3296             
3297             //if query selectors are supported we can take
3298             //a non recursive shortcut
3299             if (currentElement.querySelectorAll) {
3300                 return currentElement.querySelectorAll(FORM);
3301             }
3302             
3303             //old recursive way, due to flakeyness of querySelectorAll
3304             for (var cnt = currentElement.childNodes.length - 1; cnt >= 0; cnt--) {
3305                 var currentChild = currentElement.childNodes[cnt];
3306                 targetArr = targetArr.concat(getChildForms(currentChild, FORM));
3307             }
3308             return targetArr;
3309         }
3310         
3311         /**
3312          * @ignore
3313          */
3314         var fetchWindowIdFromURL = function () {
3315             var href = window.location.href;
3316             var windowId = "windowId";
3317             var regex = new RegExp("[\\?&]" + windowId + "=([^&#\\;]*)");
3318             var results = regex.exec(href);
3319             //initial trial over the url and a regexp
3320             if (results != null) return results[1];
3321             return null;
3322         }
3323         
3324         //byId ($)
3325         var finalNode = (node && (typeof node == "string" || node instanceof String)) ?
3326             document.getElementById(node) : (node || null);
3327         
3328         var forms = getChildForms(finalNode);
3329         var result = fetchWindowIdFromForms(forms);
3330         return (null != result) ? result : fetchWindowIdFromURL();
3331         
3332 
3333     };
3334 
3335     /**
3336      * <p class="changed_added_2_3">
3337      * The Push functionality.
3338      * </p>
3339      * @name jsf.push
3340      * @namespace
3341      * @exec
3342      */
3343     jsf.push = function() {
3344 
3345         // "Constant" fields ----------------------------------------------------------------------------------------------
3346 
3347         var RECONNECT_INTERVAL = 500;
3348         var MAX_RECONNECT_ATTEMPTS = 25;
3349         var REASON_EXPIRED = "Expired";
3350 
3351         // Private static fields ------------------------------------------------------------------------------------------
3352 
3353         var sockets = {};
3354 
3355         // Private constructor functions ----------------------------------------------------------------------------------
3356 
3357         /**
3358          * Creates a reconnecting websocket. When the websocket successfully connects on first attempt, then it will
3359          * automatically reconnect on timeout with cumulative intervals of 500ms with a maximum of 25 attempts (~3 minutes).
3360          * The <code>onclose</code> function will be called with the error code of the last attempt.
3361          * @constructor
3362          * @param {string} url The URL of the websocket.
3363          * @param {string} channel The channel name of the websocket.
3364          * @param {function} onopen The function to be invoked when the websocket is opened.
3365          * @param {function} onmessage The function to be invoked when a message is received.
3366          * @param {function} onclose The function to be invoked when the websocket is closed.
3367          * @param {Object} behaviors Client behavior functions to be invoked when specific message is received.
3368          * @ignore
3369          */
3370         function ReconnectingWebsocket(url, channel, onopen, onmessage, onclose, behaviors) {
3371 
3372             // Private fields -----------------------------------------------------------------------------------------
3373 
3374             var socket;
3375             var reconnectAttempts;
3376             var self = this;
3377 
3378             // Public functions ---------------------------------------------------------------------------------------
3379 
3380             /**
3381              * Opens the reconnecting websocket.
3382              */
3383             self.open = function() {
3384                 if (socket && socket.readyState == 1) {
3385                     return;
3386                 }
3387 
3388                 socket = new WebSocket(url);
3389 
3390                 socket.onopen = function(event) {
3391                     if (reconnectAttempts == null) {
3392                         onopen(channel);
3393                     }
3394 
3395                     reconnectAttempts = 0;
3396                 }
3397 
3398                 socket.onmessage = function(event) {
3399                     var message = JSON.parse(event.data).data;
3400                     onmessage(message, channel, event);
3401                     var functions = behaviors[message];
3402 
3403                     if (functions && functions.length) {
3404                         for (var i = 0; i < functions.length; i++) {
3405                             functions[i]();
3406                         }
3407                     }
3408                 }
3409 
3410                 socket.onclose = function(event) {
3411                     if (!socket
3412                             || (event.code == 1000 && event.reason == REASON_EXPIRED)
3413                             || (event.code == 1008)
3414                             || (reconnectAttempts == null)
3415                             || (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS))
3416                     {
3417                         onclose(event.code, channel, event);
3418                     }
3419                     else {
3420                         setTimeout(self.open, RECONNECT_INTERVAL * reconnectAttempts++);
3421                     }
3422                 }
3423             }
3424 
3425             /**
3426              * Closes the reconnecting websocket.
3427              */
3428             self.close = function() {
3429                 if (socket) {
3430                     var s = socket;
3431                     socket = null;
3432                     reconnectAttempts == null;
3433                     s.close();
3434                 }
3435             }
3436 
3437         }
3438 
3439 
3440         // Private static functions ---------------------------------------------------------------------------------------
3441 
3442         /**
3443          * If given function is actually not a function, then try to interpret it as name of a global function.
3444          * If it still doesn't resolve to anything, then return a NOOP function.
3445          * @param {Object} fn Can be function, or string representing function name, or undefined.
3446          * @return {function} The intented function, or a NOOP function when undefined.
3447          * @ignore
3448          */
3449         function resolveFunction(fn) {
3450             return (typeof fn !== "function") && (fn = window[fn] || function(){}), fn;
3451         }
3452 
3453         /**
3454          * Get socket associated with given client identifier.
3455          * @param {string} clientId The client identifier of the websocket.
3456          * @return {Socket} Socket associated with given client identifier.
3457          * @throws {Error} When client identifier is unknown. You may need to initialize it first via <code>init()</code> function.
3458          * @ignore
3459          */
3460         function getSocket(clientId) {
3461             var socket = sockets[clientId];
3462 
3463             if (socket) {
3464                 return socket;
3465             }
3466             else {
3467                 throw new Error("Unknown clientId: " + clientId);
3468             }
3469         }
3470 
3471 
3472         // Public static functions ----------------------------------------------------------------------------------------
3473 
3474         return {
3475 
3476             /**
3477              * Initialize a websocket on the given client identifier. When connected, it will stay open and reconnect as
3478              * long as URL is valid and <code>jsf.push.close()</code> hasn't explicitly been called on the same client
3479              * identifier.
3480              * @param {string} clientId The client identifier of the websocket.
3481              * @param {string} url The URL of the websocket. All open websockets on the same URL will receive the
3482              * same push notification from the server.
3483              * @param {string} channel The channel name of the websocket.
3484              * @param {function} onopen The JavaScript event handler function that is invoked when the websocket is opened.
3485              * The function will be invoked with one argument: the client identifier.
3486              * @param {function} onmessage The JavaScript event handler function that is invoked when a message is received from
3487              * the server. The function will be invoked with three arguments: the push message, the client identifier and
3488              * the raw <code>MessageEvent</code> itself.
3489              * @param {function} onclose The JavaScript event handler function that is invoked when the websocket is closed.
3490              * The function will be invoked with three arguments: the close reason code, the client identifier and the raw
3491              * <code>CloseEvent</code> itself. Note that this will also be invoked on errors and that you can inspect the
3492              * close reason code if an error occurred and which one (i.e. when the code is not 1000). See also
3493              * <a href="http://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455 section 7.4.1</a> and
3494              * <a href="http://docs.oracle.com/javaee/7/api/javax/websocket/CloseReason.CloseCodes.html">CloseCodes</a> API
3495              * for an elaborate list.
3496              * @param {Object} behaviors Client behavior functions to be invoked when specific message is received.
3497              * @param {boolean} autoconnect Whether or not to automatically connect the socket. Defaults to <code>false</code>.
3498              * @member jsf.push
3499              * @function jsf.push.init
3500              */
3501             init: function(clientId, url, channel, onopen, onmessage, onclose, behaviors, autoconnect) {
3502                 onclose = resolveFunction(onclose);
3503     
3504                 if (!window.WebSocket) { // IE6-9.
3505                     onclose(-1, clientId);
3506                     return;
3507                 }
3508     
3509                 if (!sockets[clientId]) {
3510                     sockets[clientId] = new ReconnectingWebsocket(url, channel, resolveFunction(onopen), resolveFunction(onmessage), onclose, behaviors);
3511                 }
3512     
3513                 if (autoconnect) {
3514                 	getSocket(clientId).open();
3515                 }
3516             },
3517 
3518             /**
3519              * Open the websocket on the given client identifier.
3520              * @param {string} clientId The client identifier of the websocket.
3521              * @throws {Error} When client identifier is unknown. You may need to initialize it first via <code>init()</code> function.
3522              * @member jsf.push
3523              * @function jsf.push.open
3524              */
3525             open: function(clientId) {
3526                 getSocket(clientId).open();
3527             },
3528 
3529             /**
3530              * Close the websocket on the given client identifier.
3531              * @param {string} clientId The client identifier of the websocket.
3532              * @throws {Error} When client identifier is unknown. You may need to initialize it first via <code>init()</code> function.
3533              * @member jsf.push
3534              * @function jsf.push.close
3535              */
3536             close: function(clientId) {
3537                 getSocket(clientId).close();
3538             }
3539         }
3540     }();
3541 
3542 
3543     /**
3544      * The namespace for JavaServer Faces JavaScript utilities.
3545      * @name jsf.util
3546      * @namespace
3547      */
3548     jsf.util = {};
3549 
3550     /**
3551      * <p>A varargs function that invokes an arbitrary number of scripts.
3552      * If any script in the chain returns false, the chain is short-circuited
3553      * and subsequent scripts are not invoked.  Any number of scripts may
3554      * specified after the <code>event</code> argument.</p>
3555      *
3556      * @param source The DOM element that triggered this Ajax request, or an
3557      * id string of the element to use as the triggering element.
3558      * @param event The DOM event that triggered this Ajax request.  The
3559      * <code>event</code> argument is optional.
3560      *
3561      * @returns boolean <code>false</code> if any scripts in the chain return <code>false</code>,
3562      *  otherwise returns <code>true</code>
3563      * 
3564      * @function jsf.util.chain
3565      */
3566     jsf.util.chain = function(source, event) {
3567 
3568         if (arguments.length < 3) {
3569             return true;
3570         }
3571 
3572         // RELEASE_PENDING rogerk - shouldn't this be getElementById instead of null
3573         var thisArg = (typeof source === 'object') ? source : null;
3574 
3575         // Call back any scripts that were passed in
3576         for (var i = 2; i < arguments.length; i++) {
3577 
3578             var f = new Function("event", arguments[i]);
3579             var returnValue = f.call(thisArg, event);
3580 
3581             if (returnValue === false) {
3582                 return false;
3583             }
3584         }
3585         return true;
3586         
3587     };
3588 
3589     /**
3590      * <p class="changed_added_2_2">The result of calling
3591      * <code>UINamingContainer.getNamingContainerSeparatorChar().</code></p>
3592      */
3593     jsf.separatorchar = '#{facesContext.namingContainerSeparatorChar}';
3594 
3595     /**
3596      * <p>An integer specifying the specification version that this file implements.
3597      * Its format is: rightmost two digits, bug release number, next two digits,
3598      * minor release number, leftmost digits, major release number.
3599      * This number may only be incremented by a new release of the specification.</p>
3600      */
3601     jsf.specversion = 23000;
3602 
3603     /**
3604      * <p>An integer specifying the implementation version that this file implements.
3605      * It's a monotonically increasing number, reset with every increment of
3606      * <code>jsf.specversion</code>
3607      * This number is implementation dependent.</p>
3608      */
3609     jsf.implversion = 3;
3610 
3611 
3612 } //end if version detection block
3613