mirror of https://github.com/gogits/gogs.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
193 lines
4.7 KiB
193 lines
4.7 KiB
// Copyright 2011 The Go Authors. All rights reserved. |
|
// Use of this source code is governed by a BSD-style |
|
// license that can be found in the LICENSE file. |
|
|
|
package html |
|
|
|
import ( |
|
"golang.org/x/net/html/atom" |
|
) |
|
|
|
// A NodeType is the type of a Node. |
|
type NodeType uint32 |
|
|
|
const ( |
|
ErrorNode NodeType = iota |
|
TextNode |
|
DocumentNode |
|
ElementNode |
|
CommentNode |
|
DoctypeNode |
|
scopeMarkerNode |
|
) |
|
|
|
// Section 12.2.3.3 says "scope markers are inserted when entering applet |
|
// elements, buttons, object elements, marquees, table cells, and table |
|
// captions, and are used to prevent formatting from 'leaking'". |
|
var scopeMarker = Node{Type: scopeMarkerNode} |
|
|
|
// A Node consists of a NodeType and some Data (tag name for element nodes, |
|
// content for text) and are part of a tree of Nodes. Element nodes may also |
|
// have a Namespace and contain a slice of Attributes. Data is unescaped, so |
|
// that it looks like "a<b" rather than "a<b". For element nodes, DataAtom |
|
// is the atom for Data, or zero if Data is not a known tag name. |
|
// |
|
// An empty Namespace implies a "http://www.w3.org/1999/xhtml" namespace. |
|
// Similarly, "math" is short for "http://www.w3.org/1998/Math/MathML", and |
|
// "svg" is short for "http://www.w3.org/2000/svg". |
|
type Node struct { |
|
Parent, FirstChild, LastChild, PrevSibling, NextSibling *Node |
|
|
|
Type NodeType |
|
DataAtom atom.Atom |
|
Data string |
|
Namespace string |
|
Attr []Attribute |
|
} |
|
|
|
// InsertBefore inserts newChild as a child of n, immediately before oldChild |
|
// in the sequence of n's children. oldChild may be nil, in which case newChild |
|
// is appended to the end of n's children. |
|
// |
|
// It will panic if newChild already has a parent or siblings. |
|
func (n *Node) InsertBefore(newChild, oldChild *Node) { |
|
if newChild.Parent != nil || newChild.PrevSibling != nil || newChild.NextSibling != nil { |
|
panic("html: InsertBefore called for an attached child Node") |
|
} |
|
var prev, next *Node |
|
if oldChild != nil { |
|
prev, next = oldChild.PrevSibling, oldChild |
|
} else { |
|
prev = n.LastChild |
|
} |
|
if prev != nil { |
|
prev.NextSibling = newChild |
|
} else { |
|
n.FirstChild = newChild |
|
} |
|
if next != nil { |
|
next.PrevSibling = newChild |
|
} else { |
|
n.LastChild = newChild |
|
} |
|
newChild.Parent = n |
|
newChild.PrevSibling = prev |
|
newChild.NextSibling = next |
|
} |
|
|
|
// AppendChild adds a node c as a child of n. |
|
// |
|
// It will panic if c already has a parent or siblings. |
|
func (n *Node) AppendChild(c *Node) { |
|
if c.Parent != nil || c.PrevSibling != nil || c.NextSibling != nil { |
|
panic("html: AppendChild called for an attached child Node") |
|
} |
|
last := n.LastChild |
|
if last != nil { |
|
last.NextSibling = c |
|
} else { |
|
n.FirstChild = c |
|
} |
|
n.LastChild = c |
|
c.Parent = n |
|
c.PrevSibling = last |
|
} |
|
|
|
// RemoveChild removes a node c that is a child of n. Afterwards, c will have |
|
// no parent and no siblings. |
|
// |
|
// It will panic if c's parent is not n. |
|
func (n *Node) RemoveChild(c *Node) { |
|
if c.Parent != n { |
|
panic("html: RemoveChild called for a non-child Node") |
|
} |
|
if n.FirstChild == c { |
|
n.FirstChild = c.NextSibling |
|
} |
|
if c.NextSibling != nil { |
|
c.NextSibling.PrevSibling = c.PrevSibling |
|
} |
|
if n.LastChild == c { |
|
n.LastChild = c.PrevSibling |
|
} |
|
if c.PrevSibling != nil { |
|
c.PrevSibling.NextSibling = c.NextSibling |
|
} |
|
c.Parent = nil |
|
c.PrevSibling = nil |
|
c.NextSibling = nil |
|
} |
|
|
|
// reparentChildren reparents all of src's child nodes to dst. |
|
func reparentChildren(dst, src *Node) { |
|
for { |
|
child := src.FirstChild |
|
if child == nil { |
|
break |
|
} |
|
src.RemoveChild(child) |
|
dst.AppendChild(child) |
|
} |
|
} |
|
|
|
// clone returns a new node with the same type, data and attributes. |
|
// The clone has no parent, no siblings and no children. |
|
func (n *Node) clone() *Node { |
|
m := &Node{ |
|
Type: n.Type, |
|
DataAtom: n.DataAtom, |
|
Data: n.Data, |
|
Attr: make([]Attribute, len(n.Attr)), |
|
} |
|
copy(m.Attr, n.Attr) |
|
return m |
|
} |
|
|
|
// nodeStack is a stack of nodes. |
|
type nodeStack []*Node |
|
|
|
// pop pops the stack. It will panic if s is empty. |
|
func (s *nodeStack) pop() *Node { |
|
i := len(*s) |
|
n := (*s)[i-1] |
|
*s = (*s)[:i-1] |
|
return n |
|
} |
|
|
|
// top returns the most recently pushed node, or nil if s is empty. |
|
func (s *nodeStack) top() *Node { |
|
if i := len(*s); i > 0 { |
|
return (*s)[i-1] |
|
} |
|
return nil |
|
} |
|
|
|
// index returns the index of the top-most occurrence of n in the stack, or -1 |
|
// if n is not present. |
|
func (s *nodeStack) index(n *Node) int { |
|
for i := len(*s) - 1; i >= 0; i-- { |
|
if (*s)[i] == n { |
|
return i |
|
} |
|
} |
|
return -1 |
|
} |
|
|
|
// insert inserts a node at the given index. |
|
func (s *nodeStack) insert(i int, n *Node) { |
|
(*s) = append(*s, nil) |
|
copy((*s)[i+1:], (*s)[i:]) |
|
(*s)[i] = n |
|
} |
|
|
|
// remove removes a node from the stack. It is a no-op if n is not present. |
|
func (s *nodeStack) remove(n *Node) { |
|
i := s.index(n) |
|
if i == -1 { |
|
return |
|
} |
|
copy((*s)[i:], (*s)[i+1:]) |
|
j := len(*s) - 1 |
|
(*s)[j] = nil |
|
*s = (*s)[:j] |
|
}
|
|
|