--- markup/html/scripting-parser/parser.html 2008/04/27 10:34:18 1.10
+++ markup/html/scripting-parser/parser.html 2008/04/27 11:21:09 1.12
@@ -79,6 +79,7 @@
this.input = i;
this.scriptsExecutedAfterParsing = [];
this.scriptsExecutedSoon = [];
+ this.scriptsExecutedAsynchronously = [];
} // Parser
Parser.prototype.getNextToken = function () {
@@ -335,22 +336,42 @@
// "When a script completes loading" rules start applying.
- // List of scripts that will execute as soon as possible
- for (var i = 0; i < this.scriptsExecutedSoon.length; i++) {
- var e = this.scriptsExecutedSoon[i];
+ while (this.scriptsExecutedSoon.length > 0 ||
+ this.scriptsExecutedAsynchronously.length > 0) {
+ // Handle "list of scripts that will execute as soon as possible".
+ while (this.scriptsExecutedSoon.length > 0) {
+ var e = this.scriptsExecutedSoon.shift ();
+
+ // 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;
+ }
+
+ // Handle "list of scripts that will execute asynchronously".
+ while (this.scriptsExecutedAsynchronously.length > 0) {
+ var e = this.scriptsExecutedAsynchronously.shift ();
+
+ // Step 1.
+ // We assume that all scripts have been loaded at this time.
+
+ // Step 2.
+ log ('Execute an asynchronous script...');
+ executeScript (this.doc, e);
+
+ // Step 3.
+ //
+
+ // Step 4.
+ //
- // 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;
+ 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".
var list = this.scriptsExecutedAfterParsing;
@@ -444,10 +465,13 @@
p.scriptsExecutedAfterParsing.push (e);
log ('Running a script: aborted (defer)');
} else if (e.async && e.src != null) {
- // TODO
- } else if (e.async && e.src == null
- /* && list of scripts that will execute asynchronously is not empty */) {
- // TODO
+ p.scriptsExecutedAsynchronously.push (e);
+ log ('Running a script: aborted (async src)');
+ } else if (e.async && e.src == null &&
+ p.scriptsExecutedAsynchronously.length > 0) {
+ p.scriptsExecutedAsynchronously.push (e);
+ log ('Running a script: aborted (async)');
+ // ISSUE: What is the difference with the case above?
} else if (e.src != null && e.manakaiParserInserted) {
if (p.scriptExecutedWhenParserResumes) {
log ('Error: There is a script that will execute as soon as the parser resumes.');
@@ -504,13 +528,9 @@
var m;
if (m = uri.match (/^javascript:\s*(?:'([^']*)'|"([^"]+)")\s*$/i)) {
if (m[1]) {
- return m[1].replace (/\\u([0-9A-F]{4})/g, function (s, v) {
- return String.fromCharCode (parseInt ('0x' + v));
- });
+ return unescapeJSLiteral (m[1]);
} else if (m[2]) {
- return m[2].replace (/\\u([0-9A-F]{4})/g, function (s, v) {
- return String.fromCharCode (parseInt ('0x' + v));
- });
+ return unescapeJSLiteral (m[2]);
} else {
return null;
}
@@ -531,7 +551,7 @@
matched = true;
var args = [];
t.replace (/('[^']*'|"[^"]*")/g, function (s, v) {
- args.push (v.substring (1, v.length - 1));
+ args.push (unescapeJSLiteral (v.substring (1, v.length - 1)));
return '';
});
doc.write.apply (doc, args);
@@ -540,7 +560,7 @@
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];
+ var args = [unescapeJSLiteral (t ? t : u)];
doc._insertExternalScript.apply (doc, args);
return '';
});
@@ -552,6 +572,12 @@
}
} // parseAndRunScript
+ function unescapeJSLiteral (s) {
+ return s.replace (/\\u([0-9A-Fa-f]{4})/g, function (t, v) {
+ return String.fromCharCode (parseInt ('0x' + v));
+ });
+ } // unescapeJSLiteral
+
function JSText (data) {
this.data = data;
} // JSText
@@ -788,13 +814,23 @@
src
attribute of the script
element. In addition,
the URI must be conform to
the regular expression ^javascript:\s*(?:"[^"]*"|'[^']*')\s*$
.
-
\uHHHH
escapes only in
-javascript:
URI.
+\uHHHH
escapes in JavaScript
+string literals.
+document.open ()
call. In other word, delayed
+(deferred or asynchronous) script executions and event firings might be
+treated in a wrong way if a document.open ()
invocation
+is implicitly done by document.write ()
in a delayed script.
For some reason, this parser does not work in browsers that do not support JavaScript 1.5. + +