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