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