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