|
|
@@ -32,6 +32,8 @@ type parser struct {
|
|
|
head, form *Node
|
|
|
// Other parsing state flags (section 12.2.4.5).
|
|
|
scripting, framesetOK bool
|
|
|
+ // The stack of template insertion modes
|
|
|
+ templateStack insertionModeStack
|
|
|
// im is the current insertion mode.
|
|
|
im insertionMode
|
|
|
// originalIM is the insertion mode to go back to after completing a text
|
|
|
@@ -126,7 +128,7 @@ func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int {
|
|
|
return -1
|
|
|
}
|
|
|
case tableScope:
|
|
|
- if tagAtom == a.Html || tagAtom == a.Table {
|
|
|
+ if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template {
|
|
|
return -1
|
|
|
}
|
|
|
case selectScope:
|
|
|
@@ -162,17 +164,17 @@ func (p *parser) clearStackToContext(s scope) {
|
|
|
tagAtom := p.oe[i].DataAtom
|
|
|
switch s {
|
|
|
case tableScope:
|
|
|
- if tagAtom == a.Html || tagAtom == a.Table {
|
|
|
+ if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template {
|
|
|
p.oe = p.oe[:i+1]
|
|
|
return
|
|
|
}
|
|
|
case tableRowScope:
|
|
|
- if tagAtom == a.Html || tagAtom == a.Tr {
|
|
|
+ if tagAtom == a.Html || tagAtom == a.Tr || tagAtom == a.Template {
|
|
|
p.oe = p.oe[:i+1]
|
|
|
return
|
|
|
}
|
|
|
case tableBodyScope:
|
|
|
- if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead {
|
|
|
+ if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead || tagAtom == a.Template {
|
|
|
p.oe = p.oe[:i+1]
|
|
|
return
|
|
|
}
|
|
|
@@ -183,7 +185,7 @@ func (p *parser) clearStackToContext(s scope) {
|
|
|
}
|
|
|
|
|
|
// generateImpliedEndTags pops nodes off the stack of open elements as long as
|
|
|
-// the top node has a tag name of dd, dt, li, option, optgroup, p, rp, or rt.
|
|
|
+// the top node has a tag name of dd, dt, li, optgroup, option, p, rp, or rt.
|
|
|
// If exceptions are specified, nodes with that name will not be popped off.
|
|
|
func (p *parser) generateImpliedEndTags(exceptions ...string) {
|
|
|
var i int
|
|
|
@@ -192,7 +194,9 @@ loop:
|
|
|
n := p.oe[i]
|
|
|
if n.Type == ElementNode {
|
|
|
switch n.DataAtom {
|
|
|
- case a.Dd, a.Dt, a.Li, a.Option, a.Optgroup, a.P, a.Rp, a.Rt:
|
|
|
+ // TODO: add a.Rb and a.Rtc, to match the spec. This needs additions to the
|
|
|
+ // atom package. Ditto for generateAllImpliedEndTags.
|
|
|
+ case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rp, a.Rt:
|
|
|
for _, except := range exceptions {
|
|
|
if n.Data == except {
|
|
|
break loop
|
|
|
@@ -207,6 +211,27 @@ loop:
|
|
|
p.oe = p.oe[:i+1]
|
|
|
}
|
|
|
|
|
|
+// generateAllImpliedEndTags pops nodes off the stack of open elements as long as
|
|
|
+// the top node has a tag name of caption, colgroup, dd, div, dt, li, optgroup, option, p, rp, rt,
|
|
|
+// span, tbody, td, tfoot, th, thead or tr.
|
|
|
+func (p *parser) generateAllImpliedEndTags() {
|
|
|
+ var i int
|
|
|
+ for i = len(p.oe) - 1; i >= 0; i-- {
|
|
|
+ n := p.oe[i]
|
|
|
+ if n.Type == ElementNode {
|
|
|
+ switch n.DataAtom {
|
|
|
+ // TODO: remove this divergence from the HTML5 spec
|
|
|
+ case a.Caption, a.Colgroup, a.Dd, a.Div, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rp, a.Rt,
|
|
|
+ a.Span, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break
|
|
|
+ }
|
|
|
+
|
|
|
+ p.oe = p.oe[:i+1]
|
|
|
+}
|
|
|
+
|
|
|
// addChild adds a child node n to the top element, and pushes n onto the stack
|
|
|
// of open elements if it is an element node.
|
|
|
func (p *parser) addChild(n *Node) {
|
|
|
@@ -236,7 +261,7 @@ func (p *parser) shouldFosterParent() bool {
|
|
|
// fosterParent adds a child node according to the foster parenting rules.
|
|
|
// Section 12.2.6.1, "foster parenting".
|
|
|
func (p *parser) fosterParent(n *Node) {
|
|
|
- var table, parent, prev *Node
|
|
|
+ var table, parent, prev, template *Node
|
|
|
var i int
|
|
|
for i = len(p.oe) - 1; i >= 0; i-- {
|
|
|
if p.oe[i].DataAtom == a.Table {
|
|
|
@@ -245,6 +270,19 @@ func (p *parser) fosterParent(n *Node) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ var j int
|
|
|
+ for j = len(p.oe) - 1; j >= 0; j-- {
|
|
|
+ if p.oe[j].DataAtom == a.Template {
|
|
|
+ template = p.oe[j]
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if template != nil && (table == nil || j < i) {
|
|
|
+ template.AppendChild(n)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
if table == nil {
|
|
|
// The foster parent is the html element.
|
|
|
parent = p.oe[0]
|
|
|
@@ -415,14 +453,34 @@ func (p *parser) setOriginalIM() {
|
|
|
func (p *parser) resetInsertionMode() {
|
|
|
for i := len(p.oe) - 1; i >= 0; i-- {
|
|
|
n := p.oe[i]
|
|
|
- if i == 0 && p.context != nil {
|
|
|
+ last := i == 0
|
|
|
+ if last && p.context != nil {
|
|
|
n = p.context
|
|
|
}
|
|
|
|
|
|
switch n.DataAtom {
|
|
|
case a.Select:
|
|
|
+ if !last {
|
|
|
+ for ancestor, first := n, p.oe[0]; ancestor != first; {
|
|
|
+ if ancestor == first {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ ancestor = p.oe[p.oe.index(ancestor)-1]
|
|
|
+ switch ancestor.DataAtom {
|
|
|
+ case a.Template:
|
|
|
+ p.im = inSelectIM
|
|
|
+ return
|
|
|
+ case a.Table:
|
|
|
+ p.im = inSelectInTableIM
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
p.im = inSelectIM
|
|
|
case a.Td, a.Th:
|
|
|
+ // TODO: remove this divergence from the HTML5 spec.
|
|
|
+ //
|
|
|
+ // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
|
|
|
p.im = inCellIM
|
|
|
case a.Tr:
|
|
|
p.im = inRowIM
|
|
|
@@ -434,20 +492,32 @@ func (p *parser) resetInsertionMode() {
|
|
|
p.im = inColumnGroupIM
|
|
|
case a.Table:
|
|
|
p.im = inTableIM
|
|
|
+ case a.Template:
|
|
|
+ p.im = p.templateStack.top()
|
|
|
case a.Head:
|
|
|
- p.im = inBodyIM
|
|
|
+ // TODO: remove this divergence from the HTML5 spec.
|
|
|
+ //
|
|
|
+ // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
|
|
|
+ p.im = inHeadIM
|
|
|
case a.Body:
|
|
|
p.im = inBodyIM
|
|
|
case a.Frameset:
|
|
|
p.im = inFramesetIM
|
|
|
case a.Html:
|
|
|
- p.im = beforeHeadIM
|
|
|
+ if p.head == nil {
|
|
|
+ p.im = beforeHeadIM
|
|
|
+ } else {
|
|
|
+ p.im = afterHeadIM
|
|
|
+ }
|
|
|
default:
|
|
|
+ if last {
|
|
|
+ p.im = inBodyIM
|
|
|
+ return
|
|
|
+ }
|
|
|
continue
|
|
|
}
|
|
|
return
|
|
|
}
|
|
|
- p.im = inBodyIM
|
|
|
}
|
|
|
|
|
|
const whitespace = " \t\r\n\f"
|
|
|
@@ -590,19 +660,36 @@ func inHeadIM(p *parser) bool {
|
|
|
case a.Head:
|
|
|
// Ignore the token.
|
|
|
return true
|
|
|
+ case a.Template:
|
|
|
+ p.addElement()
|
|
|
+ p.afe = append(p.afe, &scopeMarker)
|
|
|
+ p.framesetOK = false
|
|
|
+ p.im = inTemplateIM
|
|
|
+ p.templateStack = append(p.templateStack, inTemplateIM)
|
|
|
+ return true
|
|
|
}
|
|
|
case EndTagToken:
|
|
|
switch p.tok.DataAtom {
|
|
|
case a.Head:
|
|
|
- n := p.oe.pop()
|
|
|
- if n.DataAtom != a.Head {
|
|
|
- panic("html: bad parser state: <head> element not found, in the in-head insertion mode")
|
|
|
- }
|
|
|
+ p.oe.pop()
|
|
|
p.im = afterHeadIM
|
|
|
return true
|
|
|
case a.Body, a.Html, a.Br:
|
|
|
p.parseImpliedToken(EndTagToken, a.Head, a.Head.String())
|
|
|
return false
|
|
|
+ case a.Template:
|
|
|
+ if !p.oe.contains(a.Template) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ p.generateAllImpliedEndTags()
|
|
|
+ if n := p.oe.top(); n.DataAtom != a.Template {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ p.popUntil(defaultScope, a.Template)
|
|
|
+ p.clearActiveFormattingElements()
|
|
|
+ p.templateStack.pop()
|
|
|
+ p.resetInsertionMode()
|
|
|
+ return true
|
|
|
default:
|
|
|
// Ignore the token.
|
|
|
return true
|
|
|
@@ -648,7 +735,7 @@ func afterHeadIM(p *parser) bool {
|
|
|
p.addElement()
|
|
|
p.im = inFramesetIM
|
|
|
return true
|
|
|
- case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
|
|
|
+ case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
|
|
|
p.oe = append(p.oe, p.head)
|
|
|
defer p.oe.remove(p.head)
|
|
|
return inHeadIM(p)
|
|
|
@@ -660,6 +747,8 @@ func afterHeadIM(p *parser) bool {
|
|
|
switch p.tok.DataAtom {
|
|
|
case a.Body, a.Html, a.Br:
|
|
|
// Drop down to creating an implied <body> tag.
|
|
|
+ case a.Template:
|
|
|
+ return inHeadIM(p)
|
|
|
default:
|
|
|
// Ignore the token.
|
|
|
return true
|
|
|
@@ -727,10 +816,16 @@ func inBodyIM(p *parser) bool {
|
|
|
case StartTagToken:
|
|
|
switch p.tok.DataAtom {
|
|
|
case a.Html:
|
|
|
+ if p.oe.contains(a.Template) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
copyAttributes(p.oe[0], p.tok)
|
|
|
- case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
|
|
|
+ case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
|
|
|
return inHeadIM(p)
|
|
|
case a.Body:
|
|
|
+ if p.oe.contains(a.Template) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
if len(p.oe) >= 2 {
|
|
|
body := p.oe[1]
|
|
|
if body.Type == ElementNode && body.DataAtom == a.Body {
|
|
|
@@ -767,7 +862,7 @@ func inBodyIM(p *parser) bool {
|
|
|
// The newline, if any, will be dealt with by the TextToken case.
|
|
|
p.framesetOK = false
|
|
|
case a.Form:
|
|
|
- if p.form == nil {
|
|
|
+ if p.oe.contains(a.Template) || p.form == nil {
|
|
|
p.popUntil(buttonScope, a.P)
|
|
|
p.addElement()
|
|
|
p.form = p.top()
|
|
|
@@ -972,7 +1067,13 @@ func inBodyIM(p *parser) bool {
|
|
|
p.acknowledgeSelfClosingTag()
|
|
|
}
|
|
|
return true
|
|
|
- case a.Caption, a.Col, a.Colgroup, a.Frame, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
|
|
|
+ case a.Frame:
|
|
|
+ // TODO: remove this divergence from the HTML5 spec.
|
|
|
+ if p.oe.contains(a.Template) {
|
|
|
+ p.addElement()
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ case a.Caption, a.Col, a.Colgroup, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
|
|
|
// Ignore the token.
|
|
|
default:
|
|
|
p.reconstructActiveFormattingElements()
|
|
|
@@ -993,15 +1094,28 @@ func inBodyIM(p *parser) bool {
|
|
|
case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul:
|
|
|
p.popUntil(defaultScope, p.tok.DataAtom)
|
|
|
case a.Form:
|
|
|
- node := p.form
|
|
|
- p.form = nil
|
|
|
- i := p.indexOfElementInScope(defaultScope, a.Form)
|
|
|
- if node == nil || i == -1 || p.oe[i] != node {
|
|
|
- // Ignore the token.
|
|
|
- return true
|
|
|
+ if p.oe.contains(a.Template) {
|
|
|
+ if !p.oe.contains(a.Form) {
|
|
|
+ // Ignore the token.
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ p.generateImpliedEndTags()
|
|
|
+ if p.tok.DataAtom == a.Form {
|
|
|
+ // Ignore the token.
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ p.popUntil(defaultScope, a.Form)
|
|
|
+ } else {
|
|
|
+ node := p.form
|
|
|
+ p.form = nil
|
|
|
+ i := p.indexOfElementInScope(defaultScope, a.Form)
|
|
|
+ if node == nil || i == -1 || p.oe[i] != node {
|
|
|
+ // Ignore the token.
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ p.generateImpliedEndTags()
|
|
|
+ p.oe.remove(node)
|
|
|
}
|
|
|
- p.generateImpliedEndTags()
|
|
|
- p.oe.remove(node)
|
|
|
case a.P:
|
|
|
if !p.elementInScope(buttonScope, a.P) {
|
|
|
p.parseImpliedToken(StartTagToken, a.P, a.P.String())
|
|
|
@@ -1022,6 +1136,8 @@ func inBodyIM(p *parser) bool {
|
|
|
case a.Br:
|
|
|
p.tok.Type = StartTagToken
|
|
|
return false
|
|
|
+ case a.Template:
|
|
|
+ return inHeadIM(p)
|
|
|
default:
|
|
|
p.inBodyEndTagOther(p.tok.DataAtom)
|
|
|
}
|
|
|
@@ -1030,6 +1146,22 @@ func inBodyIM(p *parser) bool {
|
|
|
Type: CommentNode,
|
|
|
Data: p.tok.Data,
|
|
|
})
|
|
|
+ case ErrorToken:
|
|
|
+ // TODO: remove this divergence from the HTML5 spec.
|
|
|
+ if len(p.templateStack) > 0 {
|
|
|
+ p.im = inTemplateIM
|
|
|
+ return false
|
|
|
+ } else {
|
|
|
+ for _, e := range p.oe {
|
|
|
+ // TODO(namusyaka): rb and rtc elements should be added after updating atom.
|
|
|
+ switch e.DataAtom {
|
|
|
+ case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rp, a.Rt, a.Tbody, a.Td, a.Tfoot, a.Th,
|
|
|
+ a.Thead, a.Tr, a.Body, a.Html:
|
|
|
+ default:
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
return true
|
|
|
@@ -1135,6 +1267,12 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
|
|
|
switch commonAncestor.DataAtom {
|
|
|
case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
|
|
|
p.fosterParent(lastNode)
|
|
|
+ case a.Template:
|
|
|
+ // TODO: remove namespace checking
|
|
|
+ if commonAncestor.Namespace == "html" {
|
|
|
+ commonAncestor = commonAncestor.LastChild
|
|
|
+ }
|
|
|
+ fallthrough
|
|
|
default:
|
|
|
commonAncestor.AppendChild(lastNode)
|
|
|
}
|
|
|
@@ -1249,7 +1387,7 @@ func inTableIM(p *parser) bool {
|
|
|
}
|
|
|
// Ignore the token.
|
|
|
return true
|
|
|
- case a.Style, a.Script:
|
|
|
+ case a.Style, a.Script, a.Template:
|
|
|
return inHeadIM(p)
|
|
|
case a.Input:
|
|
|
for _, t := range p.tok.Attr {
|
|
|
@@ -1261,7 +1399,7 @@ func inTableIM(p *parser) bool {
|
|
|
}
|
|
|
// Otherwise drop down to the default action.
|
|
|
case a.Form:
|
|
|
- if p.form != nil {
|
|
|
+ if p.oe.contains(a.Template) || p.form != nil {
|
|
|
// Ignore the token.
|
|
|
return true
|
|
|
}
|
|
|
@@ -1291,6 +1429,8 @@ func inTableIM(p *parser) bool {
|
|
|
case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
|
|
|
// Ignore the token.
|
|
|
return true
|
|
|
+ case a.Template:
|
|
|
+ return inHeadIM(p)
|
|
|
}
|
|
|
case CommentToken:
|
|
|
p.addChild(&Node{
|
|
|
@@ -1386,11 +1526,13 @@ func inColumnGroupIM(p *parser) bool {
|
|
|
p.oe.pop()
|
|
|
p.acknowledgeSelfClosingTag()
|
|
|
return true
|
|
|
+ case a.Template:
|
|
|
+ return inHeadIM(p)
|
|
|
}
|
|
|
case EndTagToken:
|
|
|
switch p.tok.DataAtom {
|
|
|
case a.Colgroup:
|
|
|
- if p.oe.top().DataAtom != a.Html {
|
|
|
+ if p.oe.top().DataAtom == a.Colgroup {
|
|
|
p.oe.pop()
|
|
|
p.im = inTableIM
|
|
|
}
|
|
|
@@ -1398,14 +1540,16 @@ func inColumnGroupIM(p *parser) bool {
|
|
|
case a.Col:
|
|
|
// Ignore the token.
|
|
|
return true
|
|
|
+ case a.Template:
|
|
|
+ return inHeadIM(p)
|
|
|
}
|
|
|
}
|
|
|
- if p.oe.top().DataAtom != a.Html {
|
|
|
- p.oe.pop()
|
|
|
- p.im = inTableIM
|
|
|
- return false
|
|
|
+ if p.oe.top().DataAtom != a.Colgroup {
|
|
|
+ return true
|
|
|
}
|
|
|
- return true
|
|
|
+ p.oe.pop()
|
|
|
+ p.im = inTableIM
|
|
|
+ return false
|
|
|
}
|
|
|
|
|
|
// Section 12.2.6.4.13.
|
|
|
@@ -1597,7 +1741,7 @@ func inSelectIM(p *parser) bool {
|
|
|
p.tokenizer.NextIsNotRawText()
|
|
|
// Ignore the token.
|
|
|
return true
|
|
|
- case a.Script:
|
|
|
+ case a.Script, a.Template:
|
|
|
return inHeadIM(p)
|
|
|
}
|
|
|
case EndTagToken:
|
|
|
@@ -1618,6 +1762,8 @@ func inSelectIM(p *parser) bool {
|
|
|
if p.popUntil(selectScope, a.Select) {
|
|
|
p.resetInsertionMode()
|
|
|
}
|
|
|
+ case a.Template:
|
|
|
+ return inHeadIM(p)
|
|
|
}
|
|
|
case CommentToken:
|
|
|
p.addChild(&Node{
|
|
|
@@ -1650,6 +1796,61 @@ func inSelectInTableIM(p *parser) bool {
|
|
|
return inSelectIM(p)
|
|
|
}
|
|
|
|
|
|
+// Section 12.2.6.4.18.
|
|
|
+func inTemplateIM(p *parser) bool {
|
|
|
+ switch p.tok.Type {
|
|
|
+ case TextToken, CommentToken, DoctypeToken:
|
|
|
+ return inBodyIM(p)
|
|
|
+ case StartTagToken:
|
|
|
+ switch p.tok.DataAtom {
|
|
|
+ case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
|
|
|
+ return inHeadIM(p)
|
|
|
+ case a.Caption, a.Colgroup, a.Tbody, a.Tfoot, a.Thead:
|
|
|
+ p.templateStack.pop()
|
|
|
+ p.templateStack = append(p.templateStack, inTableIM)
|
|
|
+ p.im = inTableIM
|
|
|
+ return false
|
|
|
+ case a.Col:
|
|
|
+ p.templateStack.pop()
|
|
|
+ p.templateStack = append(p.templateStack, inColumnGroupIM)
|
|
|
+ p.im = inColumnGroupIM
|
|
|
+ return false
|
|
|
+ case a.Tr:
|
|
|
+ p.templateStack.pop()
|
|
|
+ p.templateStack = append(p.templateStack, inTableBodyIM)
|
|
|
+ p.im = inTableBodyIM
|
|
|
+ return false
|
|
|
+ case a.Td, a.Th:
|
|
|
+ p.templateStack.pop()
|
|
|
+ p.templateStack = append(p.templateStack, inRowIM)
|
|
|
+ p.im = inRowIM
|
|
|
+ return false
|
|
|
+ default:
|
|
|
+ p.templateStack.pop()
|
|
|
+ p.templateStack = append(p.templateStack, inBodyIM)
|
|
|
+ p.im = inBodyIM
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ case EndTagToken:
|
|
|
+ switch p.tok.DataAtom {
|
|
|
+ case a.Template:
|
|
|
+ return inHeadIM(p)
|
|
|
+ default:
|
|
|
+ // Ignore the token.
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if !p.oe.contains(a.Template) {
|
|
|
+ // Ignore the token.
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ p.popUntil(defaultScope, a.Template)
|
|
|
+ p.clearActiveFormattingElements()
|
|
|
+ p.templateStack.pop()
|
|
|
+ p.resetInsertionMode()
|
|
|
+ return false
|
|
|
+}
|
|
|
+
|
|
|
// Section 12.2.6.4.19.
|
|
|
func afterBodyIM(p *parser) bool {
|
|
|
switch p.tok.Type {
|
|
|
@@ -1720,6 +1921,11 @@ func inFramesetIM(p *parser) bool {
|
|
|
p.acknowledgeSelfClosingTag()
|
|
|
case a.Noframes:
|
|
|
return inHeadIM(p)
|
|
|
+ case a.Template:
|
|
|
+ // TODO: remove this divergence from the HTML5 spec.
|
|
|
+ //
|
|
|
+ // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
|
|
|
+ return inTemplateIM(p)
|
|
|
}
|
|
|
case EndTagToken:
|
|
|
switch p.tok.DataAtom {
|
|
|
@@ -2064,6 +2270,9 @@ func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
|
|
|
}
|
|
|
p.doc.AppendChild(root)
|
|
|
p.oe = nodeStack{root}
|
|
|
+ if context.DataAtom == a.Template {
|
|
|
+ p.templateStack = append(p.templateStack, inTemplateIM)
|
|
|
+ }
|
|
|
p.resetInsertionMode()
|
|
|
|
|
|
for n := context; n != nil; n = n.Parent {
|