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