github.com/vugu/vugu@v0.3.5/internal/htmlx/node.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package htmlx 6 7 import ( 8 "github.com/vugu/vugu/internal/htmlx/atom" 9 ) 10 11 // A NodeType is the type of a Node. 12 type NodeType uint32 13 14 const ( 15 ErrorNode NodeType = iota 16 TextNode 17 DocumentNode 18 ElementNode 19 CommentNode 20 DoctypeNode 21 scopeMarkerNode 22 ) 23 24 // Section 12.2.4.3 says "The markers are inserted when entering applet, 25 // object, marquee, template, td, th, and caption elements, and are used 26 // to prevent formatting from "leaking" into applet, object, marquee, 27 // template, td, th, and caption elements". 28 var scopeMarker = Node{Type: scopeMarkerNode} 29 30 // A Node consists of a NodeType and some Data (tag name for element nodes, 31 // content for text) and are part of a tree of Nodes. Element nodes may also 32 // have a Namespace and contain a slice of Attributes. Data is unescaped, so 33 // that it looks like "a<b" rather than "a<b". For element nodes, DataAtom 34 // is the atom for Data, or zero if Data is not a known tag name. 35 // 36 // An empty Namespace implies a "http://www.w3.org/1999/xhtml" namespace. 37 // Similarly, "math" is short for "http://www.w3.org/1998/Math/MathML", and 38 // "svg" is short for "http://www.w3.org/2000/svg". 39 type Node struct { 40 Parent, FirstChild, LastChild, PrevSibling, NextSibling *Node 41 42 Type NodeType 43 DataAtom atom.Atom 44 Data string 45 Namespace string 46 Attr []Attribute 47 48 Column int 49 Line int 50 } 51 52 // InsertBefore inserts newChild as a child of n, immediately before oldChild 53 // in the sequence of n's children. oldChild may be nil, in which case newChild 54 // is appended to the end of n's children. 55 // 56 // It will panic if newChild already has a parent or siblings. 57 func (n *Node) InsertBefore(newChild, oldChild *Node) { 58 if newChild.Parent != nil || newChild.PrevSibling != nil || newChild.NextSibling != nil { 59 panic("html: InsertBefore called for an attached child Node") 60 } 61 var prev, next *Node 62 if oldChild != nil { 63 prev, next = oldChild.PrevSibling, oldChild 64 } else { 65 prev = n.LastChild 66 } 67 if prev != nil { 68 prev.NextSibling = newChild 69 } else { 70 n.FirstChild = newChild 71 } 72 if next != nil { 73 next.PrevSibling = newChild 74 } else { 75 n.LastChild = newChild 76 } 77 newChild.Parent = n 78 newChild.PrevSibling = prev 79 newChild.NextSibling = next 80 } 81 82 // AppendChild adds a node c as a child of n. 83 // 84 // It will panic if c already has a parent or siblings. 85 func (n *Node) AppendChild(c *Node) { 86 if c.Parent != nil || c.PrevSibling != nil || c.NextSibling != nil { 87 panic("html: AppendChild called for an attached child Node") 88 } 89 last := n.LastChild 90 if last != nil { 91 last.NextSibling = c 92 } else { 93 n.FirstChild = c 94 } 95 n.LastChild = c 96 c.Parent = n 97 c.PrevSibling = last 98 } 99 100 // RemoveChild removes a node c that is a child of n. Afterwards, c will have 101 // no parent and no siblings. 102 // 103 // It will panic if c's parent is not n. 104 func (n *Node) RemoveChild(c *Node) { 105 if c.Parent != n { 106 panic("html: RemoveChild called for a non-child Node") 107 } 108 if n.FirstChild == c { 109 n.FirstChild = c.NextSibling 110 } 111 if c.NextSibling != nil { 112 c.NextSibling.PrevSibling = c.PrevSibling 113 } 114 if n.LastChild == c { 115 n.LastChild = c.PrevSibling 116 } 117 if c.PrevSibling != nil { 118 c.PrevSibling.NextSibling = c.NextSibling 119 } 120 c.Parent = nil 121 c.PrevSibling = nil 122 c.NextSibling = nil 123 } 124 125 // reparentChildren reparents all of src's child nodes to dst. 126 func reparentChildren(dst, src *Node) { 127 for { 128 child := src.FirstChild 129 if child == nil { 130 break 131 } 132 src.RemoveChild(child) 133 dst.AppendChild(child) 134 } 135 } 136 137 // clone returns a new node with the same type, data and attributes. 138 // The clone has no parent, no siblings and no children. 139 func (n *Node) clone() *Node { 140 m := &Node{ 141 Type: n.Type, 142 DataAtom: n.DataAtom, 143 Data: n.Data, 144 Attr: make([]Attribute, len(n.Attr)), 145 } 146 copy(m.Attr, n.Attr) 147 return m 148 } 149 150 // nodeStack is a stack of nodes. 151 type nodeStack []*Node 152 153 // pop pops the stack. It will panic if s is empty. 154 func (s *nodeStack) pop() *Node { 155 i := len(*s) 156 n := (*s)[i-1] 157 *s = (*s)[:i-1] 158 return n 159 } 160 161 // top returns the most recently pushed node, or nil if s is empty. 162 func (s *nodeStack) top() *Node { 163 if i := len(*s); i > 0 { 164 return (*s)[i-1] 165 } 166 return nil 167 } 168 169 // index returns the index of the top-most occurrence of n in the stack, or -1 170 // if n is not present. 171 func (s *nodeStack) index(n *Node) int { 172 for i := len(*s) - 1; i >= 0; i-- { 173 if (*s)[i] == n { 174 return i 175 } 176 } 177 return -1 178 } 179 180 // contains returns whether a is within s. 181 func (s *nodeStack) contains(a atom.Atom) bool { 182 for _, n := range *s { 183 if n.DataAtom == a && n.Namespace == "" { 184 return true 185 } 186 } 187 return false 188 } 189 190 // insert inserts a node at the given index. 191 func (s *nodeStack) insert(i int, n *Node) { 192 (*s) = append(*s, nil) 193 copy((*s)[i+1:], (*s)[i:]) 194 (*s)[i] = n 195 } 196 197 // remove removes a node from the stack. It is a no-op if n is not present. 198 func (s *nodeStack) remove(n *Node) { 199 i := s.index(n) 200 if i == -1 { 201 return 202 } 203 copy((*s)[i:], (*s)[i+1:]) 204 j := len(*s) - 1 205 (*s)[j] = nil 206 *s = (*s)[:j] 207 } 208 209 type insertionModeStack []insertionMode 210 211 func (s *insertionModeStack) pop() (im insertionMode) { 212 i := len(*s) 213 im = (*s)[i-1] 214 *s = (*s)[:i-1] 215 return im 216 } 217 218 func (s *insertionModeStack) top() insertionMode { 219 if i := len(*s); i > 0 { 220 return (*s)[i-1] 221 } 222 return nil 223 }