You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by we...@apache.org on 2010/05/14 12:54:34 UTC

svn commit: r944200 [1/3] - in /myfaces/core/trunk/api/src: assembler/ main/javascript/META-INF/resources/myfaces/_impl/_util/ main/javascript/META-INF/resources/myfaces/_impl/core/ main/javascript/META-INF/resources/myfaces/_impl/xhrCore/ main/javascr...

Author: werpu
Date: Fri May 14 10:54:32 2010
New Revision: 944200

URL: http://svn.apache.org/viewvc?rev=944200&view=rev
Log:
https://issues.apache.org/jira/browse/MYFACES-2715
https://issues.apache.org/jira/browse/MYFACES-2716

Added:
    myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Dom.js
    myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Lang.js
    myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_UnitTest.js
    myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/_Runtime.js
Modified:
    myfaces/core/trunk/api/src/assembler/jsfscripts-compiler.xml
    myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_HtmlStripper.js
    myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_ListenerQueue.js
    myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/jsf_impl.js
    myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/xhrCore/_AjaxRequest.js
    myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/xhrCore/_AjaxRequestQueue.js
    myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/xhrCore/_AjaxResponse.js
    myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/xhrCore/_AjaxUtils.js
    myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/xhrCore/_Exception.js
    myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/xhrCore/_xhrCoreAdapter.js
    myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/api/jsf.js
    myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/api/readme.txt

Modified: myfaces/core/trunk/api/src/assembler/jsfscripts-compiler.xml
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/assembler/jsfscripts-compiler.xml?rev=944200&r1=944199&r2=944200&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/assembler/jsfscripts-compiler.xml (original)
+++ myfaces/core/trunk/api/src/assembler/jsfscripts-compiler.xml Fri May 14 10:54:32 2010
@@ -1,12 +1,34 @@
 <?xml version="1.0"?>
 <assembler>
     <scripts>
+        <!--
+            Assembly for our javascripts
+            if you want to include them manually use:
+
+            
+            <script type="text/javascript" src="./myfaces/_impl/core/_Runtime.js"></script>
+            <script type = "text/javascript" src = "myfaces/_impl/_util/_Lang.js"></script>
+            <script type = "text/javascript" src = "./myfaces/_impl/_util/_ListenerQueue.js"></script>
+            <script type = "text/javascript" src = "./myfaces/_impl/_util/_Dom.js"></script>
+            <script type = "text/javascript" src = "./myfaces/_impl/_util/_HtmlStripper.js"></script>
+
+            <script type = "text/javascript" src = "./myfaces/_impl/xhrCore/_Exception.js"></script>
+            <script type = "text/javascript" src = "./myfaces/_impl/xhrCore/_AjaxUtils.js"></script>
+            <script type = "text/javascript" src = "./myfaces/_impl/xhrCore/_AjaxRequestQueue.js"></script>
+            <script type = "text/javascript" src = "./myfaces/_impl/xhrCore/_AjaxRequest.js"></script>
+            <script type = "text/javascript" src = "./myfaces/_impl/xhrCore/_AjaxResponse.js"></script>
+            <script type = "text/javascript" src = "./myfaces/_impl/xhrCore/_xhrCoreAdapter.js"></script>
+            <script type = "text/javascript" src = "./myfaces/_impl/core/jsf_impl.js"></script>
+            <script type = "text/javascript" src = "./myfaces/api/jsf.js"></script>
+        -->
+
         <script>
             <fileName>jsf.js</fileName>
             <includes>
-                <include>**/_impl/_util/_LangUtils.js</include>
+                <include>**/_impl/core/_Runtime.js</include>
+                <include>**/_impl/_util/_Lang.js</include>
                 <include>**/_impl/_util/_ListenerQueue.js</include>
-                <include>**/_impl/_util/_Utils.js</include>
+                <include>**/_impl/_util/_Dom.js</include>
                 <include>**/_impl/_util/_HtmlStripper.js</include>
                 <include>**/_impl/xhrCore/_Exception.js</include>
                 <include>**/_impl/xhrCore/_AjaxUtils.js</include>

Added: myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Dom.js
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Dom.js?rev=944200&view=auto
==============================================================================
--- myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Dom.js (added)
+++ myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Dom.js Fri May 14 10:54:32 2010
@@ -0,0 +1,804 @@
+myfaces._impl.core._Runtime.singletonExtendClass("myfaces._impl._util._Dom", Object, {
+    _ieQuircksEvents : {
+        "onabort": true,
+        "onload":true,
+        "onunload":true,
+        "onchange": true,
+        "onsubmit": true,
+        "onreset": true,
+        "onselect": true,
+        "onblur": true,
+        "onfocus": true,
+        "onkeydown": true,
+        "onkeypress": true,
+        "onkeyup": true,
+        "onclick": true,
+        "ondblclick": true,
+        "onmousedown": true,
+        "onmousemove": true,
+        "onmouseout": true,
+        "onmouseover": true,
+        "onmouseup": true
+    },
+
+    /**
+     * Run through the given Html item and execute the inline scripts
+     * (IE doesn't do this by itself)
+     * @param {|Node|} item
+     */
+    runScripts: function(item) {
+        var childIteration = myfaces._impl._util._Lang.hitch(this, function(item) {
+            var child = item.firstChild;
+            while (child) {
+                this.runScripts(child);
+                child = child.nextSibling;
+            }
+        });
+
+        if (item.nodeType == 1) { // only if it's an element node or document fragment
+            if ('undefined' != typeof item.tagName && item.tagName.toLowerCase() == 'script') {
+
+                if (typeof item.getAttribute('src') != 'undefined'
+                        && item.getAttribute('src') != null
+                        && item.getAttribute('src').length > 0) {
+                    // external script auto eval
+                    myfaces._impl.core._Runtime.loadScript(item.getAttribute('src'), item.getAttribute('type'), false, "ISO-8859-1");
+                } else {
+                    // embedded script auto eval
+                    var test = item.text;
+                    var go = true;
+                    while (go) {
+                        go = false;
+                        if (test.substring(0, 1) == " ") {
+                            test = test.substring(1);
+                            go = true;
+                        }
+                        if (test.substring(0, 4) == "<!--") {
+                            test = test.substring(4);
+                            go = true;
+                        }
+                        if (test.substring(0, 11) == "//<![CDATA[") {
+                            test = test.substring(11);
+                            go = true;
+                        }
+                    }
+                    // we have to run the script under a global context
+                    myfaces._impl.core._Runtime.globalEval(test); // run the script
+                }
+            } else {
+                childIteration(item);
+            }
+        } else {
+            childIteration(item);
+        }
+    },
+
+    /**
+     * Simple delete on an existing item
+     */
+    deleteItem: function(request, context, itemIdToReplace) {
+        var item = document.getElementById(itemIdToReplace);
+        if (item == null) {
+            myfaces._impl._util._Lang.throwNewWarning
+                    (request, context, "Utils", "deleteItem", "Unknown Html-Component-ID: " + itemIdToReplace);
+            return;
+        }
+
+        item.parentNode.removeChild(item);
+    },
+
+    /**
+     * outerHTML replacement which works cross browserlike
+     * but still is speed optimized
+     *
+     * @param item the item to be replaced
+     * @param markup the markup for the replacement
+     */
+    outerHTML : function(item, markup) {
+        markup = myfaces._impl._util._Lang.trim(markup);
+        if ('undefined' == typeof item || null == item) {
+            throw Error("myfaces._impl._util._Dom.outerHTML: item must be passed down");
+        }
+        if ('undefined' == typeof markup || null == markup) {
+            throw Error("myfaces._impl._util._Dom.outerHTML: markup must be passed down");
+        }
+
+        if (markup != "") {
+            var evalNode = null;
+
+            //w3c compliant browsers with proper contextual fragments
+            var parentNode;
+            if (typeof window.Range != 'undefined'
+                    && typeof Range.prototype.createContextualFragment == 'function') {
+                var range = document.createRange();
+                range.setStartBefore(item);
+                var fragment = range.createContextualFragment(markup);
+                //special case update body, we have to replace the placeholder
+                //with the first element (the place holder is the the only child)
+                //and then append additional elements as additional childs
+                //the body itself then is the root for the eval part!
+                if (item.id == 'myfaces_bodyplaceholder') {
+                    parentNode = item.parentNode;
+                    parentNode.appendChild(fragment);
+                    evalNode = parentNode;
+                } else {
+                    //normal dom node case we replace only the client id fragment!
+
+                    parentNode = item.parentNode;
+
+                    evalNode = fragment.childNodes[0];
+                    parentNode.replaceChild(fragment, item);
+                }
+            } else {
+
+                //now to the non w3c compliant browsers
+                //http://blogs.perl.org/users/clinton_gormley/2010/02/forcing-ie-to-accept-script-tags-in-innerhtml.html
+                var dummyPlaceHolder = document.createElement("div");
+
+                //fortunately a table element also works which is less critical than form elements regarding
+                //the inner content
+                dummyPlaceHolder.innerHTML = "<table>" + markup + "</table>";
+                evalNode = dummyPlaceHolder.childNodes[0].childNodes[0].childNodes[0];
+                parentNode = item.parentNode;
+                item.parentNode.replaceChild(evalNode, item);
+
+                //if this as well will fail in the future, we can let ie parse a proper xml
+                //extract the script elements and then create the script elements manually
+                //but for now we will not need it, and this solution is faster
+                //the downside of that solution would be that the fragment itself
+                //must resolve to a valid xml
+            }
+
+            // and remove the old item
+            //first we have to save the node newly insert for easier access in our eval part
+            if (myfaces._impl.core._Runtime.isManualScriptEval()) {
+                this.runScripts(evalNode);
+            }
+            return evalNode;
+        }
+        // and remove the old item, in case of an empty newtag and do nothing else
+        item.parentNode.removeChild(item);
+        return null;
+    },
+
+    /**
+     * finds a corresponding html item from a given identifier and
+     * dom fragment
+     * @param fragment the dom fragment to find the item for
+     * @param itemId the identifier of the item
+     */
+    findById : function(fragment, itemId) {
+
+        var filter = function(node) {
+            return 'undefined' != typeof node.id && node.id === itemId;
+        };
+
+        return this.findFirst(fragment, filter);
+    },
+
+    /**
+     * findfirst functionality, finds the first element
+     * for which the filter can trigger
+     *
+     * @param fragment the processed fragment/domNode
+     * @param filter a filter closure which either returns true or false depending on triggering or not
+     */
+    findFirst : function(fragment, filter) {
+        myfaces._impl._util._Lang._assertType(filter, "function");
+
+        if (document.createTreeWalker && NodeFilter) {
+            //we have a tree walker in place this allows for an optimized deep scan
+            var lastElementFound = null;
+            var treeWalkerfilter = function (node) {
+                return ((filter(node)) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP);
+            };
+
+            var treeWalker = document.createTreeWalker(fragment, NodeFilter.SHOW_ELEMENT, treeWalkerfilter, false);
+            if (treeWalker.nextNode()) {
+                return treeWalker.currentNode;
+            }
+            return null;
+        }
+
+        if (filter(fragment)) {
+            return fragment;
+        }
+
+        if (fragment.childNodes == null)
+            return null;
+
+        //sub-fragment usecases
+        var child;
+        var cnt;
+        var childLen = fragment.childNodes.length;
+        for (cnt = 0; cnt < childLen; cnt++) {
+            child = fragment.childNodes[cnt];
+            var item = this.findFirst(child, filter);
+            if (item != null)
+                return item;
+        }
+        return null;
+    },
+
+    /**
+     * determines the number of nodes according to their tagType
+     *
+     * @param {Node} fragment (Node or fragment) the fragment to be investigated
+     * @param {String} tagName the tag name (lowercase)
+     * @param {Boolean} deepScan if set to true a found element does not prevent to scan deeper
+     * (the normal usecase is false, which means if the element is found only its
+     * adjacent elements will be scanned, due to the recursive descension
+     * this should work out with elements with different nesting depths but not being
+     * parent and child to each other
+     *
+     * TODO rename to getElementsByTagName
+     * TODO add iterator handlers here for browsers which allow dom filters and iterators
+     */
+    findByTagName : function(fragment, tagName, deepScan) {
+        var _Lang = myfaces._impl._util._Lang;
+        var filter = function(node) {
+            return _Lang.exists(node, "tagName") && _Lang.equalsIgnoreCase(node.tagName, tagName);
+        };
+
+        if ('undefined' == typeof deepScan) {
+            deepScan = false;
+        }
+
+        return this.findAll(fragment, filter, deepScan);
+
+    },
+
+    findByName : function(fragment, name, deepScan) {
+        var _Lang = myfaces._impl._util._Lang;
+        var filter = function(node) {
+            return  _Lang.exists(node, "name") && _Lang.equalsIgnoreCase(node.name, name);
+        };
+        if ('undefined' == typeof deepScan) {
+            deepScan = false;
+        }
+
+        return this.findAll(fragment, filter, deepScan);
+    },
+
+    /**
+     * finds the elements by an attached style class
+     *
+     * @param fragment the source fragment which is the root of our search (included in the search)
+     * @param styleClass the styleclass to search for
+     * @param deepScan if set to true a deep scan can be performed
+     */
+    findByStyleClass : function(fragment, styleClass, deepScan) {
+        var _Lang = myfaces._impl._util._Lang;
+        var filter = _Lang.hitch(this, function(node) {
+            var classes = this.getClasses(node);
+            var len = classes.length;
+            if (len == 0) return false;
+            else {
+                for (var cnt = 0; cnt < len; cnt++) {
+                    if (classes[cnt] === styleClass) return true;
+                }
+            }
+            return false;
+        });
+
+        if ('undefined' == typeof deepScan) {
+            deepScan = false;
+        }
+
+        return this.findAll(fragment, filter, deepScan);
+    },
+
+    /**
+     * a filtered findAll for subdom treewalking
+     * (which uses browser optimizations wherever possible)
+     *
+     * @param {|Node|} rootNode the rootNode so start the scan
+     * @param filter filter closure with the syntax {boolean} filter({Node} node)
+     * @param deepScan if set to true or not set at all a deep scan is performed (for form scans it does not make much sense to deeply scan)
+     */
+    findAll : function(rootNode, filter, deepScan) {
+        var retVal = [];
+        var _Lang = myfaces._impl._util._Lang;
+
+        _Lang._assertType(filter, "function");
+
+        /*
+         one of my unit tests causing the treewalker to hang, have to fix that
+         before issuing that code
+         if (document.createTreeWalker && NodeFilter) {
+         //Works on firefox and webkit, opera and ie have to use the slower fallback mechanis
+         //we have a tree walker in place this allows for an optimized deep scan
+         var lastElementFound = null;
+         if (filter(rootNode)) {
+         lastElementFound = rootNode;
+         retVal.push(rootNode);
+         }
+
+         var treeWalkerfilter = function (node) {
+         _Lang.logInfo(node.className, "-", deepScan);
+         if (!deepScan && lastElementFound != null && node.parentNode == lastElementFound) {
+         return NodeFilter.FILTER_REJECT;
+         }
+
+         var retVal = (filter(node)) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
+         if (retVal == NodeFilter.FILTER_ACCEPT) {
+         lastElementFound = node;
+         }
+         return retVal;
+         };
+
+         var treeWalker = document.createTreeWalker(rootNode, NodeFilter.SHOW_ELEMENT, treeWalkerfilter, false);
+         int cnt = 0;
+         while (treeWalker.nextNode()) {
+
+         retVal.push(treeWalker.currentNode);
+
+         }
+         return retVal;
+         } */
+
+        //fix the value to prevent undefined errors
+        if ('undefined' == typeof deepScan) {
+            deepScan = true;
+        }
+
+        if (filter(rootNode)) {
+            retVal.push(rootNode);
+            if (!deepScan) return retVal;
+        }
+
+        //
+        if (!_Lang.exists(rootNode, "childNodes"))
+            return retVal;
+
+        //subfragment usecases
+
+        var retValLen = retVal.length;
+        var childLen = rootNode.childNodes.length;
+        for (var cnt = 0; (deepScan || retValLen == 0) && cnt < childLen; cnt++) {
+            var childNode = rootNode.childNodes[cnt];
+            var subRetVals = this.findAll(childNode, filter, deepScan);
+            retVal = retVal.concat(subRetVals);
+        }
+        return retVal;
+    },
+
+    /**
+     *
+     * @param {Node} form
+     * @param {String} nameOrIdenitifier
+     *
+     * checks for a a element with the name or identifier of nameOrIdentifier
+     * @returns the found node or null otherwise
+     */
+    findFormElement : function(form, nameOrIdenitifier) {
+        var eLen = form.elements.length;
+        //TODO add iterator handlers here for browsers which allow dom filters and iterators
+
+        for (var e = 0; e < eLen; e++) {
+            var elem = form.elements[e];
+            if ('undefined' != typeof elem.name && elem.name === nameOrIdenitifier) return elem;
+            if ('undefined' != typeof elem.id && elem.id === nameOrIdenitifier) return elem;
+        } // end of for (formElements)
+        return null;
+    },
+
+    /**
+     * bugfixing for ie6 which does not cope properly with setAttribute
+     */
+    setAttribute : function(domNode, attribute, value) {
+
+        //quirks mode and ie7 mode has the attributes problems ie8 standards mode behaves like
+        //a good citizen
+        if (!myfaces._impl.core._Runtime.browser.isIE || myfaces._impl.core._Runtime.browser.isIE > 7) {
+            domNode.setAttribute(attribute, value);
+            return;
+        }
+        var _Lang = myfaces._impl._util._Lang;
+        /*
+         Now to the broken browsers IE6+.... ie7 and ie8 quirks mode
+
+         we deal mainly with three problems here
+         class and for are not handled correctly
+         styles are arrays and cannot be set directly
+         and javascript events cannot be set via setAttribute as well!
+
+         or in original words of quirksmode.org ... this is a mess!
+
+         Btw. thank you Microsoft for providing all necessary tools for free
+         for being able to debug this entire mess in the ie rendering engine out
+         (which is the Microsoft ie vms, developers toolbar, Visual Web Developer 2008 express
+         and the ie8 8 developers toolset!)
+
+         also thank you http://www.quirksmode.org/
+         dojotoolkit.org and   //http://delete.me.uk/2004/09/ieproto.html
+         for additional information on this mess!
+
+         The lowest common denominator tested within this code
+         is IE6, older browsers for now are legacy!
+         */
+        attribute = attribute.toLowerCase();
+
+        if (attribute === "class") {
+            domNode.setAttribute("className", value);
+        } else if (attribute === "for") {
+
+            domNode.setAttribute("htmlFor", value);
+        } else if (attribute === "style") {
+            //We have to split the styles here and assign them one by one
+            var styleEntries = value.split(";");
+            var styleEntriesLen = styleEntries.length;
+            for (var loop = 0; loop < styleEntriesLen; loop++) {
+                var keyVal = styleEntries[loop].split(":");
+                if (keyVal[0] != "" && keyVal[0] == "opacity") {
+                    //special ie quirks handling for opacity
+
+                    var opacityVal = Math.max(100, Math.round(parseFloat(keyVal[1]) * 10));
+                    domNode.style.setAttribute("filter", "alpha(opacity=" + opacityVal + ")");
+                    //if you need more hacks I would recommend
+                    //to use the class attribute and conditional ie includes!
+                } else if (keyVal[0] != "") {
+                    domNode.style.setAttribute(keyVal[0], keyVal[1]);
+                }
+            }
+        } else {
+            //check if the attribute is an event, since this applies only
+            //to quirks mode of ie anyway we can live with the standard html4/xhtml
+            //ie supported events
+            if (this._ieQuircksEvents[attribute]) {
+                if (_Lang.isString(attribute)) {
+                    domNode.setAttribute(attribute, function(event) {
+                        //event implicitly used
+                        return eval(value);
+                    });
+                }
+            } else {
+                //unknown cases we try to catch them via standard setAttributes
+                domNode.setAttribute(attribute, value);
+            }
+        }
+    },
+
+    /**
+     * gets an element from a form with its id -> sometimes two elements have got
+     * the same id but are located in different forms -> MyFaces 1.1.4 two forms ->
+     * 2 inputHidden fields with ID jsf_tree_64 & jsf_state_64 ->
+     * http://www.arcknowledge.com/gmane.comp.jakarta.myfaces.devel/2005-09/msg01269.html
+     * @param {Object} request
+     * @param {Object} context (Map)
+     * @param {String} itemIdOrName - ID of the HTML element located inside the form
+     * @param {Node} form - form element containing the element
+     * @param {boolean} nameSearch if set to true a search for name is also done
+     * @param {boolean} localSearchOnly if set to true a local search is performed only (a full document search is omitted)
+     * @return {Object}   the element if found else null
+     *
+     */
+    getElementFromForm : function(request, context, itemIdOrName, form, nameSearch, localSearchOnly) {
+        var _Lang = myfaces._impl._util._Lang;
+        try {
+
+            if ('undefined' == typeof form || form == null) {
+                return document.getElementById(itemIdOrName);
+            }
+            if ('undefined' == typeof nameSearch || nameSearch == null) {
+                nameSearch = false;
+            }
+            if ('undefined' == typeof localSearchOnly || localSearchOnly == null) {
+                localSearchOnly = false;
+            }
+
+            var fLen = form.elements.length;
+
+            //we first check for a name entry!
+
+
+            //'undefined' != typeof form.elements[itemIdOrName] && null != form.elements[itemIdOrName]
+            if (nameSearch && _Lang.exists(form, "elements." + itemIdOrName)) {
+                return form.elements[itemIdOrName];
+            }
+            //if no name entry is found we check for an Id
+            for (var f = 0; f < fLen; f++) {
+                var element = form.elements[f];
+                if (_Lang.exists(element, "id") && element.id == itemIdOrName) {
+                    return element;
+                }
+            }
+            // element not found inside the form -> try document.getElementById
+            // (kann be null if element doesn't exist)
+            if (!localSearchOnly) {
+                return document.getElementById(itemIdOrName);
+            }
+        } catch (e) {
+            _Lang.throwNewError(request, context, "Utils", "getElementFromForm", e);
+        }
+        return null;
+    },
+
+    /**
+     * fuzzy form detection which tries to determine the form
+     * an item has been detached.
+     *
+     * The problem is some Javascript libraries simply try to
+     * detach controls by reusing the names
+     * of the detached input controls. Most of the times,
+     * the name is unique in a jsf scenario, due to the inherent form mapping.
+     * One way or the other, we will try to fix that by
+     * identifying the proper form over the name
+     *
+     * We do it in several ways, in case of no form null is returned
+     * in case of multiple forms we check all elements with a given name (which we determine
+     * out of a name or id of the detached element) and then iterate over them
+     * to find whether they are in a form or not.
+     *
+     * If only one element within a form and a given identifier found then we can pull out
+     * and move on
+     *
+     * We cannot do much further because in case of two identical named elements
+     * all checks must fail and the first elements form is served.
+     *
+     * Note, this method is only triggered in case of the issuer or an ajax request
+     * is a detached element, otherwise already existing code has served the correct form.
+     *
+     * This method was added because of
+     * https://issues.apache.org/jira/browse/MYFACES-2599
+     * to support the integration of existing ajax libraries which do heavy dom manipulation on the
+     * controls side (Dojos Dijit library for instance).
+     *
+     * @param {Node} element - element as source, can be detached, undefined or null
+     *
+     * @return either null or a form node if it could be determined
+     */
+    fuzzyFormDetection : function(element) {
+        if (0 == document.forms.length) {
+            return null;
+        } else if (1 == document.forms.length) {
+            return document.forms[0];
+        }
+        if ('undefined' == typeof element || null == element) {
+            return null;
+        }
+        var _Lang = myfaces._impl._util._Lang;
+
+        //before going into the more complicated stuff we try the simple approach
+        if (!_Lang.isString(element)) {
+            return this.getParent(element, "form");
+        }
+
+        var submitIdentifier = (_Lang.exists(element, "id")) ? element.id : null;
+        var submitName = (_Lang.exists.exists(element, "name")) ? element.name : null;
+        //a framework in a detachment case also can replace an existing identifier element
+        // with a name element
+        submitName = ('undefined' == typeof submitName || null == submitName) ? submitIdentifier : submitName;
+        var foundForm;
+
+        if ('undefined' != typeof submitIdentifier && null != submitIdentifier && '' != submitIdentifier) {
+            //we have to assert that the element passed down is detached
+            var domElement = myfaces._impl._util._Lang.byId(submitIdentifier);
+            if ('undefined' != typeof domElement && null != domElement) {
+                foundForm = this.getParent(domElement, "form");
+                if (null != foundForm) return foundForm;
+            }
+        }
+
+        /**
+         * name check
+         */
+        var foundElements = new Array();
+
+        /**
+         * the lesser chance is the elements which have the same name
+         * (which is the more likely case in case of a brute dom replacement)
+         */
+        var namedFoundElements = document.getElementsByName(submitName);
+        if (null != namedFoundElements) {
+            for (var cnt = 0; cnt < namedFoundElements.length; cnt++) {
+                // we already have covered the identifier case hence we only can deal with names,
+                foundForm = this.getParent(namedFoundElements[cnt], "form");
+                if (null != foundForm) {
+                    foundElements.push(foundForm);
+                }
+            }
+        }
+
+        if (null == foundElements || 0 == foundElements.length || foundElements.length > 1) {
+            return null;
+        }
+
+        return foundElements[0];
+    },
+
+    /**
+     * [STATIC]
+     * gets a parent of an item with a given tagname
+     * @param {Node} item - child element
+     * @param {String} tagNameToSearchFor - TagName of parent element
+     */
+    getParent : function(item, tagNameToSearchFor) {
+
+        if ('undefined' == typeof item || null == item) {
+            throw Error("myfaces._impl._util._Dom.getParent: item is null or undefined,this not allowed");
+        }
+
+        var _Lang = myfaces._impl._util._Lang;
+        var searchClosure = function(parentItem) {
+            return parentItem != null && _Lang.exists(parentItem, "tagName")
+                    && _Lang.equalsIgnoreCase(parentItem.tagName, tagNameToSearchFor);
+        };
+
+        return this.getFilteredParent(item, searchClosure);
+    }
+    ,
+    /**
+     *
+     * @param item
+     * @param filter
+     */
+    getFilteredParent : function(item, filter) {
+        if ('undefined' == typeof item || null == item) {
+            throw Error("myfaces._impl._util._Dom.getParen: item is null or undefined,this not allowed");
+        }
+
+        //search parent tag parentName
+        var parentItem = ('undefined' != typeof item.parentNode) ? item.parentNode : null;
+
+        while ('undefined' != typeof parentItem && null != parentItem && !filter(parentItem)) {
+            parentItem = parentItem.parentNode;
+        }
+        if ('undefined' != typeof parentItem && null != parentItem) {
+            return parentItem;
+        } else {
+            return null;
+        }
+    },
+
+
+    /**
+     * @Deprecated
+     * @param item
+     * @param filter
+     */
+    getFilteredChild: function(item, filter) {
+        var childItems = item.childNodes;
+        if ('undefined' == typeof childItems || null == childItems) {
+            return null;
+        }
+        for (var c = 0, cLen = childItems.length; c < cLen; c++) {
+            if (filter(childItems[c])) {
+                return childItems[c];
+            }
+        }
+        return null;
+    },
+
+
+    /**
+     * [STATIC]
+     * gets the child of an item with a given tag name
+     * @param {Node} item - parent element
+     * @param {String} childName - TagName of child element
+     * @param {String} itemName - name  attribute the child can have (can be null)
+     * @Deprecated
+     */
+    getChild: function(item, childName, itemName) {
+
+        function filter(node) {
+            return node.tagName != null
+                    && node.tagName.toLowerCase() == childName
+                    && (itemName == null || (itemName != null && itemName == node.getAttribute("name")));
+
+        }
+
+        return this.getFilteredChild(item, filter);
+    },
+
+
+
+    /**
+     * cross ported from dojo
+     * fetches an attribute from a node
+     *
+     * @param {String} node the node
+     * @param {String} attr the attribute
+     * @return the attributes value or null
+     */
+    getAttribute : function(/* HTMLElement */node, /* string */attr) {
+        //	summary
+        //	Returns the value of attribute attr from node.
+        node = this.byId(node);
+        // FIXME: need to add support for attr-specific accessors
+        if ((!node) || (!node.getAttribute)) {
+            // if(attr !== 'nwType'){
+            //	alert("getAttr of '" + attr + "' with bad node");
+            // }
+            return null;
+        }
+        var ta = typeof attr == 'string' ? attr : new String(attr);
+
+        // first try the approach most likely to succeed
+        var v = node.getAttribute(ta.toUpperCase());
+        if ((v) && (typeof v == 'string') && (v != "")) {
+            return v;	//	string
+        }
+
+        // try returning the attributes value, if we couldn't get it as a string
+        if (v && v.value) {
+            return v.value;	//	string
+        }
+
+        // this should work on Opera 7, but it's a little on the crashy side
+        if ((node.getAttributeNode) && (node.getAttributeNode(ta))) {
+            return (node.getAttributeNode(ta)).value;	//	string
+        } else if (node.getAttribute(ta)) {
+            return node.getAttribute(ta);	//	string
+        } else if (node.getAttribute(ta.toLowerCase())) {
+            return node.getAttribute(ta.toLowerCase());	//	string
+        }
+        return null;	//	string
+    },
+
+    /**
+     * checks whether the given node has an attribute attached
+     *
+     * @param {String|Object} node the node to search for
+     * @param {String} attr the attribute to search for
+     * @true if the attribute was found
+     */
+    hasAttribute : function(/* HTMLElement */node, /* string */attr) {
+        //	summary
+        //	Determines whether or not the specified node carries a value for the attribute in question.
+        return this.getAttribute(node, attr) ? true : false;	//	boolean
+    },
+
+    /**
+     * fetches the style class for the node
+     * cross ported from the dojo toolkit
+     * @param {String|Object} node the node to search
+     * @returns the className or ""
+     */
+    getClass : function(node) {
+        node = this.byId(node);
+        if (!node) {
+            return "";
+        }
+        var cs = "";
+        if (node.className) {
+            cs = node.className;
+        } else {
+            if (this.hasAttribute(node, "class")) {
+                cs = this.getAttribute(node, "class");
+            }
+        }
+        return cs.replace(/^\s+|\s+$/g, "");
+    },
+    /**
+     * fdtches the class for the node,
+     * cross ported from the dojo toolkit
+     * @param {String|Object}node the node to search
+     */
+    getClasses : function(node) {
+        var c = this.getClass(node);
+        return (c == "") ? [] : c.split(/\s+/g);
+    },
+
+    /**
+     * concatenation routine which concats all childnodes of a node which
+     * contains a set of CDATA blocks to one big string
+     * @param {Node} node the node to concat its blocks for
+     */
+    concatCDATABlocks
+            :
+            function(/*Node*/ node) {
+                var cDataBlock = [];
+                // response may contain several blocks
+                for (var i = 0; i < node.childNodes.length; i++) {
+                    cDataBlock.push(node.childNodes[i].data);
+                }
+                return cDataBlock.join('');
+            }
+    ,
+
+    byId: function(identifier) {
+        return myfaces._impl._util._Lang.byId(identifier);
+    }
+});
+    

Modified: myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_HtmlStripper.js
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_HtmlStripper.js?rev=944200&r1=944199&r2=944200&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_HtmlStripper.js (original)
+++ myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_HtmlStripper.js Fri May 14 10:54:32 2010
@@ -55,15 +55,10 @@
  * </p>
  */
 
-_reserveMyfacesNamespaces();
+myfaces._impl.core._Runtime.extendClass("myfaces._impl._util._HtmlStripper", Object, {
+    BEGIN_TAG: "html",
+    END_TAG: "lmth",
 
-if (!myfaces._impl._util._LangUtils.exists(myfaces._impl._util, "_HtmlStripper")) {
-
-    myfaces._impl._util._HtmlStripper = function() {
-    };
-
-    myfaces._impl._util._HtmlStripper.prototype.BEGIN_TAG = "html";
-    myfaces._impl._util._HtmlStripper.prototype.END_TAG = "lmth";
 
     /**
      * parses the token array
@@ -75,7 +70,7 @@ if (!myfaces._impl._util._LangUtils.exis
      * note in the subroutines the tokenPos must be at the last char of the operation
      * so that the
      */
-    myfaces._impl._util._HtmlStripper.prototype.parse = function(theString, tagNameStart, tagNameEnd) {
+    parse : function(theString, tagNameStart, tagNameEnd) {
         this.tokens = theString.split("");
         this.tagAttributes = {};
 
@@ -88,10 +83,8 @@ if (!myfaces._impl._util._LangUtils.exis
 
         this._tokenForward = 1;
 
-
-
         if ('undefined' == typeof tagNameStart || null == tagNameStart) {
-            this.tagNameStart = myfaces._impl._util._HtmlStripper.prototype.BEGIN_TAG;
+            this.tagNameStart = this.prototype.BEGIN_TAG;
         } else {
             this.tagNameStart = tagNameStart;
         }
@@ -119,33 +112,33 @@ if (!myfaces._impl._util._LangUtils.exis
         }
         return this.tokens.slice(this._contentStart, this._contentEnd + 1).join("");
 
-    };
+    },
 
     /**
      * fetches the content block which has been parsed
      */
-    myfaces._impl._util._HtmlStripper.prototype.getContentBlock = function() {
+    getContentBlock : function() {
         return this.tokens.slice(this._contentStart, this._contentEnd + 1).join("");
     },
 
     /**
      * fetches the content tag block including the tag code
      */
-    myfaces._impl._util._HtmlStripper.prototype.getContentTagBlock = function() {
+    getContentTagBlock : function() {
         return this.tokens.slice(this._tagStart, this._tagEnd + 1).join("");
     },
 
     /**
      * fetches the block before the tag begin
      */
-    myfaces._impl._util._HtmlStripper.prototype.getPreTagBlock = function() {
+    getPreTagBlock : function() {
         return this.tokens.slice(0, this._tagStart).join("");
     },
 
     /**
      * fetches the block after the tag end
      */
-    myfaces._impl._util._HtmlStripper.prototype.getPostTagBlock = function() {
+    getPostTagBlock : function() {
         return this.tokens.slice(this._tagEnd, this.tokens.length).join("");
     },
 
@@ -155,7 +148,7 @@ if (!myfaces._impl._util._LangUtils.exis
      * a ... normal chars should not occur here, but
      * in the long run for deeper parsing they might happen!
      */
-    myfaces._impl._util._HtmlStripper.prototype.handleInstructionBlock = function() {
+    handleInstructionBlock : function() {
         var len = this.tokens.length;
         for (; this._contentStart < 0 && this._tokenPos < len && this._tokenPos >= 0; this._tokenPos += this._tokenForward) {
             this._skipBlank();
@@ -164,12 +157,12 @@ if (!myfaces._impl._util._LangUtils.exis
                 this.handleDocument();
             }
         }
-    };
+    },
 
     /**
      * it is either a datablock or a content tag from which we can start parsing
      */
-    myfaces._impl._util._HtmlStripper.prototype.handleDocument = function() {
+    handleDocument : function() {
 
         this._tagStart = this.tokenPos;
         this._skipBlank(1);
@@ -185,7 +178,7 @@ if (!myfaces._impl._util._LangUtils.exis
 
             default: this.handleContentTag();
         }
-    };
+    },
 
     /**
      * we can skip definitions or comments!
@@ -197,7 +190,7 @@ if (!myfaces._impl._util._LangUtils.exis
      * and definitions followed by nothing else
      *
      */
-    myfaces._impl._util._HtmlStripper.prototype.handleDataBlock = function() {
+    handleDataBlock : function() {
         this._skipBlank(1);
 
         if (this._tokenPos >= this.tokens.length || this._tokenPos < 0) {
@@ -215,13 +208,13 @@ if (!myfaces._impl._util._LangUtils.exis
                 break;
         }
 
-    };
+    },
 
     /**
      * doc definition ==
      * <! [^>] >
      */
-    myfaces._impl._util._HtmlStripper.prototype.handleDocDefinition = function() {
+    handleDocDefinition : function() {
         this._skipBlank();
 
         if (this._tokenPos >= this.tokens.length || this._tokenPos < 0) {
@@ -240,7 +233,7 @@ if (!myfaces._impl._util._LangUtils.exis
             this._tokenPos += this._tokenForward;
         }
 
-    };
+    },
 
     /**
      * General tag andling section
@@ -252,7 +245,7 @@ if (!myfaces._impl._util._LangUtils.exis
      * on head and body sections and within head (which is skipped)
      * we neither can have code or pre segments!
      */
-    myfaces._impl._util._HtmlStripper.prototype.handleContentTag = function() {
+    handleContentTag : function() {
         //lookahead head, body, html which means a lookahead of 4;
         this._currentSection = null;
         this._skipBlank();
@@ -264,7 +257,7 @@ if (!myfaces._impl._util._LangUtils.exis
             this.handleIdentifiedContent();
             //after the html tag is processed we can break from the first parsing stage
             this.tokenPos = this.tokens.length;
-        } else    if (tagName == "scri" || tagName == "styl") {
+        } else if (tagName == "scri" || tagName == "styl") {
             //script must be handled separately since we can have embedded tags which must be ignored
             this.handleScriptStyle();
         } else {
@@ -272,7 +265,7 @@ if (!myfaces._impl._util._LangUtils.exis
             //and then be done with it!
             this.skipToTagEnd();
         }
-    };
+    },
 
     /**
      * script skipping routine...
@@ -283,7 +276,7 @@ if (!myfaces._impl._util._LangUtils.exis
      *
      *
      */
-    myfaces._impl._util._HtmlStripper.prototype.handleScriptStyle = function() {
+    handleScriptStyle : function() {
         this.skipToTagEnd();
         //singleToken??
         if (this.tokens[this._tokenPos - 1] == "/" && this.tokens[this._tokenPos] == ">") {
@@ -305,7 +298,7 @@ if (!myfaces._impl._util._LangUtils.exis
         } while (this.tokens[this._tokenPos] != "<");
         //now we should be at the end of the script tag at any circumstances!
         this.skipToTagEnd();
-    };
+    },
 
     /**
      * javascript comment handler
@@ -317,7 +310,7 @@ if (!myfaces._impl._util._LangUtils.exis
      * then oh well, syntax error on the javascript side
      * we cannot do anything about it
      */
-    myfaces._impl._util._HtmlStripper.prototype.handleJSComment = function() {
+    handleJSComment : function() {
         var token = this._getCurrentToken();
         var prefetchToken = this.tokens[this._tokenPos + 1];
         var backtrackToken = this.tokens[this._tokenPos - 1];
@@ -348,7 +341,7 @@ if (!myfaces._impl._util._LangUtils.exis
                 }
             }
         }
-    };
+    },
 
     /*----------------- reverse parsing --------*/
 
@@ -356,7 +349,7 @@ if (!myfaces._impl._util._LangUtils.exis
      * the end block tos a bottom up resolution of the parsing process
      * via an inverted tag name to look for
      */
-    myfaces._impl._util._HtmlStripper.prototype.handleEndBlock = function() {
+    handleEndBlock : function() {
         for (; this._tokenPos >= 0; this._tokenPos += this._tokenForward) {
             this._skipBlank(0);
             var token = this._getCurrentToken();
@@ -364,9 +357,9 @@ if (!myfaces._impl._util._LangUtils.exis
                 this.handleEndTagPart();
             }
         }
-    };
+    },
 
-    myfaces._impl._util._HtmlStripper.prototype.handleEndTagPart = function() {
+    handleEndTagPart : function() {
         this._tagEnd = this._tokenPos;
         this._skipBlank(1);
 
@@ -386,9 +379,9 @@ if (!myfaces._impl._util._LangUtils.exis
             default: this.handleContentEnd();
         }
 
-    };
+    },
 
-    myfaces._impl._util._HtmlStripper.prototype.handleContentEnd = function() {
+    handleContentEnd : function() {
         var tagFound = false;
         var first = true;
         for (; this._tokenPos >= 0; this._skipBlank(1)) {
@@ -408,7 +401,7 @@ if (!myfaces._impl._util._LangUtils.exis
             }
 
         }
-    };
+    },
 
     /*----------------- helpers ----------------*/
     /**
@@ -418,7 +411,7 @@ if (!myfaces._impl._util._LangUtils.exis
      * a map of determined key value pairs which we then can further process
      * otherwise the key value pair determination is ignored!
      */
-    myfaces._impl._util._HtmlStripper.prototype.skipToTagEnd = function(analyzeAttributes) {
+    skipToTagEnd : function(analyzeAttributes) {
 
         var token = this._getCurrentToken();
         //faster shortcut for tags which have to be nont analyzed
@@ -455,13 +448,13 @@ if (!myfaces._impl._util._LangUtils.exis
             this._tokenPos += this._tokenForward;
         }
         return keyValuePairs;
-    };
+    },
 
     /**
      * fetches a word which either can be a string or
      * a sequence of non string characters until either = or > or blank is reached!
      */
-    myfaces._impl._util._HtmlStripper.prototype._fetchWord = function() {
+    _fetchWord : function() {
         this._skipBlank(0);
         var result = [];
 
@@ -471,25 +464,25 @@ if (!myfaces._impl._util._LangUtils.exis
                 this._tokenPos += this._tokenForward;
                 return this.handleString(token)
             }
-            
+
             result.push(token);
             this._tokenPos += this._tokenForward;
             token = this._getCurrentToken();
         }
         return result.join("");
-    };
+    },
 
-    myfaces._impl._util._HtmlStripper.prototype._isBlank = function() {
+    _isBlank : function() {
         var token = this._getCurrentToken();
         return token == " " && token == "\t" && token == "\n";
-    };
+    },
 
     /**
      * we can make speedup shorcut assumptions here
      * becase we only try to either identfy head
      * html or body!
      */
-    myfaces._impl._util._HtmlStripper.prototype.handleIdentifiedContent = function() {
+    handleIdentifiedContent : function() {
 
         this.tagAttributes = this.skipToTagEnd(true);
         //TODO trace down the attributes and store them
@@ -502,16 +495,16 @@ if (!myfaces._impl._util._LangUtils.exis
         } else {
             this._contentStart = this._tokenPos + 1;
         }
-    };
+    },
 
     /**
      * returns true if the current token is a string start!
      */
-    myfaces._impl._util._HtmlStripper.prototype._isStringStart = function() {
+    _isStringStart : function() {
         var backTrack = (this._tokenPos > 0) ? this.tokens[this._tokenPos - 1] : null;
         var token = this.tokens[this._tokenPos];
         return (token == "'" || token == '"') && backTrack != "\\";
-    };
+    },
 
     /**
      * skips a string section cintentwise no matter how many other strings
@@ -520,7 +513,7 @@ if (!myfaces._impl._util._LangUtils.exis
      * @param  {String} stringToken the string token to skip!
      * @return the string value without the enclosing hypenations to be processed later on
      */
-    myfaces._impl._util._HtmlStripper.prototype.handleString = function(stringToken) {
+    handleString : function(stringToken) {
         var backTrack = null;
         var resultString = [];
         while (this.tokens[this._tokenPos] != stringToken || backTrack == "\\") {
@@ -533,17 +526,17 @@ if (!myfaces._impl._util._LangUtils.exis
         }
         this._getCurrentToken();
         return resultString.join("");
-    };
+    },
 
-    myfaces._impl._util._HtmlStripper.prototype._assertValues = function(assertValues) {
+    _assertValues : function(assertValues) {
 
         for (var loop = 0; loop < assertValues.length; loop++) {
             this._assertValue(assertValues[loop]);
             this._skipBlank(1);
         }
-    };
+    },
 
-    myfaces._impl._util._HtmlStripper.prototype._assertValue = function(expectedToken) {
+    _assertValue : function(expectedToken) {
         var token = this._getCurrentToken();
         this._assertLength();
         if (token != expectedToken) {
@@ -551,20 +544,20 @@ if (!myfaces._impl._util._LangUtils.exis
         }
 
         return token;
-    };
+    },
 
-    myfaces._impl._util._HtmlStripper.prototype._assertLength = function() {
+    _assertLength : function() {
         if (this._tokenPos >= this.tokens.length) {
             throw Error("Invalid html comment opened but not closed");
         }
-    };
+    },
 
     /**
      * nested comments are not allowed hence we
      * skip them!
      * comment == "&lt;!--" [--&gt;] "--&gt;"
      */
-    myfaces._impl._util._HtmlStripper.prototype.handleComment = function(reverse) {
+    handleComment : function(reverse) {
         this._assertValues(["-","-"]);
         if ('undefined' == typeof reverse || null == reverse) {
             reverse = false;
@@ -600,14 +593,14 @@ if (!myfaces._impl._util._LangUtils.exis
                 this._skipBlank(1);
             }
         }
-    };
+    },
 
     /**
      * fetches and stores the current token
      */
-    myfaces._impl._util._HtmlStripper.prototype._getCurrentToken = function() {
+    _getCurrentToken : function() {
         return this.tokens[this._tokenPos];
-    };
+    },
 
     /**
      * skip blank until the next token is found
@@ -615,7 +608,7 @@ if (!myfaces._impl._util._LangUtils.exis
      * 1 means it skips 1 no matter if the current token is a blank or not!
      *
      */
-    myfaces._impl._util._HtmlStripper.prototype._skipBlank = function(skipVal) {
+    _skipBlank : function(skipVal) {
         var len = this.tokens.length;
         if ('undefined' == typeof  skipVal || null == skipVal) {
             skipVal = 0;
@@ -627,9 +620,9 @@ if (!myfaces._impl._util._LangUtils.exis
                 return;
             }
         }
-    };
+    },
 
-    myfaces._impl._util._HtmlStripper.prototype._fetchTagname = function() {
+    _fetchTagname : function() {
         var tagName = [];
 
         //TODO make the tagname prefetch more generic
@@ -645,5 +638,9 @@ if (!myfaces._impl._util._LangUtils.exis
 
         tagName = tagName.join("").toLowerCase();
         return tagName;
-    };
-}
\ No newline at end of file
+    }
+
+});
+
+
+

Added: myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Lang.js
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Lang.js?rev=944200&view=auto
==============================================================================
--- myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Lang.js (added)
+++ myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Lang.js Fri May 14 10:54:32 2010
@@ -0,0 +1,479 @@
+/*
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *  under the License.
+ */
+
+
+/*
+ theoretically we could save some code
+ by
+ defining the parent object as
+ var parent = new Object();
+ parent.prototype = new myfaces._impl.core._Runtime();
+ extendClass(function () {
+ }, parent , {
+ But for now we are not doing it the little bit of saved
+ space is not worth the loss of readability
+ */
+
+myfaces._impl.core._Runtime.singletonExtendClass("myfaces._impl._util._Lang", Object, {
+
+    fetchNamespace : function(namespacing) {
+        return myfaces._impl.core._Runtime.fetchNamespace(namespacing);
+    },
+
+    reserveNamespace : function(namespacing) {
+        return myfaces._impl.core._Runtime.reserveNamespace(namespacing);
+    },
+
+    globalEval : function(code) {
+        return myfaces._impl.core._Runtime.globalEval(code);
+    },
+
+    /**
+     * cross port from the dojo lib
+     * browser save event resolution
+     * @param event the event object
+     * (with a fallback for ie events if none is present) 
+     */
+    getEventTarget: function(event) {
+        if (!event) {
+            //ie6 and 7 fallback
+            event = window.event || {};
+        }
+        var t = (event.srcElement ? event.srcElement : (event.target ? event.target : null));
+        while ((t) && (t.nodeType != 1)) {
+            t = t.parentNode;
+        }
+        return t;
+    },
+
+    /**
+     * check if an element exists in the root
+     */
+    exists : function(root, element) {
+        return myfaces._impl.core._Runtime.exists(root, element);
+    },
+
+    /**
+     @see myfaces._impl.core._Runtime.extendClass
+     */
+    singletonExtendClass : function(newClass, extendsClass, functionMap, inherited) {
+        return myfaces._impl.core._Runtime.singletonExtendClass(newClass, extendsClass, functionMap, inherited);
+    },
+
+
+    /**
+     * equalsIgnoreCase, case insensitive comparison of two strings
+     *
+     * @param source
+     * @param destination
+     * @param strongCompare
+     */
+    equalsIgnoreCase: function(source, destination) {
+        //either both are not set or null
+        if (!source && !destination) {
+            return true;
+        }
+        //source or dest is set while the other is not
+        if (!source || !destination) return false;
+
+        //in any other case we do a strong string comparison
+        return source.toLowerCase() === destination.toLowerCase();
+    },
+
+
+    /**
+     @see myfaces._impl.core._Runtime.extendClass
+     */
+    extendClass : function(newClass, extendsClass, functionMap, inherited) {
+        return myfaces._impl.core._Runtime.extendClass(newClass, extendsClass, functionMap, inherited);
+    },
+
+    //core namespacing and inheritance done, now to the language extensions
+
+    /**
+     * Save document.getElementById (this code was ported over from dojo)
+     * the idea is that either a string or domNode can be passed
+     * @param {Object} reference the reference which has to be byIded
+     */
+    byId : function(/*object*/ reference) {
+        if (this.isString(reference)) {
+            return document.getElementById(reference);
+        }
+        return reference;
+    },
+
+    /**
+     * backported from dojo
+     * Converts an array-like object (i.e. arguments, DOMCollection) to an
+     array. Returns a new Array with the elements of obj.
+     * @param {Object} obj the object to "arrayify". We expect the object to have, at a
+     minimum, a length property which corresponds to integer-indexed
+     properties.
+     * @param {int} offset the location in obj to start iterating from. Defaults to 0.
+     Optional.
+     * @param {Array} startWith An array to pack with the properties of obj. If provided,
+     properties in obj are appended at the end of startWith and
+     startWith is the returned array.
+     */
+    _toArray : function(obj, offset, startWith) {
+        //	summary:
+        //		Converts an array-like object (i.e. arguments, DOMCollection) to an
+        //		array. Returns a new Array with the elements of obj.
+        //	obj:
+        //		the object to "arrayify". We expect the object to have, at a
+        //		minimum, a length property which corresponds to integer-indexed
+        //		properties.
+        //	offset:
+        //		the location in obj to start iterating from. Defaults to 0.
+        //		Optional.
+        //	startWith:
+        //		An array to pack with the properties of obj. If provided,
+        //		properties in obj are appended at the end of startWith and
+        //		startWith is the returned array.
+        var arr = startWith || [];
+        for (var x = offset || 0; x < obj.length; x++) {
+            arr.push(obj[x]);
+        }
+        return arr; // Array
+    },
+
+    /**
+     * Helper function to provide a trim with a given splitter regular expression
+     * @param {|String|} it the string to be trimmed
+     * @param {|RegExp|} splitter the splitter regular expressiion
+     *
+     * FIXME is this still used?
+     */
+    trimStringInternal : function(it, splitter) {
+        return this.strToArray(it, splitter).join(splitter);
+    },
+
+    /**
+     * String to array function performs a string to array transformation
+     * @param {String} it the string which has to be changed into an array
+     * @param {RegExp} splitter our splitter reglar expression
+     * @return an array of the splitted string
+     */
+    strToArray : function(/*string*/ it, /*regexp*/ splitter) {
+        //	summary:
+        //		Return true if it is a String
+
+        if (!this.isString(it)) {
+            throw Error("myfaces._impl._util._Lang.strToArray param not of type string");
+        }
+        var resultArr = it.split(splitter);
+        var len = resultArr.length;
+        for (var cnt = 0; cnt < len; cnt++) {
+            resultArr[cnt] = this.trim(resultArr[cnt]);
+        }
+        return resultArr;
+    },
+
+    /**
+     * hyperfast trim
+     * http://blog.stevenlevithan.com/archives/faster-trim-javascript
+     * crossported from dojo
+     */
+    trim : function(/*string*/ str) {
+
+        str = str.replace(/^\s\s*/, '');
+        var ws = /\s/;
+        var i = str.length;
+        while (ws.test(str.charAt(--i)));
+        return str.slice(0, i + 1);
+    },
+
+    /**
+     * Splits a string and fetches the last element of the String
+     * @param {String} theString the string to be splitted
+     * @param {String} delimiter a delimiting string regexp
+     *
+     */
+    splitAndGetLast : function(theString, delimiter) {
+        var arr = theString.split(delimiter);
+        return arr[arr.length - 1];
+    },
+
+    /**
+     * Backported from dojo
+     * a failsafe string determination method
+     * (since in javascript String != "" typeof alone fails!)
+     * @param it {|Object|} the object to be checked for being a string
+     * @return true in case of being a string false otherwiseÊ
+     */
+    isString: function(/*anything*/ it) {
+        //	summary:
+        //		Return true if it is a String
+        return !!arguments.length && it != null && (typeof it == "string" || it instanceof String); // Boolean
+    },
+    /**
+     * hitch backported from dojo
+     * hitch allows to assign a function to a dedicated scope
+     * this is helpful in situations when function reassignments
+     * can happen
+     * (notably happens often in lazy xhr code)
+     *
+     * @param {Function} scope of the function to be executed in
+     * @param {Function} method to be executed
+     *
+     * @return whatevery the executed method returns
+     */
+    hitch : function(/*Object*/scope, /*Function|String*/method /*,...*/) {
+        //	summary:
+        //		Returns a function that will only ever execute in the a given scope.
+        //		This allows for easy use of object member functions
+        //		in callbacks and other places in which the "this" keyword may
+        //		otherwise not reference the expected scope.
+        //		Any number of default positional arguments may be passed as parameters
+        //		beyond "method".
+        //		Each of these values will be used to "placehold" (similar to curry)
+        //		for the hitched function.
+        //	scope:
+        //		The scope to use when method executes. If method is a string,
+        //		scope is also the object containing method.
+        //	method:
+        //		A function to be hitched to scope, or the name of the method in
+        //		scope to be hitched.
+        //	example:
+        //	|	myfaces._impl._util._Lang.hitch(foo, "bar")();
+        //		runs foo.bar() in the scope of foo
+        //	example:
+        //	|	myfaces._impl._util._Lang.hitch(foo, myFunction);
+        //		returns a function that runs myFunction in the scope of foo
+        if (arguments.length > 2) {
+            return this._hitchArgs._hitchArgs.apply(this._hitchArgs, arguments); // Function
+        }
+        if (!method) {
+            method = scope;
+            scope = null;
+        }
+        if (this.isString(method)) {
+            scope = scope || window || function() {
+            };
+            /*since we do not have dojo global*/
+            if (!scope[method]) {
+                throw(['myfaces._impl._util._Lang: scope["', method, '"] is null (scope="', scope, '")'].join(''));
+            }
+            return function() {
+                return scope[method].apply(scope, arguments || []);
+            }; // Function
+        }
+        return !scope ? method : function() {
+            return method.apply(scope, arguments || []);
+        }; // Function
+    }
+    ,
+
+    _hitchArgs : function(scope, method /*,...*/) {
+        var pre = this._toArray(arguments, 2);
+        var named = this.isString(method);
+        return function() {
+            // array-fy arguments
+            var args = this._toArray(arguments);
+            // locate our method
+            var f = named ? (scope || this.global)[method] : method;
+            // invoke with collected args
+            return f && f.apply(scope || this, pre.concat(args)); // mixed
+        }; // Function
+    }
+    ,
+
+    /**
+     * Helper function to merge two maps
+     * into one
+     * @param {|Object|} destination the destination map
+     * @param {|Object|} source the source map
+     * @param {|boolean|} overwriteDest if set to true the destination is overwritten if the keys exist in both maps
+     **/
+    mixMaps : function(destination, source, overwriteDest) {
+        /**
+         * mixing code depending on the state of dest and the overwrite param
+         */
+        var _Lang = this;
+        var result = {};
+        var keyIdx = {};
+        var key = null;
+        for (key in source) {
+            /**
+             *we always overwrite dest with source
+             *unless overWrite is not set or source does not exist
+             *but also only if dest exists otherwise source still is taken
+             */
+            if (!overwriteDest) {
+                /**
+                 *we use exists instead of booleans because we cannot rely
+                 *on all values being non boolean, we would need an elvis
+                 *operator in javascript to shorten this :-(
+                 */
+                result[key] = _Lang.exists(dest, key) ? destination[key] : source[key];
+            } else {
+                result[key] = _Lang.exists(source, key) ? source[key] : destination[key];
+            }
+            keyIdx[key] = true;
+        }
+        for (key in destination) {
+            /*if result.key does not exist we push in dest.key*/
+            result[key] = _Lang.exists(result, key) ? result[key] : destination[key];
+        }
+        return result;
+    }
+    ,
+
+    /**
+     * checks if an array contains an element
+     * @param {Array} arr   array
+     * @param {String} string_name string to check for
+     */
+    arrayContains : function(arr, string_name) {
+        for (var loop = 0; loop < arr.length; loop++) {
+            if (arr[loop] == string_name) {
+                return true;
+            }
+        }
+        return false;
+    }
+    ,
+
+    /**
+     * Concatenates an array to a string
+     * @param {Array} arr the array to be concatenated
+     * @param {String} delimiter the concatenation delimiter if none is set \n is used
+     *
+     * @return the concatenated array, one special behavior to enable j4fry compatibility has been added
+     * if no delimiter is used the [entryNumber]+entry is generated for a single entry
+     * TODO check if this is still needed it is somewhat outside of the scope of the function
+     * and functionality wise dirty
+     */
+    arrayToString : function(/*String or array*/ arr, /*string*/ delimiter) {
+        if (this.isString(arr)) {
+            return arr;
+        }
+        var finalDelimiter = (null == delimiter) ? "\n" : delimiter;
+
+        var resultArr = [];
+        for (var cnt = 0; cnt < arr.length; cnt ++) {
+            if (this.isString(arr[cnt])) {
+                resultArr.push(((delimiter == null) ? ("[" + cnt + "] ") : "") + arr[cnt]);
+            } else {
+                resultArr.push(((delimiter == null) ? ("[" + cnt + "] ") : "") + arr[cnt].toString());
+            }
+        }
+        return resultArr.join(finalDelimiter);
+    }
+    ,
+
+    /**
+     * general type assertion routine
+     *
+     * @param probe the probe to be checked for the correct type
+     * @param type the type to be checked for
+     */
+    _assertType : function(probe, type) {
+        if (type != typeof probe) {
+            throw Error("probe must be of type " + type);
+        }
+    },
+
+    /**
+     * [STATIC]
+     * static method used by static methods that throw errors
+     */
+    throwNewError : function(request, context, sourceClass, func, exception) {
+        var newException = new myfaces._impl.xhrCore._Exception(request, context, sourceClass, "ERROR");
+        newException.throwError(request, context, func, exception);
+    },
+
+    /**
+     * [STATIC]
+     * static method used by static methods that throw warnings
+     */
+    throwNewWarning: function(request, context, sourceClass, func, message) {
+        var newException = new myfaces._impl.xhrCore._Exception(request, context, sourceClass, "WARNING");
+        newException.throwWarning(request, context, func, message);
+    },
+
+    /**
+     * onload wrapper for chaining the onload cleanly
+     * @param func the function which should be added to the load
+     * chain (note we cannot rely on return values here, hence jsf.util.chain will fail)
+     */
+    addOnLoad: function(func) {
+        var oldonload = window.onload;
+        if (typeof window.onload != "function") {
+            window.onload = func;
+        } else {
+            window.onload = function() {
+                oldonload();
+                func();
+            }
+        }
+    },
+    /**
+     * Simple simple logging only triggering at
+     * firebug compatible logging consoles
+     *
+     * note: ;; means the code will be stripped
+     * from the production code by the build system
+     */
+    _logToContainer: function(styleClass /*+arguments*/, loggingArguments) {
+        var loggingContainer = document.getElementById("myfaces.logging");
+        if (loggingContainer) {
+            var element = document.createElement("div");
+            //element.className = styleClass;
+            element.innerHTML = loggingArguments.join(" ");
+            loggingContainer.appendChild(element);
+        }
+    },
+
+    logLog: function(/*varargs*/) {
+        var argumentStr = Array.prototype.slice.call(arguments, 0).join(" ");
+        if (window.console && window.console.log) {
+            window.console.log(argumentStr);
+        }
+        this._logToContainer("logLog", ["Log:"].concat([argumentStr]));
+    },
+    logDebug: function(/*varargs*/) {
+        var argumentStr = Array.prototype.slice.call(arguments, 0).join(" ");
+
+        if (window.console && window.console.log) {
+            window.console.debug(argumentStr);
+        }
+        this._logToContainer("logDebug", ["Debug:"].concat([argumentStr]));
+    },
+    logError: function(/*varargs*/) {
+        var argumentStr = Array.prototype.slice.call(arguments, 0).join(" ");
+
+        if (window.console && window.console.error) {
+            window.console.error(argumentStr);
+        }
+        this._logToContainer("logError", ["Error:"].concat([argumentStr]));
+
+    },
+    logInfo: function(/*varargs*/) {
+        var argumentStr = Array.prototype.slice.call(arguments, 0).join(" ");
+
+        if (window.console && window.console.info) {
+            window.console.info(argumentStr);
+        }
+        this._logToContainer("logInfo", ["Info:"].concat([argumentStr]));
+    },
+    logWarn: function(/*varargs*/) {
+        var argumentStr = Array.prototype.slice.call(arguments, 0).join(" ");
+        if (window.console && window.console.warn) {
+            window.console.warn(argumentStr);
+        }
+        this._logToContainer("logWarn", ["Warn:"].concat([argumentStr]));
+    }
+});

Modified: myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_ListenerQueue.js
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_ListenerQueue.js?rev=944200&r1=944199&r2=944200&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_ListenerQueue.js (original)
+++ myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_ListenerQueue.js Fri May 14 10:54:32 2010
@@ -3,7 +3,7 @@
  */
 
 
-_reserveMyfacesNamespaces();
+
 
 /**
  * Simple listener queue with closures which shall be
@@ -12,71 +12,93 @@ _reserveMyfacesNamespaces();
  * idea:
  * var queue = new myfaces._impl._util._ListenerQueue();
  */
-if(!myfaces._impl._util._LangUtils.exists(myfaces, "_ListenerQueue")) {
-    myfaces._impl._util._ListenerQueue = function() {
+myfaces._impl.core._Runtime.extendClass("myfaces._impl._util._ListenerQueue", Object, {
+    constructor_: function() {
         this._queue = [];
+    },
 
-    }
+    length: function() {
+      return this._queue.length;  
+    },
 
-    myfaces._impl._util._ListenerQueue.prototype._assertListener = function(/*function*/listener) {
-        if("function" != typeof (listener)) {
+    /**
+     * listener type safety assertion function
+     *
+     * @param listener must be of type function otherwise an error is raised
+     */
+    _assertListener : function(/*function*/listener) {
+        if ("function" != typeof (listener)) {
             throw Error("Error: myfaces._impl._util._ListenerQueue." + arguments.caller.toString() + "Parameter must be of type function");
         }
-    }
+    },
 
-    myfaces._impl._util._ListenerQueue.prototype.add = function(/*function*/listener) {
-        this._assertListener( listener);
+    /**
+     * adds a listener to the queue
+     *
+     * @param listener the listener to be added
+     */
+    add : function(/*function*/listener) {
+        this._assertListener(listener);
         this._queue.push(listener);
-    }
+    },
 
-    myfaces._impl._util._ListenerQueue.prototype.remove = function(/*function*/listener) {
-        this._assertListener( listener);
+    /**
+     * removes a listener form the queue
+     *
+     * @param listener the listener to be removed
+     */
+    remove : function(/*function*/listener) {
+        this._assertListener(listener);
         /*find element in queue*/
         var cnt = 0;
-        while(cnt < this._queue.length && this._queue[cnt] != listener) {
+        var len = this._queue.length;
+        while (cnt < len && this._queue[cnt] != listener) {
             cnt += 1;
         }
         /*found*/
-        if(cnt < this._queue.length) {
+        if (cnt < len) {
             this._queue[cnt] = null;
             /*we remove the element now as fast as possible*/
             this._queue.splice(cnt, 1);
         }
 
-    }
-   /**
+    },
+    
+    /**
      * generic broadcast with a number of arguments being passed down
      * @param scope the execution scope for the event callback
-     * @param argument,...*  the arguments list which has to be passed
+     * @param argument ,...*  the arguments list which has to be passed
      *                  down the queue function
      */
-    myfaces._impl._util._ListenerQueue.prototype.broadcastScopedEvent = function(scope, /*any*/argument) {
-        for(var cnt = 0; cnt < this._queue.length; cnt ++) {
+    broadcastScopedEvent : function(scope, /*any*/argument) {
+        for (var cnt = 0; cnt < this._queue.length; cnt ++) {
             /**
              * we call the original method under its original scope
              * use hitch to keep the original scope in place
              * because there is no way that I can keep it from here
              **/
             var varArgs = [];
-            for(var argsCnt = 1; argsCnt < arguments.length; argsCnt++) {
+            var len = arguments.length;
+            for (var argsCnt = 1; argsCnt < len; argsCnt++) {
                 varArgs.push(arguments[argsCnt]);
             }
             this._queue[cnt].apply(scope, varArgs);
         }
-    }
+    },
 
     /**
      * generic broadcast with a number of arguments being passed down
      */
-    myfaces._impl._util._ListenerQueue.prototype.broadcastEvent = function(/*any*/argument) {
-        for(var cnt = 0; cnt < this._queue.length; cnt ++) {
+    broadcastEvent : function(/*any*/argument) {
+        var len = this._queue.length;
+        for (var cnt = 0; cnt < len; cnt ++) {
             /**
              * we call the original method under its original scope
              * use hitch to keep the original scope in place
              * because there is no way that I can keep it from here
              **/
- 
+
             this._queue[cnt].apply(null, arguments);
         }
     }
-}
\ No newline at end of file
+});
\ No newline at end of file

Added: myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_UnitTest.js
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_UnitTest.js?rev=944200&view=auto
==============================================================================
--- myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_UnitTest.js (added)
+++ myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_UnitTest.js Fri May 14 10:54:32 2010
@@ -0,0 +1,26 @@
+/**
+ * This class is for http based unit tests
+ */
+myfaces._impl.core._Runtime.singletonExtendClass("myfaces._impl._util._UnitTest", Object, {
+    /**
+     *
+     */
+    assertTrue: function(message, assertionOutcome) {
+        var _Lang = myfaces._impl._util._Lang;
+
+        if (!assertionOutcome) {
+            _Lang.logError(message, "assertionOutcome:", assertionOutcome);
+            throw Error(message, assertionOutcome);
+        }
+        _Lang.logInfo(message, "assertionOutcome:", assertionOutcome);
+    },
+    assertFalse: function(message, assertionOutcome) {
+        var _Lang = myfaces._impl._util._Lang;
+
+        if (assertionOutcome) {
+            _Lang.logError(message, "assertionOutcome:", assertionOutcome);
+            throw Error(message, assertionOutcome);
+        }
+        _Lang.logInfo(message, "assertionOutcome:", assertionOutcome);
+    }
+});
\ No newline at end of file