aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNigel Tao <nigeltao@golang.org>2011-10-22 20:18:12 +1100
committerNigel Tao <nigeltao@golang.org>2011-10-22 20:18:12 +1100
commit2f352ae48abf1a714f7b3bfb097fab6451067599 (patch)
tree5d3409fd10a9e80f24e2525fc2870efd5d914752
parent696ced50feea2e9711636deeb5a5835cfeb998e9 (diff)
downloadgo-2f352ae48abf1a714f7b3bfb097fab6451067599.tar.gz
go-2f352ae48abf1a714f7b3bfb097fab6451067599.zip
html: parse <select> tags.
The additional test case in parse_test.go is: <select><b><option><select><option></b></select>X R=andybalholm CC=golang-dev https://golang.org/cl/5293051
-rw-r--r--src/pkg/html/parse.go106
-rw-r--r--src/pkg/html/parse_test.go2
2 files changed, 105 insertions, 3 deletions
diff --git a/src/pkg/html/parse.go b/src/pkg/html/parse.go
index ba7e705a79..5b25e2620d 100644
--- a/src/pkg/html/parse.go
+++ b/src/pkg/html/parse.go
@@ -234,6 +234,41 @@ func (p *parser) setOriginalIM(im insertionMode) {
p.originalIM = im
}
+// Section 11.2.3.1, "reset the insertion mode".
+func (p *parser) resetInsertionMode() insertionMode {
+ for i := len(p.oe) - 1; i >= 0; i-- {
+ n := p.oe[i]
+ if i == 0 {
+ // TODO: set n to the context element, for HTML fragment parsing.
+ }
+ switch n.Data {
+ case "select":
+ return inSelectIM
+ case "td", "th":
+ return inCellIM
+ case "tr":
+ return inRowIM
+ case "tbody", "thead", "tfoot":
+ return inTableBodyIM
+ case "caption":
+ // TODO: return inCaptionIM
+ case "colgroup":
+ // TODO: return inColumnGroupIM
+ case "table":
+ return inTableIM
+ case "head":
+ return inBodyIM
+ case "body":
+ return inBodyIM
+ case "frameset":
+ // TODO: return inFramesetIM
+ case "html":
+ return beforeHeadIM
+ }
+ }
+ return inBodyIM
+}
+
// Section 11.2.5.4.1.
func initialIM(p *parser) (insertionMode, bool) {
switch p.tok.Type {
@@ -478,6 +513,12 @@ func inBodyIM(p *parser) (insertionMode, bool) {
p.oe.pop()
p.acknowledgeSelfClosingTag()
p.framesetOK = false
+ case "select":
+ p.reconstructActiveFormattingElements()
+ p.addElement(p.tok.Data, p.tok.Attr)
+ p.framesetOK = false
+ // TODO: detect <select> inside a table.
+ return inSelectIM, true
default:
// TODO.
p.addElement(p.tok.Data, p.tok.Attr)
@@ -671,8 +712,7 @@ func inTableIM(p *parser) (insertionMode, bool) {
switch p.tok.Data {
case "table":
if p.popUntil(tableScopeStopTags, "table") {
- // TODO: "reset the insertion mode appropriately" as per 11.2.3.1.
- return inBodyIM, false
+ return p.resetInsertionMode(), true
}
// Ignore the token.
return inTableIM, true
@@ -833,6 +873,68 @@ func inCellIM(p *parser) (insertionMode, bool) {
return useTheRulesFor(p, inCellIM, inBodyIM)
}
+// Section 11.2.5.4.16.
+func inSelectIM(p *parser) (insertionMode, bool) {
+ endSelect := false
+ switch p.tok.Type {
+ case ErrorToken:
+ // TODO.
+ case TextToken:
+ p.addText(p.tok.Data)
+ case StartTagToken:
+ switch p.tok.Data {
+ case "html":
+ // TODO.
+ case "option":
+ if p.top().Data == "option" {
+ p.oe.pop()
+ }
+ p.addElement(p.tok.Data, p.tok.Attr)
+ case "optgroup":
+ // TODO.
+ case "select":
+ endSelect = true
+ case "input", "keygen", "textarea":
+ // TODO.
+ case "script":
+ // TODO.
+ default:
+ // Ignore the token.
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "option":
+ // TODO.
+ case "optgroup":
+ // TODO.
+ case "select":
+ endSelect = true
+ default:
+ // Ignore the token.
+ }
+ case CommentToken:
+ p.doc.Add(&Node{
+ Type: CommentNode,
+ Data: p.tok.Data,
+ })
+ }
+ if endSelect {
+ for i := len(p.oe) - 1; i >= 0; i-- {
+ switch p.oe[i].Data {
+ case "select":
+ p.oe = p.oe[:i]
+ return p.resetInsertionMode(), true
+ case "option", "optgroup":
+ continue
+ default:
+ // Ignore the token.
+ return inSelectIM, true
+ }
+ }
+ }
+ return inSelectIM, true
+}
+
// Section 11.2.5.4.18.
func afterBodyIM(p *parser) (insertionMode, bool) {
switch p.tok.Type {
diff --git a/src/pkg/html/parse_test.go b/src/pkg/html/parse_test.go
index 18b70bf510..2c56ffd6ad 100644
--- a/src/pkg/html/parse_test.go
+++ b/src/pkg/html/parse_test.go
@@ -123,7 +123,7 @@ func TestParser(t *testing.T) {
rc := make(chan io.Reader)
go readDat(filename, rc)
// TODO(nigeltao): Process all test cases, not just a subset.
- for i := 0; i < 29; i++ {
+ for i := 0; i < 30; i++ {
// Parse the #data section.
b, err := ioutil.ReadAll(<-rc)
if err != nil {