--- markup/html/scripting-parser/parser.html 2008/04/29 02:50:00 1.14
+++ markup/html/scripting-parser/parser.html 2008/05/16 10:29:25 1.17
@@ -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
@@ -81,6 +83,7 @@
doc = new JSDocument (this);
doc.manakaiIsHTML = true;
}
+ this.nextToken = [];
this.doc = doc;
this.openElements = [doc];
this.input = i;
@@ -90,6 +93,10 @@
} // Parser
Parser.prototype.getNextToken = function () {
+ if (this.nextToken.length) {
+ return this.nextToken.shift ();
+ }
+
var p = this;
var i = this.input;
if (this.parseMode == 'cdata') {
@@ -144,7 +151,7 @@
i.s = i.s.replace (/^<\/([^>]+)(?:>|$)/, function (s, e) {
if (p.insertionPoint < s.length ||
(p.insertionPoint <= s.length &&
- s.substring (s.length - 1, 1) != '>')) {
+ s.substring (s.length - 1, s.length) != '>')) {
token = {type: 'abort'};
return s;
}
@@ -156,7 +163,7 @@
i.s = i.s.replace (/^<([^>]+)(?:>|$)/, function (s, e) {
if (p.insertionPoint < s.length ||
(p.insertionPoint <= s.length &&
- s.substring (s.length - 1, 1) != '>')) {
+ s.substring (s.length - 1, s.length) != '>')) {
token = {type: 'abort'};
return s;
}
@@ -219,6 +226,24 @@
var token = this.getNextToken ();
log ('token: ' + token.type + ' "' + token.value + '"');
+ if (this.cdataEndTagRequired) {
+ // Generic CDATA parsing algorithm
+
+ if (token.type != 'abort') {
+ // 7.
+ if (token.type == 'end-tag' && token.value == this.endTagName) {
+ // 7.1. Ignores it.
+ //
+ } else {
+ // 7.2. Parse error.
+ log ('Parse error: no ' + this.endTagName + '>');
+ this.nextToken.unshift (token);
+ }
+ this.cdataEndTagRequired = false;
+ continue;
+ }
+ }
+
if (token.type == 'start-tag') {
if (token.value == 'script') {
// 1. Create an element for the token in the HTML namespace.
@@ -255,6 +280,7 @@
if (!(token.type == 'end-tag' && token.value == 'script')) {
// 7.2. This is a parse error.
log ('Parse error: no ' + 'script>');
+ this.nextToken.unshift (token);
// 7.3. Mark the script element as "already executed".
el.manakaiAlreadyExecuted = true;
@@ -346,11 +372,17 @@
// 6. Switched back to the PCDATA state.
this.parseMode = 'pcdata';
+ if (token.type == 'abort') {
+ this.cdataEndTagRequired = true;
+ break;
+ }
+
// 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 ' + this.endTagName + '>');
+ this.nextToken.unshift (token);
// 7.3. Mark the script element as "already executed".
el.manakaiAlreadyExecuted = true;
@@ -501,7 +533,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;
}
@@ -566,7 +598,6 @@
}
// If the load was successful
- log ('load event fired at the script element');
if (true) {
// Scripting is enabled, Document.designMode is disabled,
@@ -575,6 +606,8 @@
parseAndRunScript (doc, s);
}
+ log ('load event fired at the script element');
+
log ('executing a script block: end');
} // executeScript
@@ -612,11 +645,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;
@@ -701,6 +745,7 @@
}; // document.open
JSDocument.prototype.write = function () {
+ log ('document.write: start');
logIndentLevel++;
var p = this._parser;
@@ -724,6 +769,7 @@
if (p.scriptExecutedAfterParserResumes) {
log ('document.write: processed later (there is an unprocessed