mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	* Show commit status icon in commits table * Add comments * Fix icons * Few more places where commit table is displayed * Change integration test to use goquery for parsing html * Add integration tests for commit table and status icons * Fix status to return lates status correctly on all databases * Rewrote lates commit status selects
		
			
				
	
	
		
			699 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			699 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package goquery
 | 
						|
 | 
						|
import "golang.org/x/net/html"
 | 
						|
 | 
						|
type siblingType int
 | 
						|
 | 
						|
// Sibling type, used internally when iterating over children at the same
 | 
						|
// level (siblings) to specify which nodes are requested.
 | 
						|
const (
 | 
						|
	siblingPrevUntil siblingType = iota - 3
 | 
						|
	siblingPrevAll
 | 
						|
	siblingPrev
 | 
						|
	siblingAll
 | 
						|
	siblingNext
 | 
						|
	siblingNextAll
 | 
						|
	siblingNextUntil
 | 
						|
	siblingAllIncludingNonElements
 | 
						|
)
 | 
						|
 | 
						|
// Find gets the descendants of each element in the current set of matched
 | 
						|
// elements, filtered by a selector. It returns a new Selection object
 | 
						|
// containing these matched elements.
 | 
						|
func (s *Selection) Find(selector string) *Selection {
 | 
						|
	return pushStack(s, findWithMatcher(s.Nodes, compileMatcher(selector)))
 | 
						|
}
 | 
						|
 | 
						|
// FindMatcher gets the descendants of each element in the current set of matched
 | 
						|
// elements, filtered by the matcher. It returns a new Selection object
 | 
						|
// containing these matched elements.
 | 
						|
func (s *Selection) FindMatcher(m Matcher) *Selection {
 | 
						|
	return pushStack(s, findWithMatcher(s.Nodes, m))
 | 
						|
}
 | 
						|
 | 
						|
// FindSelection gets the descendants of each element in the current
 | 
						|
// Selection, filtered by a Selection. It returns a new Selection object
 | 
						|
// containing these matched elements.
 | 
						|
func (s *Selection) FindSelection(sel *Selection) *Selection {
 | 
						|
	if sel == nil {
 | 
						|
		return pushStack(s, nil)
 | 
						|
	}
 | 
						|
	return s.FindNodes(sel.Nodes...)
 | 
						|
}
 | 
						|
 | 
						|
// FindNodes gets the descendants of each element in the current
 | 
						|
// Selection, filtered by some nodes. It returns a new Selection object
 | 
						|
// containing these matched elements.
 | 
						|
func (s *Selection) FindNodes(nodes ...*html.Node) *Selection {
 | 
						|
	return pushStack(s, mapNodes(nodes, func(i int, n *html.Node) []*html.Node {
 | 
						|
		if sliceContains(s.Nodes, n) {
 | 
						|
			return []*html.Node{n}
 | 
						|
		}
 | 
						|
		return nil
 | 
						|
	}))
 | 
						|
}
 | 
						|
 | 
						|
// Contents gets the children of each element in the Selection,
 | 
						|
// including text and comment nodes. It returns a new Selection object
 | 
						|
// containing these elements.
 | 
						|
func (s *Selection) Contents() *Selection {
 | 
						|
	return pushStack(s, getChildrenNodes(s.Nodes, siblingAllIncludingNonElements))
 | 
						|
}
 | 
						|
 | 
						|
// ContentsFiltered gets the children of each element in the Selection,
 | 
						|
// filtered by the specified selector. It returns a new Selection
 | 
						|
// object containing these elements. Since selectors only act on Element nodes,
 | 
						|
// this function is an alias to ChildrenFiltered unless the selector is empty,
 | 
						|
// in which case it is an alias to Contents.
 | 
						|
func (s *Selection) ContentsFiltered(selector string) *Selection {
 | 
						|
	if selector != "" {
 | 
						|
		return s.ChildrenFiltered(selector)
 | 
						|
	}
 | 
						|
	return s.Contents()
 | 
						|
}
 | 
						|
 | 
						|
// ContentsMatcher gets the children of each element in the Selection,
 | 
						|
// filtered by the specified matcher. It returns a new Selection
 | 
						|
// object containing these elements. Since matchers only act on Element nodes,
 | 
						|
// this function is an alias to ChildrenMatcher.
 | 
						|
func (s *Selection) ContentsMatcher(m Matcher) *Selection {
 | 
						|
	return s.ChildrenMatcher(m)
 | 
						|
}
 | 
						|
 | 
						|
// Children gets the child elements of each element in the Selection.
 | 
						|
// It returns a new Selection object containing these elements.
 | 
						|
func (s *Selection) Children() *Selection {
 | 
						|
	return pushStack(s, getChildrenNodes(s.Nodes, siblingAll))
 | 
						|
}
 | 
						|
 | 
						|
// ChildrenFiltered gets the child elements of each element in the Selection,
 | 
						|
// filtered by the specified selector. It returns a new
 | 
						|
// Selection object containing these elements.
 | 
						|
func (s *Selection) ChildrenFiltered(selector string) *Selection {
 | 
						|
	return filterAndPush(s, getChildrenNodes(s.Nodes, siblingAll), compileMatcher(selector))
 | 
						|
}
 | 
						|
 | 
						|
// ChildrenMatcher gets the child elements of each element in the Selection,
 | 
						|
// filtered by the specified matcher. It returns a new
 | 
						|
// Selection object containing these elements.
 | 
						|
func (s *Selection) ChildrenMatcher(m Matcher) *Selection {
 | 
						|
	return filterAndPush(s, getChildrenNodes(s.Nodes, siblingAll), m)
 | 
						|
}
 | 
						|
 | 
						|
// Parent gets the parent of each element in the Selection. It returns a
 | 
						|
// new Selection object containing the matched elements.
 | 
						|
func (s *Selection) Parent() *Selection {
 | 
						|
	return pushStack(s, getParentNodes(s.Nodes))
 | 
						|
}
 | 
						|
 | 
						|
// ParentFiltered gets the parent of each element in the Selection filtered by a
 | 
						|
// selector. It returns a new Selection object containing the matched elements.
 | 
						|
func (s *Selection) ParentFiltered(selector string) *Selection {
 | 
						|
	return filterAndPush(s, getParentNodes(s.Nodes), compileMatcher(selector))
 | 
						|
}
 | 
						|
 | 
						|
// ParentMatcher gets the parent of each element in the Selection filtered by a
 | 
						|
// matcher. It returns a new Selection object containing the matched elements.
 | 
						|
func (s *Selection) ParentMatcher(m Matcher) *Selection {
 | 
						|
	return filterAndPush(s, getParentNodes(s.Nodes), m)
 | 
						|
}
 | 
						|
 | 
						|
// Closest gets the first element that matches the selector by testing the
 | 
						|
// element itself and traversing up through its ancestors in the DOM tree.
 | 
						|
func (s *Selection) Closest(selector string) *Selection {
 | 
						|
	cs := compileMatcher(selector)
 | 
						|
	return s.ClosestMatcher(cs)
 | 
						|
}
 | 
						|
 | 
						|
// ClosestMatcher gets the first element that matches the matcher by testing the
 | 
						|
// element itself and traversing up through its ancestors in the DOM tree.
 | 
						|
func (s *Selection) ClosestMatcher(m Matcher) *Selection {
 | 
						|
	return pushStack(s, mapNodes(s.Nodes, func(i int, n *html.Node) []*html.Node {
 | 
						|
		// For each node in the selection, test the node itself, then each parent
 | 
						|
		// until a match is found.
 | 
						|
		for ; n != nil; n = n.Parent {
 | 
						|
			if m.Match(n) {
 | 
						|
				return []*html.Node{n}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return nil
 | 
						|
	}))
 | 
						|
}
 | 
						|
 | 
						|
// ClosestNodes gets the first element that matches one of the nodes by testing the
 | 
						|
// element itself and traversing up through its ancestors in the DOM tree.
 | 
						|
func (s *Selection) ClosestNodes(nodes ...*html.Node) *Selection {
 | 
						|
	set := make(map[*html.Node]bool)
 | 
						|
	for _, n := range nodes {
 | 
						|
		set[n] = true
 | 
						|
	}
 | 
						|
	return pushStack(s, mapNodes(s.Nodes, func(i int, n *html.Node) []*html.Node {
 | 
						|
		// For each node in the selection, test the node itself, then each parent
 | 
						|
		// until a match is found.
 | 
						|
		for ; n != nil; n = n.Parent {
 | 
						|
			if set[n] {
 | 
						|
				return []*html.Node{n}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return nil
 | 
						|
	}))
 | 
						|
}
 | 
						|
 | 
						|
// ClosestSelection gets the first element that matches one of the nodes in the
 | 
						|
// Selection by testing the element itself and traversing up through its ancestors
 | 
						|
// in the DOM tree.
 | 
						|
func (s *Selection) ClosestSelection(sel *Selection) *Selection {
 | 
						|
	if sel == nil {
 | 
						|
		return pushStack(s, nil)
 | 
						|
	}
 | 
						|
	return s.ClosestNodes(sel.Nodes...)
 | 
						|
}
 | 
						|
 | 
						|
// Parents gets the ancestors of each element in the current Selection. It
 | 
						|
// returns a new Selection object with the matched elements.
 | 
						|
func (s *Selection) Parents() *Selection {
 | 
						|
	return pushStack(s, getParentsNodes(s.Nodes, nil, nil))
 | 
						|
}
 | 
						|
 | 
						|
// ParentsFiltered gets the ancestors of each element in the current
 | 
						|
// Selection. It returns a new Selection object with the matched elements.
 | 
						|
func (s *Selection) ParentsFiltered(selector string) *Selection {
 | 
						|
	return filterAndPush(s, getParentsNodes(s.Nodes, nil, nil), compileMatcher(selector))
 | 
						|
}
 | 
						|
 | 
						|
// ParentsMatcher gets the ancestors of each element in the current
 | 
						|
// Selection. It returns a new Selection object with the matched elements.
 | 
						|
func (s *Selection) ParentsMatcher(m Matcher) *Selection {
 | 
						|
	return filterAndPush(s, getParentsNodes(s.Nodes, nil, nil), m)
 | 
						|
}
 | 
						|
 | 
						|
// ParentsUntil gets the ancestors of each element in the Selection, up to but
 | 
						|
// not including the element matched by the selector. It returns a new Selection
 | 
						|
// object containing the matched elements.
 | 
						|
func (s *Selection) ParentsUntil(selector string) *Selection {
 | 
						|
	return pushStack(s, getParentsNodes(s.Nodes, compileMatcher(selector), nil))
 | 
						|
}
 | 
						|
 | 
						|
// ParentsUntilMatcher gets the ancestors of each element in the Selection, up to but
 | 
						|
// not including the element matched by the matcher. It returns a new Selection
 | 
						|
// object containing the matched elements.
 | 
						|
func (s *Selection) ParentsUntilMatcher(m Matcher) *Selection {
 | 
						|
	return pushStack(s, getParentsNodes(s.Nodes, m, nil))
 | 
						|
}
 | 
						|
 | 
						|
// ParentsUntilSelection gets the ancestors of each element in the Selection,
 | 
						|
// up to but not including the elements in the specified Selection. It returns a
 | 
						|
// new Selection object containing the matched elements.
 | 
						|
func (s *Selection) ParentsUntilSelection(sel *Selection) *Selection {
 | 
						|
	if sel == nil {
 | 
						|
		return s.Parents()
 | 
						|
	}
 | 
						|
	return s.ParentsUntilNodes(sel.Nodes...)
 | 
						|
}
 | 
						|
 | 
						|
// ParentsUntilNodes gets the ancestors of each element in the Selection,
 | 
						|
// up to but not including the specified nodes. It returns a
 | 
						|
// new Selection object containing the matched elements.
 | 
						|
func (s *Selection) ParentsUntilNodes(nodes ...*html.Node) *Selection {
 | 
						|
	return pushStack(s, getParentsNodes(s.Nodes, nil, nodes))
 | 
						|
}
 | 
						|
 | 
						|
// ParentsFilteredUntil is like ParentsUntil, with the option to filter the
 | 
						|
// results based on a selector string. It returns a new Selection
 | 
						|
// object containing the matched elements.
 | 
						|
func (s *Selection) ParentsFilteredUntil(filterSelector, untilSelector string) *Selection {
 | 
						|
	return filterAndPush(s, getParentsNodes(s.Nodes, compileMatcher(untilSelector), nil), compileMatcher(filterSelector))
 | 
						|
}
 | 
						|
 | 
						|
// ParentsFilteredUntilMatcher is like ParentsUntilMatcher, with the option to filter the
 | 
						|
// results based on a matcher. It returns a new Selection object containing the matched elements.
 | 
						|
func (s *Selection) ParentsFilteredUntilMatcher(filter, until Matcher) *Selection {
 | 
						|
	return filterAndPush(s, getParentsNodes(s.Nodes, until, nil), filter)
 | 
						|
}
 | 
						|
 | 
						|
// ParentsFilteredUntilSelection is like ParentsUntilSelection, with the
 | 
						|
// option to filter the results based on a selector string. It returns a new
 | 
						|
// Selection object containing the matched elements.
 | 
						|
func (s *Selection) ParentsFilteredUntilSelection(filterSelector string, sel *Selection) *Selection {
 | 
						|
	return s.ParentsMatcherUntilSelection(compileMatcher(filterSelector), sel)
 | 
						|
}
 | 
						|
 | 
						|
// ParentsMatcherUntilSelection is like ParentsUntilSelection, with the
 | 
						|
// option to filter the results based on a matcher. It returns a new
 | 
						|
// Selection object containing the matched elements.
 | 
						|
func (s *Selection) ParentsMatcherUntilSelection(filter Matcher, sel *Selection) *Selection {
 | 
						|
	if sel == nil {
 | 
						|
		return s.ParentsMatcher(filter)
 | 
						|
	}
 | 
						|
	return s.ParentsMatcherUntilNodes(filter, sel.Nodes...)
 | 
						|
}
 | 
						|
 | 
						|
// ParentsFilteredUntilNodes is like ParentsUntilNodes, with the
 | 
						|
// option to filter the results based on a selector string. It returns a new
 | 
						|
// Selection object containing the matched elements.
 | 
						|
func (s *Selection) ParentsFilteredUntilNodes(filterSelector string, nodes ...*html.Node) *Selection {
 | 
						|
	return filterAndPush(s, getParentsNodes(s.Nodes, nil, nodes), compileMatcher(filterSelector))
 | 
						|
}
 | 
						|
 | 
						|
// ParentsMatcherUntilNodes is like ParentsUntilNodes, with the
 | 
						|
// option to filter the results based on a matcher. It returns a new
 | 
						|
// Selection object containing the matched elements.
 | 
						|
func (s *Selection) ParentsMatcherUntilNodes(filter Matcher, nodes ...*html.Node) *Selection {
 | 
						|
	return filterAndPush(s, getParentsNodes(s.Nodes, nil, nodes), filter)
 | 
						|
}
 | 
						|
 | 
						|
// Siblings gets the siblings of each element in the Selection. It returns
 | 
						|
// a new Selection object containing the matched elements.
 | 
						|
func (s *Selection) Siblings() *Selection {
 | 
						|
	return pushStack(s, getSiblingNodes(s.Nodes, siblingAll, nil, nil))
 | 
						|
}
 | 
						|
 | 
						|
// SiblingsFiltered gets the siblings of each element in the Selection
 | 
						|
// filtered by a selector. It returns a new Selection object containing the
 | 
						|
// matched elements.
 | 
						|
func (s *Selection) SiblingsFiltered(selector string) *Selection {
 | 
						|
	return filterAndPush(s, getSiblingNodes(s.Nodes, siblingAll, nil, nil), compileMatcher(selector))
 | 
						|
}
 | 
						|
 | 
						|
// SiblingsMatcher gets the siblings of each element in the Selection
 | 
						|
// filtered by a matcher. It returns a new Selection object containing the
 | 
						|
// matched elements.
 | 
						|
func (s *Selection) SiblingsMatcher(m Matcher) *Selection {
 | 
						|
	return filterAndPush(s, getSiblingNodes(s.Nodes, siblingAll, nil, nil), m)
 | 
						|
}
 | 
						|
 | 
						|
// Next gets the immediately following sibling of each element in the
 | 
						|
// Selection. It returns a new Selection object containing the matched elements.
 | 
						|
func (s *Selection) Next() *Selection {
 | 
						|
	return pushStack(s, getSiblingNodes(s.Nodes, siblingNext, nil, nil))
 | 
						|
}
 | 
						|
 | 
						|
// NextFiltered gets the immediately following sibling of each element in the
 | 
						|
// Selection filtered by a selector. It returns a new Selection object
 | 
						|
// containing the matched elements.
 | 
						|
func (s *Selection) NextFiltered(selector string) *Selection {
 | 
						|
	return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNext, nil, nil), compileMatcher(selector))
 | 
						|
}
 | 
						|
 | 
						|
// NextMatcher gets the immediately following sibling of each element in the
 | 
						|
// Selection filtered by a matcher. It returns a new Selection object
 | 
						|
// containing the matched elements.
 | 
						|
func (s *Selection) NextMatcher(m Matcher) *Selection {
 | 
						|
	return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNext, nil, nil), m)
 | 
						|
}
 | 
						|
 | 
						|
// NextAll gets all the following siblings of each element in the
 | 
						|
// Selection. It returns a new Selection object containing the matched elements.
 | 
						|
func (s *Selection) NextAll() *Selection {
 | 
						|
	return pushStack(s, getSiblingNodes(s.Nodes, siblingNextAll, nil, nil))
 | 
						|
}
 | 
						|
 | 
						|
// NextAllFiltered gets all the following siblings of each element in the
 | 
						|
// Selection filtered by a selector. It returns a new Selection object
 | 
						|
// containing the matched elements.
 | 
						|
func (s *Selection) NextAllFiltered(selector string) *Selection {
 | 
						|
	return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextAll, nil, nil), compileMatcher(selector))
 | 
						|
}
 | 
						|
 | 
						|
// NextAllMatcher gets all the following siblings of each element in the
 | 
						|
// Selection filtered by a matcher. It returns a new Selection object
 | 
						|
// containing the matched elements.
 | 
						|
func (s *Selection) NextAllMatcher(m Matcher) *Selection {
 | 
						|
	return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextAll, nil, nil), m)
 | 
						|
}
 | 
						|
 | 
						|
// Prev gets the immediately preceding sibling of each element in the
 | 
						|
// Selection. It returns a new Selection object containing the matched elements.
 | 
						|
func (s *Selection) Prev() *Selection {
 | 
						|
	return pushStack(s, getSiblingNodes(s.Nodes, siblingPrev, nil, nil))
 | 
						|
}
 | 
						|
 | 
						|
// PrevFiltered gets the immediately preceding sibling of each element in the
 | 
						|
// Selection filtered by a selector. It returns a new Selection object
 | 
						|
// containing the matched elements.
 | 
						|
func (s *Selection) PrevFiltered(selector string) *Selection {
 | 
						|
	return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrev, nil, nil), compileMatcher(selector))
 | 
						|
}
 | 
						|
 | 
						|
// PrevMatcher gets the immediately preceding sibling of each element in the
 | 
						|
// Selection filtered by a matcher. It returns a new Selection object
 | 
						|
// containing the matched elements.
 | 
						|
func (s *Selection) PrevMatcher(m Matcher) *Selection {
 | 
						|
	return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrev, nil, nil), m)
 | 
						|
}
 | 
						|
 | 
						|
// PrevAll gets all the preceding siblings of each element in the
 | 
						|
// Selection. It returns a new Selection object containing the matched elements.
 | 
						|
func (s *Selection) PrevAll() *Selection {
 | 
						|
	return pushStack(s, getSiblingNodes(s.Nodes, siblingPrevAll, nil, nil))
 | 
						|
}
 | 
						|
 | 
						|
// PrevAllFiltered gets all the preceding siblings of each element in the
 | 
						|
// Selection filtered by a selector. It returns a new Selection object
 | 
						|
// containing the matched elements.
 | 
						|
func (s *Selection) PrevAllFiltered(selector string) *Selection {
 | 
						|
	return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevAll, nil, nil), compileMatcher(selector))
 | 
						|
}
 | 
						|
 | 
						|
// PrevAllMatcher gets all the preceding siblings of each element in the
 | 
						|
// Selection filtered by a matcher. It returns a new Selection object
 | 
						|
// containing the matched elements.
 | 
						|
func (s *Selection) PrevAllMatcher(m Matcher) *Selection {
 | 
						|
	return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevAll, nil, nil), m)
 | 
						|
}
 | 
						|
 | 
						|
// NextUntil gets all following siblings of each element up to but not
 | 
						|
// including the element matched by the selector. It returns a new Selection
 | 
						|
// object containing the matched elements.
 | 
						|
func (s *Selection) NextUntil(selector string) *Selection {
 | 
						|
	return pushStack(s, getSiblingNodes(s.Nodes, siblingNextUntil,
 | 
						|
		compileMatcher(selector), nil))
 | 
						|
}
 | 
						|
 | 
						|
// NextUntilMatcher gets all following siblings of each element up to but not
 | 
						|
// including the element matched by the matcher. It returns a new Selection
 | 
						|
// object containing the matched elements.
 | 
						|
func (s *Selection) NextUntilMatcher(m Matcher) *Selection {
 | 
						|
	return pushStack(s, getSiblingNodes(s.Nodes, siblingNextUntil,
 | 
						|
		m, nil))
 | 
						|
}
 | 
						|
 | 
						|
// NextUntilSelection gets all following siblings of each element up to but not
 | 
						|
// including the element matched by the Selection. It returns a new Selection
 | 
						|
// object containing the matched elements.
 | 
						|
func (s *Selection) NextUntilSelection(sel *Selection) *Selection {
 | 
						|
	if sel == nil {
 | 
						|
		return s.NextAll()
 | 
						|
	}
 | 
						|
	return s.NextUntilNodes(sel.Nodes...)
 | 
						|
}
 | 
						|
 | 
						|
// NextUntilNodes gets all following siblings of each element up to but not
 | 
						|
// including the element matched by the nodes. It returns a new Selection
 | 
						|
// object containing the matched elements.
 | 
						|
func (s *Selection) NextUntilNodes(nodes ...*html.Node) *Selection {
 | 
						|
	return pushStack(s, getSiblingNodes(s.Nodes, siblingNextUntil,
 | 
						|
		nil, nodes))
 | 
						|
}
 | 
						|
 | 
						|
// PrevUntil gets all preceding siblings of each element up to but not
 | 
						|
// including the element matched by the selector. It returns a new Selection
 | 
						|
// object containing the matched elements.
 | 
						|
func (s *Selection) PrevUntil(selector string) *Selection {
 | 
						|
	return pushStack(s, getSiblingNodes(s.Nodes, siblingPrevUntil,
 | 
						|
		compileMatcher(selector), nil))
 | 
						|
}
 | 
						|
 | 
						|
// PrevUntilMatcher gets all preceding siblings of each element up to but not
 | 
						|
// including the element matched by the matcher. It returns a new Selection
 | 
						|
// object containing the matched elements.
 | 
						|
func (s *Selection) PrevUntilMatcher(m Matcher) *Selection {
 | 
						|
	return pushStack(s, getSiblingNodes(s.Nodes, siblingPrevUntil,
 | 
						|
		m, nil))
 | 
						|
}
 | 
						|
 | 
						|
// PrevUntilSelection gets all preceding siblings of each element up to but not
 | 
						|
// including the element matched by the Selection. It returns a new Selection
 | 
						|
// object containing the matched elements.
 | 
						|
func (s *Selection) PrevUntilSelection(sel *Selection) *Selection {
 | 
						|
	if sel == nil {
 | 
						|
		return s.PrevAll()
 | 
						|
	}
 | 
						|
	return s.PrevUntilNodes(sel.Nodes...)
 | 
						|
}
 | 
						|
 | 
						|
// PrevUntilNodes gets all preceding siblings of each element up to but not
 | 
						|
// including the element matched by the nodes. It returns a new Selection
 | 
						|
// object containing the matched elements.
 | 
						|
func (s *Selection) PrevUntilNodes(nodes ...*html.Node) *Selection {
 | 
						|
	return pushStack(s, getSiblingNodes(s.Nodes, siblingPrevUntil,
 | 
						|
		nil, nodes))
 | 
						|
}
 | 
						|
 | 
						|
// NextFilteredUntil is like NextUntil, with the option to filter
 | 
						|
// the results based on a selector string.
 | 
						|
// It returns a new Selection object containing the matched elements.
 | 
						|
func (s *Selection) NextFilteredUntil(filterSelector, untilSelector string) *Selection {
 | 
						|
	return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil,
 | 
						|
		compileMatcher(untilSelector), nil), compileMatcher(filterSelector))
 | 
						|
}
 | 
						|
 | 
						|
// NextFilteredUntilMatcher is like NextUntilMatcher, with the option to filter
 | 
						|
// the results based on a matcher.
 | 
						|
// It returns a new Selection object containing the matched elements.
 | 
						|
func (s *Selection) NextFilteredUntilMatcher(filter, until Matcher) *Selection {
 | 
						|
	return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil,
 | 
						|
		until, nil), filter)
 | 
						|
}
 | 
						|
 | 
						|
// NextFilteredUntilSelection is like NextUntilSelection, with the
 | 
						|
// option to filter the results based on a selector string. It returns a new
 | 
						|
// Selection object containing the matched elements.
 | 
						|
func (s *Selection) NextFilteredUntilSelection(filterSelector string, sel *Selection) *Selection {
 | 
						|
	return s.NextMatcherUntilSelection(compileMatcher(filterSelector), sel)
 | 
						|
}
 | 
						|
 | 
						|
// NextMatcherUntilSelection is like NextUntilSelection, with the
 | 
						|
// option to filter the results based on a matcher. It returns a new
 | 
						|
// Selection object containing the matched elements.
 | 
						|
func (s *Selection) NextMatcherUntilSelection(filter Matcher, sel *Selection) *Selection {
 | 
						|
	if sel == nil {
 | 
						|
		return s.NextMatcher(filter)
 | 
						|
	}
 | 
						|
	return s.NextMatcherUntilNodes(filter, sel.Nodes...)
 | 
						|
}
 | 
						|
 | 
						|
// NextFilteredUntilNodes is like NextUntilNodes, with the
 | 
						|
// option to filter the results based on a selector string. It returns a new
 | 
						|
// Selection object containing the matched elements.
 | 
						|
func (s *Selection) NextFilteredUntilNodes(filterSelector string, nodes ...*html.Node) *Selection {
 | 
						|
	return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil,
 | 
						|
		nil, nodes), compileMatcher(filterSelector))
 | 
						|
}
 | 
						|
 | 
						|
// NextMatcherUntilNodes is like NextUntilNodes, with the
 | 
						|
// option to filter the results based on a matcher. It returns a new
 | 
						|
// Selection object containing the matched elements.
 | 
						|
func (s *Selection) NextMatcherUntilNodes(filter Matcher, nodes ...*html.Node) *Selection {
 | 
						|
	return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil,
 | 
						|
		nil, nodes), filter)
 | 
						|
}
 | 
						|
 | 
						|
// PrevFilteredUntil is like PrevUntil, with the option to filter
 | 
						|
// the results based on a selector string.
 | 
						|
// It returns a new Selection object containing the matched elements.
 | 
						|
func (s *Selection) PrevFilteredUntil(filterSelector, untilSelector string) *Selection {
 | 
						|
	return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil,
 | 
						|
		compileMatcher(untilSelector), nil), compileMatcher(filterSelector))
 | 
						|
}
 | 
						|
 | 
						|
// PrevFilteredUntilMatcher is like PrevUntilMatcher, with the option to filter
 | 
						|
// the results based on a matcher.
 | 
						|
// It returns a new Selection object containing the matched elements.
 | 
						|
func (s *Selection) PrevFilteredUntilMatcher(filter, until Matcher) *Selection {
 | 
						|
	return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil,
 | 
						|
		until, nil), filter)
 | 
						|
}
 | 
						|
 | 
						|
// PrevFilteredUntilSelection is like PrevUntilSelection, with the
 | 
						|
// option to filter the results based on a selector string. It returns a new
 | 
						|
// Selection object containing the matched elements.
 | 
						|
func (s *Selection) PrevFilteredUntilSelection(filterSelector string, sel *Selection) *Selection {
 | 
						|
	return s.PrevMatcherUntilSelection(compileMatcher(filterSelector), sel)
 | 
						|
}
 | 
						|
 | 
						|
// PrevMatcherUntilSelection is like PrevUntilSelection, with the
 | 
						|
// option to filter the results based on a matcher. It returns a new
 | 
						|
// Selection object containing the matched elements.
 | 
						|
func (s *Selection) PrevMatcherUntilSelection(filter Matcher, sel *Selection) *Selection {
 | 
						|
	if sel == nil {
 | 
						|
		return s.PrevMatcher(filter)
 | 
						|
	}
 | 
						|
	return s.PrevMatcherUntilNodes(filter, sel.Nodes...)
 | 
						|
}
 | 
						|
 | 
						|
// PrevFilteredUntilNodes is like PrevUntilNodes, with the
 | 
						|
// option to filter the results based on a selector string. It returns a new
 | 
						|
// Selection object containing the matched elements.
 | 
						|
func (s *Selection) PrevFilteredUntilNodes(filterSelector string, nodes ...*html.Node) *Selection {
 | 
						|
	return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil,
 | 
						|
		nil, nodes), compileMatcher(filterSelector))
 | 
						|
}
 | 
						|
 | 
						|
// PrevMatcherUntilNodes is like PrevUntilNodes, with the
 | 
						|
// option to filter the results based on a matcher. It returns a new
 | 
						|
// Selection object containing the matched elements.
 | 
						|
func (s *Selection) PrevMatcherUntilNodes(filter Matcher, nodes ...*html.Node) *Selection {
 | 
						|
	return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil,
 | 
						|
		nil, nodes), filter)
 | 
						|
}
 | 
						|
 | 
						|
// Filter and push filters the nodes based on a matcher, and pushes the results
 | 
						|
// on the stack, with the srcSel as previous selection.
 | 
						|
func filterAndPush(srcSel *Selection, nodes []*html.Node, m Matcher) *Selection {
 | 
						|
	// Create a temporary Selection with the specified nodes to filter using winnow
 | 
						|
	sel := &Selection{nodes, srcSel.document, nil}
 | 
						|
	// Filter based on matcher and push on stack
 | 
						|
	return pushStack(srcSel, winnow(sel, m, true))
 | 
						|
}
 | 
						|
 | 
						|
// Internal implementation of Find that return raw nodes.
 | 
						|
func findWithMatcher(nodes []*html.Node, m Matcher) []*html.Node {
 | 
						|
	// Map nodes to find the matches within the children of each node
 | 
						|
	return mapNodes(nodes, func(i int, n *html.Node) (result []*html.Node) {
 | 
						|
		// Go down one level, becausejQuery's Find selects only within descendants
 | 
						|
		for c := n.FirstChild; c != nil; c = c.NextSibling {
 | 
						|
			if c.Type == html.ElementNode {
 | 
						|
				result = append(result, m.MatchAll(c)...)
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// Internal implementation to get all parent nodes, stopping at the specified
 | 
						|
// node (or nil if no stop).
 | 
						|
func getParentsNodes(nodes []*html.Node, stopm Matcher, stopNodes []*html.Node) []*html.Node {
 | 
						|
	return mapNodes(nodes, func(i int, n *html.Node) (result []*html.Node) {
 | 
						|
		for p := n.Parent; p != nil; p = p.Parent {
 | 
						|
			sel := newSingleSelection(p, nil)
 | 
						|
			if stopm != nil {
 | 
						|
				if sel.IsMatcher(stopm) {
 | 
						|
					break
 | 
						|
				}
 | 
						|
			} else if len(stopNodes) > 0 {
 | 
						|
				if sel.IsNodes(stopNodes...) {
 | 
						|
					break
 | 
						|
				}
 | 
						|
			}
 | 
						|
			if p.Type == html.ElementNode {
 | 
						|
				result = append(result, p)
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// Internal implementation of sibling nodes that return a raw slice of matches.
 | 
						|
func getSiblingNodes(nodes []*html.Node, st siblingType, untilm Matcher, untilNodes []*html.Node) []*html.Node {
 | 
						|
	var f func(*html.Node) bool
 | 
						|
 | 
						|
	// If the requested siblings are ...Until, create the test function to
 | 
						|
	// determine if the until condition is reached (returns true if it is)
 | 
						|
	if st == siblingNextUntil || st == siblingPrevUntil {
 | 
						|
		f = func(n *html.Node) bool {
 | 
						|
			if untilm != nil {
 | 
						|
				// Matcher-based condition
 | 
						|
				sel := newSingleSelection(n, nil)
 | 
						|
				return sel.IsMatcher(untilm)
 | 
						|
			} else if len(untilNodes) > 0 {
 | 
						|
				// Nodes-based condition
 | 
						|
				sel := newSingleSelection(n, nil)
 | 
						|
				return sel.IsNodes(untilNodes...)
 | 
						|
			}
 | 
						|
			return false
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return mapNodes(nodes, func(i int, n *html.Node) []*html.Node {
 | 
						|
		return getChildrenWithSiblingType(n.Parent, st, n, f)
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// Gets the children nodes of each node in the specified slice of nodes,
 | 
						|
// based on the sibling type request.
 | 
						|
func getChildrenNodes(nodes []*html.Node, st siblingType) []*html.Node {
 | 
						|
	return mapNodes(nodes, func(i int, n *html.Node) []*html.Node {
 | 
						|
		return getChildrenWithSiblingType(n, st, nil, nil)
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// Gets the children of the specified parent, based on the requested sibling
 | 
						|
// type, skipping a specified node if required.
 | 
						|
func getChildrenWithSiblingType(parent *html.Node, st siblingType, skipNode *html.Node,
 | 
						|
	untilFunc func(*html.Node) bool) (result []*html.Node) {
 | 
						|
 | 
						|
	// Create the iterator function
 | 
						|
	var iter = func(cur *html.Node) (ret *html.Node) {
 | 
						|
		// Based on the sibling type requested, iterate the right way
 | 
						|
		for {
 | 
						|
			switch st {
 | 
						|
			case siblingAll, siblingAllIncludingNonElements:
 | 
						|
				if cur == nil {
 | 
						|
					// First iteration, start with first child of parent
 | 
						|
					// Skip node if required
 | 
						|
					if ret = parent.FirstChild; ret == skipNode && skipNode != nil {
 | 
						|
						ret = skipNode.NextSibling
 | 
						|
					}
 | 
						|
				} else {
 | 
						|
					// Skip node if required
 | 
						|
					if ret = cur.NextSibling; ret == skipNode && skipNode != nil {
 | 
						|
						ret = skipNode.NextSibling
 | 
						|
					}
 | 
						|
				}
 | 
						|
			case siblingPrev, siblingPrevAll, siblingPrevUntil:
 | 
						|
				if cur == nil {
 | 
						|
					// Start with previous sibling of the skip node
 | 
						|
					ret = skipNode.PrevSibling
 | 
						|
				} else {
 | 
						|
					ret = cur.PrevSibling
 | 
						|
				}
 | 
						|
			case siblingNext, siblingNextAll, siblingNextUntil:
 | 
						|
				if cur == nil {
 | 
						|
					// Start with next sibling of the skip node
 | 
						|
					ret = skipNode.NextSibling
 | 
						|
				} else {
 | 
						|
					ret = cur.NextSibling
 | 
						|
				}
 | 
						|
			default:
 | 
						|
				panic("Invalid sibling type.")
 | 
						|
			}
 | 
						|
			if ret == nil || ret.Type == html.ElementNode || st == siblingAllIncludingNonElements {
 | 
						|
				return
 | 
						|
			}
 | 
						|
			// Not a valid node, try again from this one
 | 
						|
			cur = ret
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	for c := iter(nil); c != nil; c = iter(c) {
 | 
						|
		// If this is an ...Until case, test before append (returns true
 | 
						|
		// if the until condition is reached)
 | 
						|
		if st == siblingNextUntil || st == siblingPrevUntil {
 | 
						|
			if untilFunc(c) {
 | 
						|
				return
 | 
						|
			}
 | 
						|
		}
 | 
						|
		result = append(result, c)
 | 
						|
		if st == siblingNext || st == siblingPrev {
 | 
						|
			// Only one node was requested (immediate next or previous), so exit
 | 
						|
			return
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// Internal implementation of parent nodes that return a raw slice of Nodes.
 | 
						|
func getParentNodes(nodes []*html.Node) []*html.Node {
 | 
						|
	return mapNodes(nodes, func(i int, n *html.Node) []*html.Node {
 | 
						|
		if n.Parent != nil && n.Parent.Type == html.ElementNode {
 | 
						|
			return []*html.Node{n.Parent}
 | 
						|
		}
 | 
						|
		return nil
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// Internal map function used by many traversing methods. Takes the source nodes
 | 
						|
// to iterate on and the mapping function that returns an array of nodes.
 | 
						|
// Returns an array of nodes mapped by calling the callback function once for
 | 
						|
// each node in the source nodes.
 | 
						|
func mapNodes(nodes []*html.Node, f func(int, *html.Node) []*html.Node) (result []*html.Node) {
 | 
						|
	set := make(map[*html.Node]bool)
 | 
						|
	for i, n := range nodes {
 | 
						|
		if vals := f(i, n); len(vals) > 0 {
 | 
						|
			result = appendWithoutDuplicates(result, vals, set)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return result
 | 
						|
}
 |