--- markup/html/scripting-parser/parser.html 2008/04/27 08:56:34 1.8 +++ markup/html/scripting-parser/parser.html 2008/04/27 10:34:18 1.10 @@ -47,7 +47,12 @@ var p = new Parser (new InputStream (v)); var doc = p.doc; p.parse (); + log (dumpTree (doc, '')); + + if (p.hasAsyncScript) { + log ('Some script codes are executed asynchronously; it means that the document might be rendered in different ways depending on the network condition and other factors'); + } } } // update2 @@ -73,6 +78,7 @@ this.openElements = [doc]; this.input = i; this.scriptsExecutedAfterParsing = []; + this.scriptsExecutedSoon = []; } // Parser Parser.prototype.getNextToken = function () { @@ -150,14 +156,19 @@ tagName = v.toLowerCase (); return ''; }); - e = e.replace (/^\s*([^\s=]+)\s*(?:=\s*(?:"([^"]*)"|'([^']*)'|([^"']+)))?/, - function (x, attrName, attrValue1, attrValue2, attrValue3) { - v = attrValue1 || attrValue2 || attrValue3; - v = v.replace (/"/g, '"').replace (/'/g, "'") - .replace (/&/g, '&'); - attrs[attrName.toLowerCase ()] = v; - return ''; - }); + while (true) { + var m = false; + e = e.replace (/^\s*([^\s=]+)\s*(?:=\s*(?:"([^"]*)"|'([^']*)'|([^"'\s]*)))?/, + function (x, attrName, attrValue1, attrValue2, attrValue3) { + v = attrValue1 || attrValue2 || attrValue3; + v = v.replace (/"/g, '"').replace (/'/g, "'") + .replace (/&/g, '&'); + attrs[attrName.toLowerCase ()] = v; + m = true; + return ''; + }); + if (!m) break; + } if (e.length) { log ('Broken start tag: "' + e + '"'); } @@ -324,8 +335,21 @@ // "When a script completes loading" rules start applying. - // TODO: Handles "list of scripts that will execute as soon as possible" - // and "list of scripts that will execute asynchronously" + // List of scripts that will execute as soon as possible + for (var i = 0; i < this.scriptsExecutedSoon.length; i++) { + var e = this.scriptsExecutedSoon[i]; + + // If it has completed loading + log ('Execute an external script not inserted by parser...'); + executeScript (this.doc, e); + + // NOTE: It MAY be executed before the end of the parsing, according + // to the spec. + this.hasAsyncScript = true; + } + + // TODO: Handles + // "list of scripts that will execute asynchronously" // Handle "list of scripts that will execute when the document has finished // parsing". @@ -429,9 +453,10 @@ log ('Error: There is a script that will execute as soon as the parser resumes.'); } p.scriptExecutedWhenParserResumes = e; - log ('Running a script: aborted (src)'); + log ('Running a script: aborted (src parser-inserted)'); } else if (e.src != null) { - // TODO + p.scriptsExecutedSoon.push (e); + log ('Running a script: aborted (src)'); } else { executeScript (doc, e); // even if other scripts are already executing. } @@ -479,9 +504,13 @@ var m; if (m = uri.match (/^javascript:\s*(?:'([^']*)'|"([^"]+)")\s*$/i)) { if (m[1]) { - return m[1]; + return m[1].replace (/\\u([0-9A-F]{4})/g, function (s, v) { + return String.fromCharCode (parseInt ('0x' + v)); + }); } else if (m[2]) { - return m[2]; + return m[2].replace (/\\u([0-9A-F]{4})/g, function (s, v) { + return String.fromCharCode (parseInt ('0x' + v)); + }); } else { return null; } @@ -508,6 +537,13 @@ 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*/, + function (s, t, u) { + matched = true; + var args = [t ? t : u]; + doc._insertExternalScript.apply (doc, args); + return ''; + }); if (s == '') break; if (!matched) { log ('Script parse error: "' + s + '"'); @@ -626,6 +662,22 @@ return; }; // document.write + JSDocument.prototype._insertExternalScript = function (uri) { + var s = new JSElement (this, 'script'); + s.src = uri; + this.documentElement.appendChild (s); + }; // _insertExternalScript + + JSDocument.prototype.__defineGetter__ ('documentElement', function () { + var cn = this.childNodes; + for (var i = 0; i < cn.length; i++) { + if (cn[i] instanceof JSElement) { + return cn[i] + } + } + return null; + }); + JSElement.prototype.__defineGetter__ ('text', function () { var r = ''; for (var i = 0; i < this.childNodes.length; i++) { @@ -644,7 +696,9 @@ r += '| ' + indent + node.localName + '\n'; if (node.async) r += '| ' + indent + ' async=""\n'; if (node.defer) r += '| ' + indent + ' defer=""\n'; - if (node.src) r += '| ' + indent + ' src="' + node.src + '"\n'; + if (node.src != null) { + r += '| ' + indent + ' src="' + node.src + '"\n'; + } r += dumpTree (node, indent + ' '); } else if (node instanceof JSText) { r += '| ' + indent + '"' + node.data + '"\n'; @@ -693,10 +747,10 @@ <p> -
-