Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #45 from Pomax/textarea-cdata

added CDATA intepreting, rather than markup parsing, for textarea content
  • Loading branch information...
commit f0206edbd9de869fb2188a6c94c593f7012f83a6 2 parents 541d71a + c2d77c3
@toolness authored
Showing with 51 additions and 1 deletion.
  1. +38 −1 slowparse.js
  2. +13 −0 test/test-slowparse.js
View
39 slowparse.js
@@ -1034,7 +1034,7 @@ var Slowparse = (function() {
this._parseComment();
return;
}
-
+
this.stream.eat(/\//);
this.stream.eatWhile(/[\w\d]/);
var token = this.stream.makeToken();
@@ -1090,6 +1090,37 @@ var Slowparse = (function() {
token = this.stream.makeToken();
throw new ParseError("UNTERMINATED_COMMENT", token);
},
+ // This helper parses CDATA content, which should be treated as raw text,
+ // rather than being parsed for markup. It assumes the stream has just
+ // passed the beginning `<tagname` of an HTML element.
+ _parseCDATA: function(tagname) {
+ var token,
+ matchString = '</'+tagname+'>',
+ text,
+ textInterval = { start: 0, end: 0 },
+ openTagEnd = this.domBuilder.currentNode.parseInfo.openTag.end,
+ closeTagInterval;
+
+ this.stream.makeToken();
+ while (!this.stream.end()) {
+ if (this.stream.match(matchString, true)) {
+ token = this.stream.makeToken();
+ text = token.value.slice(0, -matchString.length);
+ closeTagInterval = {
+ start: openTagEnd + text.length,
+ end: token.interval.end
+ };
+ this.domBuilder.currentNode.parseInfo.closeTag = closeTagInterval;
+ textInterval.start = token.interval.start;
+ textInterval.end = token.interval.end - (closeTagInterval.end - closeTagInterval.start);
+ this.domBuilder.text(text, textInterval);
+ this.domBuilder.popElement();
+ return;
+ }
+ this.stream.next();
+ }
+ throw new ParseError("UNCLOSED_TAG", this);
+ },
// This helper function parses the end of a closing tag. It expects
// the stream to be right after the end of the closing tag's tag
// name.
@@ -1135,6 +1166,12 @@ var Slowparse = (function() {
var cssBlock = this.cssParser.parse();
this.domBuilder.text(cssBlock.value, cssBlock.parseInfo);
}
+
+ // If the opening tag represents a `<textarea>` element, we need
+ // to parse all its contents as CDATA (unparsed character data)
+ if (tagName && tagName === "textarea") {
+ this._parseCDATA("textarea");
+ }
return;
} else
View
13 test/test-slowparse.js
@@ -135,6 +135,19 @@ test("parsing of HTML comments with '--' in them", function() {
"serialization of generated DOM matches original HTML");
});
+test("parsing of CDATA in <textarea> elements", function() {
+ var text = "\nThis is CDATA with <p>, <i> and" +
+ " <script> in it.\nThis should not trigger errors.";
+ var html = "<textarea>" + text + "</textarea>";
+ var doc = parseWithoutErrors(html);
+
+ equal(doc.childNodes.length, 1, "doc has one child node");
+ equal(doc.childNodes[0].nodeName, "TEXTAREA", "child node is <textarea>");
+ equal(doc.childNodes[0].childNodes.length, 1, "textarea has one child");
+ equal(doc.childNodes[0].childNodes[0].nodeValue, text,
+ "textarea contents are ok");
+});
+
testManySnippets("parsing of HTML is case-insensitive", [
'<P CLASS="FOO">hi</P>',
'<P class="FOO">hi</P>',
Please sign in to comment.
Something went wrong with that request. Please try again.