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/06/30 22:24:22 UTC

svn commit: r959421 - in /myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl: _util/_Dom.js _util/_HtmlStripper.js _util/_Lang.js core/Impl.js core/_Runtime.js xhrCore/_AjaxResponse.js

Author: werpu
Date: Wed Jun 30 20:24:21 2010
New Revision: 959421

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

Render All now also causes the evaluation of the head scripts, dropping of the ll parser in favor of browser based
parsing with a small html tag stripper as failsafe solution.
(significant reduction in final codesize)

Modified:
    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/_HtmlStripper.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/core/Impl.js
    myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/_Runtime.js
    myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/xhrCore/_AjaxResponse.js

Modified: 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=959421&r1=959420&r2=959421&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Dom.js (original)
+++ myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Dom.js Wed Jun 30 20:24:21 2010
@@ -64,22 +64,22 @@ myfaces._impl.core._Runtime.singletonExt
      * (IE doesn't do this by itself)
      * @param {|Node|} item
      */
-    runScripts: function(item) {
+    runScripts: function(item, xmlData) {
         var execScrpt = myfaces._impl._util._Lang.hitch(this, function(item) {
             if (item.tagName && item.tagName.toLowerCase() == 'script') {
                 var src = item.getAttribute('src');
-                if (    'undefined' !=  typeof src 
-                        && null !=  src
+                if ('undefined' != typeof src
+                        && null != src
                         && src.length > 0
-                ) {
+                        ) {
                     //we have to move this into an inner if because chrome otherwise chokes
                     //due to changing the and order instead of relying on left to right
                     if ((src.indexOf("ln=scripts") == -1 && src.indexOf("ln=javax.faces") == -1) || (src.indexOf("/jsf.js") == -1
-                        && src.indexOf("/jsf-uncompressed.js") == -1))
-                    myfaces._impl.core._Runtime.loadScriptEval(src, item.getAttribute('type'), false, "UTF-8");
+                            && src.indexOf("/jsf-uncompressed.js") == -1))
+                        myfaces._impl.core._Runtime.loadScriptEval(src, item.getAttribute('type'), false, "UTF-8");
                 } else {
                     // embedded script auto eval
-                    var test = item.text;
+                    var test = (!xmlData) ? item.text :myfaces._impl._util._Lang.serializeChilds(item);
                     var go = true;
                     while (go) {
                         go = false;
@@ -236,7 +236,26 @@ myfaces._impl.core._Runtime.singletonExt
             evalNodes = dummyPlaceHolder.childNodes[0].childNodes;
         }
 
-        parentNode = item.parentNode;
+        evalNodes = this.replaceElement(item, evalNodes);
+
+        //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
+        return evalNodes;
+    },
+
+    /**
+     * replaces an element with another element or a set of elements
+     *
+     * @param item the item to be replaced
+     *
+     * @param evalNodes the elements
+     */
+    replaceElement: function (item, evalNodes) {
+        var _Lang = myfaces._impl._util._Lang;
+        var parentNode = item.parentNode;
 
         if ('undefined' != typeof evalNodes.length) {
             var oldNode = item;
@@ -259,12 +278,6 @@ myfaces._impl.core._Runtime.singletonExt
         } else {
             evalNodes = parentNode.replaceChild(evalNodes, 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
         return evalNodes;
     },
 
@@ -499,7 +512,7 @@ myfaces._impl.core._Runtime.singletonExt
             //but only for deep scan and normal parent nodes
             else if (fragment.querySelectorAll && deepScan) {
                 try {
-                    var result = fragment.querySelectorAll("."+styleClass.replace(/\./g, "\\."));
+                    var result = fragment.querySelectorAll("." + styleClass.replace(/\./g, "\\."));
 
                     if (fragment.nodeType == 1 && filter(fragment)) {
                         result = (result == null) ? [] : result;

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=959421&r1=959420&r2=959421&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 Wed Jun 30 20:24:21 2010
@@ -16,38 +16,8 @@
 
 /**
  * <p>
- * A simple html parser class
- * that handles the stripping of the body
- * and head area properly
- * </p>
- * <p>
- * we assume that the ajax response encapsules
- * the html elements
- * so we only have to strip those really needed by the response
- * </p>
- * Due to this fact we can make several shortcuts...
- * First we only have to parse either for html or body for now
- * hence we can skip code and pre parsing to skip embedded tags as well
- *
- * <p>
- * secondly once we have found our section we can parse bottom up
- * which adds an additional speedup to our parsing process!
- * </p>
- * <p>
- * Note we do not solve the head and body stripping via regular expressions
- * because there are usecases where this does not work out
- * for instance comments with embedded head and body sections
- * or javascripts with head and body in strings..
- *
- * Also we do not rely on the response being xhtml due to
- * the fact that we might still have to cover jsp over html 4.0.1
- *
- * We tried to solve that that way in the first place but due to
- * the nature of things a minimal semantic understanding in the parsing
- * process is needed to strip everything out correctly which is not entirely
- * given via normal pattern matching, so we went the hard route
- * of implementing everything with a minimal parser
- * which tries to cover the semantics needed to strip out the correct content!
+ *  Fallback routine if the browser embedded xml parser fails on the document
+ *  This fallback is not failsafe but should give enough cover to handle all cases
  * </p>
  */
 
@@ -56,18 +26,7 @@ myfaces._impl.core._Runtime.extendClass(
     BEGIN_TAG: "html",
     END_TAG: "lmth",
 
-
-    /**
-     * parses the token array
-     * and handles the incoming tokens via an ll
-     * parsing and backtracking of one char
-     * the handling of the parsing is done via
-     * recursive descension
-     *
-     * note in the subroutines the tokenPos must be at the last char of the operation
-     * so that the
-     */
-    parse : function(theString, tagNameStart, tagNameEnd) {
+    parse : function(theString, tagNameStart) {
         this.tokens = theString.split("");
         this.tagAttributes = {};
 
@@ -81,545 +40,74 @@ myfaces._impl.core._Runtime.extendClass(
         this._tokenForward = 1;
 
         this.tagNameStart = (!tagNameStart) ? this.BEGIN_TAG : tagNameStart;
-        this.tagNameEnd = (!tagNameEnd) ? this.tagNameStart.split("").reverse().join("") : tagNameEnd.split("").reverse().join("");
-
-        this.handleInstructionBlock();
-
-        if (this._contentStart >= 0 && this._contentEnd == -1) {
-            this._tokenPos = this.tokens.length - 1;
-            this._tokenForward = -1;
-            //we now can skip the parsing for the rest of the block and have to roll out the parsing
-            //from bottom up, this speeds up the entire process tremendously!
-            this.handleEndBlock();
-        }
-
-        if (this._contentStart >= 0 && this._contentEnd == -1) {
-            this._contentEnd = this.tokens.length - 1;
-        } else if (this._contentStart == -1) {
-            return "";
-        }
-        return this.tokens.slice(this._contentStart, this._contentEnd + 1).join("");
-
-    },
-
-    /**
-     * fetches the content block which has been parsed
-     */
-    getContentBlock : function() {
-        return this.tokens.slice(this._contentStart, this._contentEnd + 1).join("");
-    },
-
-    /**
-     * fetches the content tag block including the tag code
-     */
-    getContentTagBlock : function() {
-        return this.tokens.slice(this._tagStart, this._tagEnd + 1).join("");
-    },
-
-    /**
-     * fetches the block before the tag begin
-     */
-    getPreTagBlock : function() {
-        return this.tokens.slice(0, this._tagStart).join("");
-    },
-
-    /**
-     * fetches the block after the tag end
-     */
-    getPostTagBlock : function() {
-        return this.tokens.slice(this._tagEnd, this.tokens.length).join("");
-    },
-
-    /**
-     * normal characters are skipped
-     * a < clearly is an indicator for
-     * a ... normal chars should not occur here, but
-     * in the long run for deeper parsing they might happen!
-     */
-    handleInstructionBlock : function() {
-        var len = this.tokens.length;
-        for (; this._contentStart < 0 && this._tokenPos < len && this._tokenPos >= 0; this._tokenPos += this._tokenForward) {
-            this._skipBlank();
-            var token = this._getCurrentToken();
-            if (token == "<") {
-                this.handleDocument();
-            }
-        }
-    },
-
-    /**
-     * it is either a datablock or a content tag from which we can start parsing
-     */
-    handleDocument : function() {
-
-        this._tagStart = this.tokenPos;
-        this._skipBlank(1);
-
-        if (this._tokenPos >= this.tokens.length) {
-            throw new Error("Document end reached prematurely");
-        }
-        var token = this._getCurrentToken();
-        switch (token) {
-            case "!":
-                this.handleDataBlock();
-                break;
-
-            default: this.handleContentTag();
-        }
-    },
-
-    /**
-     * we can skip definitions or comments!
-     *
-     * a definition or comment section is like following:
-     * <! ... > with no </ at the end
-     *
-     * with comments followed by --
-     * and definitions followed by nothing else
-     *
-     */
-    handleDataBlock : function() {
-        this._skipBlank(1);
-
-        if (this._tokenPos >= this.tokens.length || this._tokenPos < 0) {
-            return;
-        }
-        var token = this.tokens[this._tokenPos];
-        switch (token) {
-            case "-":
-                this.handleComment();
-                break;
-
-            default:
-                this._getCurrentToken();
-                this.handleDocDefinition();
-                break;
-        }
-
-    },
-
-    /**
-     * doc definition ==
-     * <! [^>] >
-     */
-    handleDocDefinition : function() {
-        this._skipBlank();
-
-        if (this._tokenPos >= this.tokens.length || this._tokenPos < 0) {
-            throw new Error("Document end reached prematurely");
-        }
-        var len = this.tokens.length;
-        while (this._tokenPos < len && this._tokenPos >= 0) {
-            //var token = this._getCurrentToken();
-            //inlining for speed reasons  we also could use getCurrentToken
-            var token = this.tokens[this._tokenPos];
-
-            //inlining end
-            if (token == ">") {
-                return;
-            }
-            this._tokenPos += this._tokenForward;
-        }
-
-    },
-
-    /**
-     * General tag andling section
-     * we define identified and unidentified content
-     * and script which is a subpart of idenitifed
-     *
-     * for now we do not handle the special conditions within pre and code
-     * segments since we have a specialized usage of this stripper
-     * on head and body sections and within head (which is skipped)
-     * we neither can have code or pre segments!
-     */
-    handleContentTag : function() {
-        //lookahead head, body, html which means a lookahead of 4;
-        this._currentSection = null;
-        this._skipBlank();
-        var tagName = this._fetchTagname();
-
-        /*we try to avoid lookaheads here hence the shifting of tokens!*/
-        if (tagName == this.tagNameStart) {
-            /*either embedded into html */
-            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") {
-            //script must be handled separately since we can have embedded tags which must be ignored
-            this.handleScriptStyle();
-        } else {
-            //unidentified content we deal with it by skipping to the tag end
-            //and then be done with it!
-            this.skipToTagEnd();
-        }
-    },
-
-    /**
-     * script skipping routine...
-     * we skip automatically over embedded scripts
-     * and tags within strings and comments
-     * so that we do not trigger against embedded tags in script sections
-     * of the head!
-     *
-     *
-     */
-    handleScriptStyle : function() {
-        this.skipToTagEnd();
-        //singleToken??
-        if (this.tokens[this._tokenPos - 1] == "/" && this.tokens[this._tokenPos] == ">") {
-            return;
-        }
-        //lets skip until we hit < by ignoring embedded strings and comments
-        do {
-            this._skipBlank(1);
-            var token = this._getCurrentToken();
-            switch (token) {
-                case "\'" || "'":
-                    this.handleString(token);
-                    break;
-                case "/" :
-                    this.handleJSComment();
-                    break;
-            }
-
-        } while (this.tokens[this._tokenPos] != "<");
-        //now we should be at the end of the script tag at any circumstances!
-        this.skipToTagEnd();
-    },
 
-    /**
-     * javascript comment handler
-     * we have to check for escape sequences so that we do not trigger
-     * accidentally the comment parsing within embedded regular expressions
-     * which means we have to prefetch and backtrack one token!
-     * \/* should not start a comment neither should \//
-     * if someone places this in the middle of the code
-     * then oh well, syntax error on the javascript side
-     * we cannot do anything about it
-     */
-    handleJSComment : function() {
-        var token = this._getCurrentToken();
-        var prefetchToken = this.tokens[this._tokenPos + 1];
-        var backtrackToken = this.tokens[this._tokenPos - 1];
-        var backtrackToken2 = this.tokens[this._tokenPos - 2];
-
-        //comment condition == either /* or // with no \ in backtrack or \\ in backtrack!
-        var backTrackIsComment = backtrackToken != '\\' || (backtrackToken == '\\' && backtrackToken2 == '\\');
-        if (!backTrackIsComment) {
-            return;
-        }
-
-        var singleLineComment = prefetchToken == '/';
-        var multiLineComment = prefetchToken == "*";
-
-        if (singleLineComment) {
-            while (this._tokenPos < this.tokens.length && this._getCurrentToken() != "\n") {
-                this._tokenPos++;
-            }
-
-        } else if (multiLineComment) {
-            this._skipBlank(1);
-            while (this._tokenPos < this.tokens.length) {
-                this._skipBlank(1);
-                token = this._getCurrentToken();
-                prefetchToken = this.tokens[this._tokenPos + 1];
-                if (token == "*" && prefetchToken == "/") {
-                    return;
-                }
-            }
-        }
-    },
+        //no need for ll parsing a handful of indexofs instead of slower regepx suffices
 
-    /*----------------- reverse parsing --------*/
+        var proposedTagStartPos = theString.indexOf("<"+tagNameStart);
 
-    /**
-     * the end block tos a bottom up resolution of the parsing process
-     * via an inverted tag name to look for
-     */
-    handleEndBlock : function() {
-        for (; this._tokenPos >= 0; this._tokenPos += this._tokenForward) {
-            this._skipBlank(0);
-            var token = this._getCurrentToken();
-            if (token == ">") {
-                this.handleEndTagPart();
+        while(this._contentStart == -1 && proposedTagStartPos != -1) {
+            if(this.checkBackForComment(theString, proposedTagStartPos))  {
+                this._tagStart = proposedTagStartPos;
+                this._contentStart = proposedTagStartPos+theString.substring(proposedTagStartPos).indexOf(">")+1;
             }
-        }
-    },
-
-    handleEndTagPart : function() {
-        this._tagEnd = this._tokenPos;
-        this._skipBlank(1);
-
-        if (this._tokenPos < 0) {
-            throw new Error("Document end reached prematurely");
-        }
-        var token = this._getCurrentToken();
-
-        //we can assume we are outside of the html or body sections
-        //se we only have to check for comments for the reverse parsing!
-        switch (token) {
-            case "-":
-
-                this.handleComment(true);
-                break;
-
-            default: this.handleContentEnd();
-        }
-
-    },
-
-    handleContentEnd : function() {
-        var tagFound = false;
-        var first = true;
-        for (; this._tokenPos >= 0; this._skipBlank(1)) {
-            if (first && !tagFound) {
-                var tagName = this._fetchTagname();
-                if (tagName == this.tagNameEnd) {
-                    tagFound = true;
-                }
-                first = false;
-            } else if (tagFound && this.tokens[this._tokenPos] == "<") {
-                this._contentEnd = this._tokenPos - 1;
-                this._tokenPos = -1;
-                return;
-            } else if (this.tokens[this._tokenPos] == "<") {
-                this._tokenPos += 1;
-                return;
-            }
-
-        }
-    },
-
-    /*----------------- helpers ----------------*/
-    /**
-     * skips the current tag definition until the end is reached
-     *
-     * @param analyzeAttributes if set to true we will end up with
-     * a map of determined key value pairs which we then can further process
-     * otherwise the key value pair determination is ignored!
-     */
-    skipToTagEnd : function(analyzeAttributes) {
-
-        var token = this._getCurrentToken();
-        //faster shortcut for tags which have to be nont analyzed
-        if (!analyzeAttributes) {
-            while (token != ">") {
-                if (this._isStringStart()) {
-                    this._tokenPos += this._tokenForward;
-                    return this.handleString(token)
-                }
-                this._skipBlank(1);
-                token = this._getCurrentToken();
-            }
-
-            return null;
+            proposedTagStartPos = theString.substring(proposedTagStartPos+tagNameStart.length+2).indexOf("<"+tagNameStart);
         }
 
-        //analyze part
-
-        var keyValuePairs = {};
-        var currentWord = [];
-        while (this.tokens[this._tokenPos] != ">") {
-            currentWord = this._fetchWord();
-            token = this._getCurrentToken();
-
-            if (token == "=") {
-                this._tokenPos += this._tokenForward;
-                keyValuePairs[currentWord] = this._fetchWord();
-            } else {
-                keyValuePairs[currentWord] = null;
+        var proposedEndTagPos = theString.lastIndexOf("</"+tagNameStart);
+        while(this._contentEnd == -1 && proposedEndTagPos > 0) {
+            if(this.checkForwardForComment(theString, proposedEndTagPos))  {
+                this._tagEnd = proposedEndTagPos;
+                this._contentEnd = proposedEndTagPos;
             }
-            this._tokenPos += this._tokenForward;
+            proposedTagStartPos = theString.substring(proposedTagStartPos-tagNameStart.length-2).lastIndexOf("</"+tagNameStart);
         }
-        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!
-     */
-    _fetchWord : function() {
-        this._skipBlank(0);
-        var result = [];
-
-        var token = this._getCurrentToken();
-        while ((!this._isBlank()) && token != "=" && token != ">") {
-            if (this._isStringStart()) {
-                this._tokenPos += this._tokenForward;
-                return this.handleString(token)
-            }
-
-            result.push(token);
-            this._tokenPos += this._tokenForward;
-            token = this._getCurrentToken();
+        if(this._contentStart != -1 && this._contentEnd != -1) {
+            return theString.substring(this._contentStart, this._contentEnd);
         }
-        return result.join("");
-    },
-
-    _isBlank : function() {
-        var token = this._getCurrentToken();
-        return token == " " && token == "\t" && token == "\n";
+        return null;
     },
+    
+    checkForwardForComment: function(theStr, tagPos) {
+        var toCheck = theStr.substring(tagPos);
+        var firstBeginComment = toCheck.indexOf("<!--");
+        var firstEndComment = toCheck.indexOf("-->");
 
-    /**
-     * we can make speedup shorcut assumptions here
-     * becase we only try to either identfy head
-     * html or body!
-     */
-    handleIdentifiedContent : function() {
-
-        this.tagAttributes = this.skipToTagEnd(true);
-        //TODO trace down the attributes and store them
-        //they must be key value pairs
-
-        if (this.tokens[this._tokenPos - 1] == "/" && this.tokens[this._tokenPos] == ">") {
-            this._contentStart = -1;
-            this._contentEnd = -1;
-            /*we move to the end*/
-        } else {
-            this._contentStart = this._tokenPos + 1;
+        var firstBeginCDATA = toCheck.indexOf("<[CDATA[");
+        var firstEndCDATA = toCheck.indexOf("]]>");
+        
+        if(this.isValidPositionCombination(firstBeginComment, firstEndComment, firstBeginCDATA, firstEndCDATA)) {
+            return true;
         }
-    },
 
-    /**
-     * returns true if the current token is a string start!
-     */
-    _isStringStart : function() {
-        var backTrack = (this._tokenPos > 0) ? this.tokens[this._tokenPos - 1] : null;
-        var token = this.tokens[this._tokenPos];
-        return (token == "'" || token == '"') && backTrack != "\\";
+        return firstBeginComment <= firstEndComment && firstBeginCDATA <= firstEndCDATA;
     },
 
-    /**
-     * skips a string section cintentwise no matter how many other strings
-     * are embedded (uses backtracking to check for escapes)
-     *
-     * @param  {String} stringToken the string token to skip!
-     * @return the string value without the enclosing hypenations to be processed later on
-     */
-    handleString : function(stringToken) {
-        var backTrack = null;
-        var resultString = [];
-        while (this.tokens[this._tokenPos] != stringToken || backTrack == "\\") {
-            backTrack = this._getCurrentToken();
-            resultString.push(backTrack);
-            this._tokenPos += this._tokenForward;
-            if (this._tokenPos >= this.tokens.length) {
-                throw Error("Invalid html string opened but not closed");
-            }
-        }
-        this._getCurrentToken();
-        return resultString.join("");
-    },
+    checkBackForComment: function(theStr, tagPos) {
+        var toCheck = theStr.substring(tagPos);
+        var lastBeginComment = toCheck.lastIndexOf("<!--");
+        var lastEndComment = toCheck.lastIndexOf("-->");
 
-    _assertValues : function(assertValues) {
+        var lastBeginCDATA = toCheck.lastIndexOf("<[CDATA[");
+        var lastEndCDATA = toCheck.lastIndexOf("]]>");
 
-        for (var loop = 0; loop < assertValues.length; loop++) {
-            this._assertValue(assertValues[loop]);
-            this._skipBlank(1);
-        }
-    },
 
-    _assertValue : function(expectedToken) {
-        var token = this._getCurrentToken();
-        this._assertLength();
-        if (token != expectedToken) {
-            throw Error("Invalid Token  " + expectedToken + " was expected instead of " + token);
+        if(this.isValidPositionCombination(lastBeginComment, lastEndComment, lastBeginCDATA, lastEndCDATA)) {
+            //TODO we have to handle the embedded cases, for now we leave them out
+            return true;
         }
 
-        return token;
     },
 
-    _assertLength : function() {
-        if (this._tokenPos >= this.tokens.length) {
-            throw Error("Invalid html comment opened but not closed");
-        }
+    isValidPositionCombination: function(pos1, pos2, pos3, pos4) {
+        return pos1 <= pos2 && pos3 <= pos4;
     },
 
-    /**
-     * nested comments are not allowed hence we
-     * skip them!
-     * comment == "&lt;!--" [--&gt;] "--&gt;"
-     */
-    handleComment : function(reverse) {
-        this._assertValues(["-","-"]);
-        reverse = !!reverse;
-
-        while (this._tokenPos < this.tokens.length - 3) {
-            //lookahead3, to save some code
-            var token = this._getCurrentToken();
-            var backTrackBuf = [];
-
-            if (token == "-") {
-                backTrackBuf.push(token);
-                this._skipBlank(1);
-                token = this._getCurrentToken();
-                backTrackBuf.push(token);
-                this._skipBlank(1);
-                token = this._getCurrentToken();
-                backTrackBuf.push(token);
-
-                if (reverse) {
-                    this._skipBlank(1);
-                    token = this._getCurrentToken();
-                    backTrackBuf.push(token);
-                }
-                var sBackTrackBuf = backTrackBuf.join("");
-
-                if (reverse && sBackTrackBuf == "<!--") {
-                    return;
-                } else if (!reverse && sBackTrackBuf == "-->") {
-                    return;
-                }
-            } else {
-                this._skipBlank(1);
-            }
-        }
-    },
-
-    /**
-     * fetches and stores the current token
-     */
-    _getCurrentToken : function() {
-        return this.tokens[this._tokenPos];
+    isFullyEmbedded: function(pos1, pos2, embedPos1, embedPos2) {
+        return embedPos1 < pos1 < pos2 < embedPos2;
     },
 
-    /**
-     * skip blank until the next token is found
-     * @param skipVal  the minimum skip forward to happen
-     * 1 means it skips 1 no matter if the current token is a blank or not!
-     *
-     */
-    _skipBlank : function(skipVal) {
-        var len = this.tokens.length;
-        if (!skipVal) {
-            skipVal = 0;
-        }
-
-        for (this._tokenPos += (skipVal * this._tokenForward); this._tokenPos < len && this._tokenPos >= 0; this._tokenPos += this._tokenForward) {
-            var token = this.tokens[this._tokenPos];
-            if (token != " " && token != "\t" && token != "\n") {
-                return;
-            }
-        }
-    },
-
-    _fetchTagname : function() {
-        var tagName = [];
-
-        //TODO make the tagname prefetch more generic
-
-        tagName.push(this.tokens[this._tokenPos]);
-        this._tokenPos += this._tokenForward;
-        tagName.push(this._getCurrentToken());
-        this._tokenPos += this._tokenForward;
-        tagName.push(this._getCurrentToken());
-        this._tokenPos += this._tokenForward;
-        tagName.push(this._getCurrentToken());
-        this._tokenPos += this._tokenForward;
-
-        return tagName.join("").toLowerCase();
+    isPartiallyEmbedded: function(pos1, pos2, embedPos1, embedPos2) {
+        return embedPos1 < pos1 <  embedPos2 < pos2 || pos1 < embedPos1 < pos2 <  embedPos2  ;    
     }
 
 });

Modified: 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=959421&r1=959420&r2=959421&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Lang.js (original)
+++ myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Lang.js Wed Jun 30 20:24:21 2010
@@ -381,7 +381,7 @@ myfaces._impl.core._Runtime.singletonDel
         return this.isString(theType) ? probe == typeof theType : probe instanceof theType;
     },
 
-  
+
 
     objToArray: function(obj, offset, pack) {
         //since offset is numeric we cannot use the shortcut due to 0 being false
@@ -408,7 +408,7 @@ myfaces._impl.core._Runtime.singletonDel
      * foreach implementation utilizing the
      * ECMAScript wherever possible
      * with added functionality
-     * 
+     *
      * @param arr the array to filter
      * @param func the closure to apply the function to, with the syntax defined by the ecmascript functionality
      * function (element<,key, array>)
@@ -416,14 +416,14 @@ myfaces._impl.core._Runtime.singletonDel
      * @param scope (optional) the scope to apply the closure to
      */
     arrForEach: function(arr, func /*startPos, scope*/) {
-        var startPos = Number(arguments[2]) ||  0;
+        var startPos = Number(arguments[2]) || 0;
         var thisObj = arguments[3];
 
         //check for an existing foreach mapping on array prototypes
         if (Array.prototype.forEach) {
             (startPos) ? arr.slice(startPos).forEach(func, thisObj) : arr.forEach(func, thisObj);
         } else {
-             startPos = (startPos < 0)? Math.ceil(startPos): Math.floor(startPos);
+            startPos = (startPos < 0) ? Math.ceil(startPos) : Math.floor(startPos);
             if (typeof func != "function") {
                 throw new TypeError();
             }
@@ -462,7 +462,7 @@ myfaces._impl.core._Runtime.singletonDel
                 throw new TypeError();
             }
             var ret = [];
-            startPos = (startPos < 0)? Math.ceil(startPos): Math.floor(startPos);
+            startPos = (startPos < 0) ? Math.ceil(startPos) : Math.floor(startPos);
 
             for (var cnt = startPos; cnt < arr.length; cnt++) {
                 if (thisObj) {
@@ -486,18 +486,18 @@ myfaces._impl.core._Runtime.singletonDel
      * @param element the index to search for
      */
     arrIndexOf: function(arr, element /*fromIndex*/) {
-        if(!arr) return -1;
+        if (!arr) return -1;
         var pos = Number(arguments[2]) || 0;
 
-        if(Array.prototype.indexOf) {
+        if (Array.prototype.indexOf) {
             return arr.indexOf(element, pos);
         }
         //var cnt = this._space;
         var len = arr.length;
-        pos = (pos < 0)? Math.ceil(pos): Math.floor(pos);
+        pos = (pos < 0) ? Math.ceil(pos) : Math.floor(pos);
 
         //if negative then it is taken from as offset from the length of the array
-        if(pos < 0) {
+        if (pos < 0) {
             pos += len;
         }
         while (pos < len && arr[pos] !== element) {
@@ -575,6 +575,105 @@ myfaces._impl.core._Runtime.singletonDel
         }
         ret.push(delimiter);
         return ret.join("");
+    },
+
+
+    parseXML: function(txt) {
+        var parser = null, xmlDoc = null;
+        if (window.DOMParser)
+        {
+            parser = new DOMParser();
+            xmlDoc = parser.parseFromString(txt, "text/xml");
+        }
+        else // Internet Explorer
+        {
+            xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
+            xmlDoc.async = "false";
+            xmlDoc.loadXML(txt);
+        }
+        return xmlDoc;
+    },
+
+    serializeXML: function(xmlNode) {
+        if (xmlNode.xml) return xmlNode.xml; //IE
+        //rest of the world
+        return (new XMLSerializer()).serializeToString(xmlNode);
+    },
+
+    serializeChilds: function(xmlNode) {
+        var buffer = [];
+        if (!xmlNode.childNodes) return "";
+        for (var cnt = 0; cnt < xmlNode.childNodes.length; cnt++) {
+            buffer.push(this.serializeXML(xmlNode.childNodes[cnt]));
+        }
+        return buffer.join("");
+    },
+    isXMLParseError: function(xmlContent) {
+        var findParseError = function(node) {
+            if (!node || !node.childNodes) return false;
+            for (var cnt = 0; cnt < node.childNodes.length; cnt++) {
+                var childNode = node.childNodes[cnt];
+                if (childNode.tagName && childNode.tagName == "parsererror") return true;
+            }
+            return false;
+        };
+        return !xmlContent ||
+                (this.exists(xmlContent, "parseError.errorCode") && xmlContent.parseError.errorCode != 0) ||
+                findParseError(xmlContent)
+
     }
 
-});
+    /* not used for now
+     parseHTML: function(txt) {
+     var frame = document.getElementById("parsing-frame");
+     if (frame) {
+     var frame = document.getElementById("parsing-frame");
+     frame.parentNode.removeChild(frame);
+     }
+
+     try {
+     // create frame
+     var frame = document.createElement("iframe"); // iframe (or browser on older Firefox)
+     frame.setAttribute("id", "parsing-frame");
+     frame.setAttribute("name", "parsing-frame");
+     frame.setAttribute("type", "content");
+     frame.setAttribute("collapsed", "true");
+     frame.setAttribute("display", "none");
+     document.body.appendChild(frame);
+     // or
+     // document.documentElement.appendChild(frame);
+
+     // set restrictions as needed
+     if (frame.webNavigation) {
+     frame.webNavigation.allowAuth = false;
+     frame.webNavigation.allowImages = false;
+     frame.webNavigation.allowJavascript = false;
+     frame.webNavigation.allowMetaRedirects = true;
+     frame.webNavigation.allowPlugins = false;
+     frame.webNavigation.allowSubframes = false;
+     }
+
+     var doc = frame.document;
+     if (frame.contentDocument)
+     doc = frame.contentDocument; // For NS6
+     else if (frame.contentWindow)
+     doc = frame.contentWindow.document; // For IE5.5 and IE6
+
+     // Put the content in the iframe
+     doc.open();
+     doc.writeln(txt);
+     doc.close();
+
+     return doc;
+     } finally {
+     if (frame) {
+     var frame = document.getElementById("parsing-frame");
+     frame.parentNode.removeChild(frame);
+     }
+     }
+     // listen for load
+     }
+     */
+
+})
+        ;

Modified: myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/Impl.js
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/Impl.js?rev=959421&r1=959420&r2=959421&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/Impl.js (original)
+++ myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/Impl.js Wed Jun 30 20:24:21 2010
@@ -382,6 +382,7 @@ myfaces._impl.core._Runtime.singletonExt
     getProjectStage : function() {
         /* run through all script tags and try to find the one that includes jsf.js */
         var scriptTags = document.getElementsByTagName("script");
+        var getConfig = myfaces._impl.core._Runtime.getGlobalConfig;
         for (var i = 0; i < scriptTags.length; i++)
         {
             if (scriptTags[i].src.search(/\/javax\.faces\.resource\/jsf\.js.*ln=javax\.faces/) != -1)
@@ -401,13 +402,15 @@ myfaces._impl.core._Runtime.singletonExt
                 }
                 else
                 {
-                    //we found the script, but there was no stage parameter --> Production
-                    return "Production";
+                    //we found the script, but there was no stage parameter -- Production
+                    //(we also add an override here for testing purposes, the default, however is Production)
+                    return getConfig("projectStage", "Production");
+                    //return "Production";
                 }
             }
         }
         /* we could not find anything valid --> return the default value */
-        return "Production";
+        return getConfig("projectStage", "Production");
     },
 
     /**

Modified: myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/_Runtime.js
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/_Runtime.js?rev=959421&r1=959420&r2=959421&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/_Runtime.js (original)
+++ myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/_Runtime.js Wed Jun 30 20:24:21 2010
@@ -463,7 +463,7 @@ if (!myfaces._impl.core._Runtime) {
                 if (key && typeof delFn == "function") {
                     proto[key] = function(/*arguments*/) {
                         var ret = delFn.apply(delegateObj, arguments);
-                        if ('undefined' != ret) return ret;
+                        if ('undefined' != typeof ret) return ret;
                     };
                 }
             })(key, delegateObj[key]);

Modified: myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/xhrCore/_AjaxResponse.js
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/xhrCore/_AjaxResponse.js?rev=959421&r1=959420&r2=959421&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/xhrCore/_AjaxResponse.js (original)
+++ myfaces/core/trunk/api/src/main/javascript/META-INF/resources/myfaces/_impl/xhrCore/_AjaxResponse.js Wed Jun 30 20:24:21 2010
@@ -88,14 +88,17 @@ myfaces._impl.core._Runtime.extendClass(
                 _Impl.sendError(request, context, myfaces._impl.core.Impl.EMPTY_RESPONSE);
                 return;
             }
+            //check for a parseError under certain browsers
+
 
             var xmlContent = request.responseXML;
             //ie6+ keeps the parsing response under xmlContent.parserError
             //while the rest of the world keeps it as element under the first node
 
-            if ((this._Lang.exists(xmlContent, "parseError.errorCode") && xmlContent.parseError.errorCode != 0) || this._Lang.equalsIgnoreCase(xmlContent.firstChild.tagName, "parsererror")) {
-                //TODO improve error name and message sending here
 
+
+
+            if ( this._Lang.isXMLParseError(xmlContent)) {
                 _Impl.sendError(request, context, myfaces._impl.core.Impl.MALFORMEDXML);
                 return;
             }
@@ -170,7 +173,7 @@ myfaces._impl.core._Runtime.extendClass(
     _setVSTOuterForm: function(elem) {
         var viewStateField = this._Dom.findFormElement(elem, this.P_VIEWSTATE);
         if (null != viewStateField) {
-            this._Dom.setAttribute(viewStateField, "value", this.appliedViewState);
+            this._Dom.setAttribute(viewStateField,"value", this.appliedViewState);
         }
     },
 
@@ -352,6 +355,8 @@ myfaces._impl.core._Runtime.extendClass(
 
             switch (node.getAttribute('id')) {
                 case this.P_VIEWROOT:
+                    cDataBlock = cDataBlock.substring(cDataBlock.indexOf("<html"));
+                    this._replaceHead(request, context, cDataBlock);    
                     var resultNode = this._replaceBody(request, context, cDataBlock);
                     if (resultNode) {
                         this._pushOperationResult(resultNode);
@@ -360,7 +365,7 @@ myfaces._impl.core._Runtime.extendClass(
                 case this.P_VIEWHEAD:
                     //we cannot replace the head, almost no browser allows this, some of them throw errors
                     //others simply ignore it or replace it and destroy the dom that way!
-                    throw new Error("Head cannot be replaced, due to browser deficiencies!");
+                    this._replaceHead(request, context, cDataBlock); 
 
                     break;
                 case this.P_VIEWBODY:
@@ -404,6 +409,32 @@ myfaces._impl.core._Runtime.extendClass(
 
     },
 
+    _replaceHead: function(request, context, newData) {
+        var doc = this._Lang.parseXML(newData);
+        var newHead = null;
+        if(this._Lang.isXMLParseError(doc)) {
+            //the standard xml parser failed we retry with the stripper
+            var parser = new (myfaces._impl.core._Runtime.getGlobalConfig("updateParser", myfaces._impl._util._HtmlStripper))();
+            var headData = parser.parse(newData, "head");
+            newHead =  this._Lang.parseXML("<root>"+headData+"</root>");
+            if(this._Lang.isXMLParseError(newHead)) {
+                //we give up no further fallbacks
+                this._Impl.sendError(request, context, _Impl.MALFORMEDXML, _Impl.MALFORMEDXML, "Error in PPR Insert, before id or after id must be present");
+                return;
+            }
+        } else {
+            //parser worked we go on
+            newHead = doc.getElementsByTagName("head")[0];
+        }
+
+        //since we are xml enabled here we probably can walk over it via xml <head> ... </head> normally is valid xml
+        //the ie tricks with form etc... do not work out, so we have to rely on internal xml parsing
+        //prestripping the body should reduce the failure rate of this method
+        ///var xmlData = this._Lang.parseXML("<root>"+headData+"</root>");
+        this._Dom.runScripts(newHead, true);
+    },
+
+
     /**
      * special method to handle the body dom manipulation,
      * replacing the entire body does not work fully by simply adding a second body
@@ -428,16 +459,32 @@ myfaces._impl.core._Runtime.extendClass(
         //the contextualFragment trick does not work on the body tag instead we have to generate a manual body
         //element and then add a child which then is the replacement holder for our fragment!
 
-        //TODO we probably should try to offload this to the browser first via the integrated xml parsing
-        //and if it fails revert to our internal parser
-        var bodyData = parser.parse(newData, "body");
+        //Note, we also could offload this to the browser,
+        //but for now our parser seems to be faster than the browser offloading method
+        //and also does not interfere on security level
+        //the browser offloading methods would be first to use the xml parsing
+        //and if that fails revert to a hidden iframe
+        //var bodyData = parser.parse(newData, "body");
+        var bodyData = null;
+        var doc = this._Lang.parseXML(newData);
+        if(this._Lang.isXMLParseError(doc)) {
+             //the standard xml parser failed we retry with the stripper
+             var parser = new (myfaces._impl.core._Runtime.getGlobalConfig("updateParser", myfaces._impl._util._HtmlStripper))();
+             bodyData = parser.parse(newData, "body");
+        } else {
+             //parser worked we go on
+            var newBodyData = doc.getElementsByTagName("body")[0];
+            bodyData = this._Lang.serializeChilds(newBodyData);
+            for (var cnt = 0; cnt < newBodyData.attributes.length; cnt++) {
+                var value = newBodyData.attributes[cnt].value;
+                if(value)
+                    this._Dom.setAttribute(newBody, newBodyData.attributes[cnt].name, value);
+            }
+        }
+
         bodyParent.replaceChild(newBody, oldBody);
         var returnedElement = this._replaceElement(request, context, placeHolder, bodyData);
 
-        for (var key in parser.tagAttributes) {
-            var value = parser.tagAttributes[key];
-            this._Dom.setAttribute(newBody, key, value);
-        }
         return returnedElement;
     }
     ,