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