--- markup/html/scripting-parser/parser.html 2008/04/27 11:27:04 1.13 +++ markup/html/scripting-parser/parser.html 2008/04/29 03:29:41 1.15 @@ -65,9 +65,11 @@ var logIndentLevel = 0; function log (s) { + var indent = ''; for (var i = 0; i < logIndentLevel; i++) { - s = ' ' + s; + indent += ' '; } + s = indent + s.replace (/\n/g, "\n" + indent); document.logElement.appendChild (document.createTextNode (s + "\n")); } // log @@ -92,7 +94,8 @@ Parser.prototype.getNextToken = function () { var p = this; var i = this.input; - if (this.parseMode == 'script') { + if (this.parseMode == 'cdata') { + var tagName = this.endTagName; var token; if (p.insertionPoint <= 0) { return {type: 'abort'}; @@ -110,21 +113,22 @@ return ''; }); if (token) return token; - i.s = i.s.replace (/^<\/[Ss][Cc][Rr][Ii][Pp][Tt]>/, function (s) { + var pattern = new RegExp ('^', 'i'); + i.s = i.s.replace (pattern, function (s) { if (p.insertionPoint < s.length) { token = {type: 'abort'}; return s; } - token = {type: 'end-tag', value: 'script'}; + token = {type: 'end-tag', value: tagName}; p.insertionPoint -= s.length; return ''; }); if (token) return token; var m; - if ((p.insertionPoint < ''); @@ -313,6 +318,51 @@ // } } + } else if (token.value == 'style' || + token.value == 'noscript' || + token.value == 'xmp') { + // 1. Create an element for the token in the HTML namespace. + var el = new JSElement (this.doc, token.value); + + // 2. Append the new element to the current node. + this.openElements[this.openElements.length - 1].appendChild (el); + + // 3. Switch the tokeniser's content model flag to the CDATA state. + this.parseMode = 'cdata'; + this.endTagName = token.value; + + // 4.1. Collect all the character tokens. + while (true) { + var token = this.getNextToken (); + log ('token: ' + token.type + ' "' + token.value + '"'); + + if (token.type == 'char') { + // 5. Append a single Text node to the script element node. + el.manakaiAppendText (token.value); + + // 4.2. Until it returns a token that is not a character token, or + // until it stops tokenising. + } else if (token.type == 'eof' || + token.type == 'end-tag' || + token.type == 'abort') { + // 6. Switched back to the PCDATA state. + this.parseMode = 'pcdata'; + + // 7.1. If the next token is not an end tag token with ... + if (!(token.type == 'end-tag' && + token.value == this.endTagName)) { + // 7.2. This is a parse error. + log ('Parse error: no '); + + // 7.3. Mark the script element as "already executed". + el.manakaiAlreadyExecuted = true; + } else { + // 7.4. Ignore it. + // + } + break; + } + } } else { var el = new JSElement (this.doc, token.value); this.openElements[this.openElements.length - 1].appendChild (el); @@ -397,7 +447,7 @@ log ('DOMContentLoaded event fired'); - // "delays tha load event" things has completed: + // "delays the load event" things has completed: // readyState = 'complete' log ('load event fired'); @@ -453,7 +503,7 @@ // 2.4. If the script element has its "already executed" flag set if (e.manakaiAlreadyExecuted) { // 2.5. Abort these steps at this point. - log ('Running a script: aborted'); + log ('Running a script: aborted (already executed)'); logIndentLevel--; return e; } @@ -564,11 +614,22 @@ doc.write.apply (doc, args); return ''; }); - s = s.replace (/^\s*var\s+s\s*=\s*document\.createElement\s*\(\s*['"]script['"]\s*\)\s*;\s*s\.src\s*=\s*(?:'(javascript:[^']*)'|"(javascript:[^"]*)")\s*;\s*document\.documentElement\.appendChild\s*\(\s*s\s*\)\s*;\s*/, + var noDocumentElement = false; + s = s.replace (/^\s*var\s+s\s*=\s*document\.createElement\s*\(\s*['"]script['"]\s*\)\s*;\s*s\.src\s*=\s*(?:'([^']*)'|"([^"]*)")\s*;\s*document\.documentElement\.appendChild\s*\(\s*s\s*\)\s*;\s*/, function (s, t, u) { matched = true; var args = [unescapeJSLiteral (t ? t : u)]; - doc._insertExternalScript.apply (doc, args); + noDocumentElement = !doc._insertExternalScript.apply (doc, args); + return ''; + }); + if (noDocumentElement) { + log ('Script error: documentElement is null'); + break; + } + s = s.replace (/^\s*w\s*\(\s*document\.documentElement\.innerHTML\s*\)\s*;\s*/, + function (s, t) { + matched = true; + log (dumpTree (doc, '')); return ''; }); if (s == '') break; @@ -653,6 +714,7 @@ }; // document.open JSDocument.prototype.write = function () { + log ('document.write: start'); logIndentLevel++; var p = this._parser; @@ -676,6 +738,7 @@ if (p.scriptExecutedAfterParserResumes) { log ('document.write: processed later (there is an unprocessed