The reconcile package is used for DOM reconcilation in Isomorphic Go web applications.

node.go 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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. package html
  5. import (
  6. "golang.org/x/net/html/atom"
  7. )
  8. // A NodeType is the type of a Node.
  9. type NodeType uint32
  10. const (
  11. ErrorNode NodeType = iota
  12. TextNode
  13. DocumentNode
  14. ElementNode
  15. CommentNode
  16. DoctypeNode
  17. scopeMarkerNode
  18. )
  19. // Section 12.2.3.3 says "scope markers are inserted when entering applet
  20. // elements, buttons, object elements, marquees, table cells, and table
  21. // captions, and are used to prevent formatting from 'leaking'".
  22. var scopeMarker = Node{Type: scopeMarkerNode}
  23. // A Node consists of a NodeType and some Data (tag name for element nodes,
  24. // content for text) and are part of a tree of Nodes. Element nodes may also
  25. // have a Namespace and contain a slice of Attributes. Data is unescaped, so
  26. // that it looks like "a<b" rather than "a&lt;b". For element nodes, DataAtom
  27. // is the atom for Data, or zero if Data is not a known tag name.
  28. //
  29. // An empty Namespace implies a "http://www.w3.org/1999/xhtml" namespace.
  30. // Similarly, "math" is short for "http://www.w3.org/1998/Math/MathML", and
  31. // "svg" is short for "http://www.w3.org/2000/svg".
  32. type Node struct {
  33. Parent, FirstChild, LastChild, PrevSibling, NextSibling *Node
  34. Type NodeType
  35. DataAtom atom.Atom
  36. Data string
  37. Namespace string
  38. Attr []Attribute
  39. }
  40. // InsertBefore inserts newChild as a child of n, immediately before oldChild
  41. // in the sequence of n's children. oldChild may be nil, in which case newChild
  42. // is appended to the end of n's children.
  43. //
  44. // It will panic if newChild already has a parent or siblings.
  45. func (n *Node) InsertBefore(newChild, oldChild *Node) {
  46. if newChild.Parent != nil || newChild.PrevSibling != nil || newChild.NextSibling != nil {
  47. panic("html: InsertBefore called for an attached child Node")
  48. }
  49. var prev, next *Node
  50. if oldChild != nil {
  51. prev, next = oldChild.PrevSibling, oldChild
  52. } else {
  53. prev = n.LastChild
  54. }
  55. if prev != nil {
  56. prev.NextSibling = newChild
  57. } else {
  58. n.FirstChild = newChild
  59. }
  60. if next != nil {
  61. next.PrevSibling = newChild
  62. } else {
  63. n.LastChild = newChild
  64. }
  65. newChild.Parent = n
  66. newChild.PrevSibling = prev
  67. newChild.NextSibling = next
  68. }
  69. // AppendChild adds a node c as a child of n.
  70. //
  71. // It will panic if c already has a parent or siblings.
  72. func (n *Node) AppendChild(c *Node) {
  73. if c.Parent != nil || c.PrevSibling != nil || c.NextSibling != nil {
  74. panic("html: AppendChild called for an attached child Node")
  75. }
  76. last := n.LastChild
  77. if last != nil {
  78. last.NextSibling = c
  79. } else {
  80. n.FirstChild = c
  81. }
  82. n.LastChild = c
  83. c.Parent = n
  84. c.PrevSibling = last
  85. }
  86. // RemoveChild removes a node c that is a child of n. Afterwards, c will have
  87. // no parent and no siblings.
  88. //
  89. // It will panic if c's parent is not n.
  90. func (n *Node) RemoveChild(c *Node) {
  91. if c.Parent != n {
  92. panic("html: RemoveChild called for a non-child Node")
  93. }
  94. if n.FirstChild == c {
  95. n.FirstChild = c.NextSibling
  96. }
  97. if c.NextSibling != nil {
  98. c.NextSibling.PrevSibling = c.PrevSibling
  99. }
  100. if n.LastChild == c {
  101. n.LastChild = c.PrevSibling
  102. }
  103. if c.PrevSibling != nil {
  104. c.PrevSibling.NextSibling = c.NextSibling
  105. }
  106. c.Parent = nil
  107. c.PrevSibling = nil
  108. c.NextSibling = nil
  109. }
  110. // reparentChildren reparents all of src's child nodes to dst.
  111. func reparentChildren(dst, src *Node) {
  112. for {
  113. child := src.FirstChild
  114. if child == nil {
  115. break
  116. }
  117. src.RemoveChild(child)
  118. dst.AppendChild(child)
  119. }
  120. }
  121. // clone returns a new node with the same type, data and attributes.
  122. // The clone has no parent, no siblings and no children.
  123. func (n *Node) clone() *Node {
  124. m := &Node{
  125. Type: n.Type,
  126. DataAtom: n.DataAtom,
  127. Data: n.Data,
  128. Attr: make([]Attribute, len(n.Attr)),
  129. }
  130. copy(m.Attr, n.Attr)
  131. return m
  132. }
  133. // nodeStack is a stack of nodes.
  134. type nodeStack []*Node
  135. // pop pops the stack. It will panic if s is empty.
  136. func (s *nodeStack) pop() *Node {
  137. i := len(*s)
  138. n := (*s)[i-1]
  139. *s = (*s)[:i-1]
  140. return n
  141. }
  142. // top returns the most recently pushed node, or nil if s is empty.
  143. func (s *nodeStack) top() *Node {
  144. if i := len(*s); i > 0 {
  145. return (*s)[i-1]
  146. }
  147. return nil
  148. }
  149. // index returns the index of the top-most occurrence of n in the stack, or -1
  150. // if n is not present.
  151. func (s *nodeStack) index(n *Node) int {
  152. for i := len(*s) - 1; i >= 0; i-- {
  153. if (*s)[i] == n {
  154. return i
  155. }
  156. }
  157. return -1
  158. }
  159. // insert inserts a node at the given index.
  160. func (s *nodeStack) insert(i int, n *Node) {
  161. (*s) = append(*s, nil)
  162. copy((*s)[i+1:], (*s)[i:])
  163. (*s)[i] = n
  164. }
  165. // remove removes a node from the stack. It is a no-op if n is not present.
  166. func (s *nodeStack) remove(n *Node) {
  167. i := s.index(n)
  168. if i == -1 {
  169. return
  170. }
  171. copy((*s)[i:], (*s)[i+1:])
  172. j := len(*s) - 1
  173. (*s)[j] = nil
  174. *s = (*s)[:j]
  175. }