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