array.go 3.76 KB
Newer Older
ale's avatar
ale committed
1 2 3 4 5 6
package goquery

import (
	"golang.org/x/net/html"
)

ale's avatar
ale committed
7 8 9 10 11 12 13 14 15 16
const (
	maxUint = ^uint(0)
	maxInt  = int(maxUint >> 1)

	// ToEnd is a special index value that can be used as end index in a call
	// to Slice so that all elements are selected until the end of the Selection.
	// It is equivalent to passing (*Selection).Length().
	ToEnd = maxInt
)

ale's avatar
ale committed
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
// First reduces the set of matched elements to the first in the set.
// It returns a new Selection object, and an empty Selection object if the
// the selection is empty.
func (s *Selection) First() *Selection {
	return s.Eq(0)
}

// Last reduces the set of matched elements to the last in the set.
// It returns a new Selection object, and an empty Selection object if
// the selection is empty.
func (s *Selection) Last() *Selection {
	return s.Eq(-1)
}

// Eq reduces the set of matched elements to the one at the specified index.
// If a negative index is given, it counts backwards starting at the end of the
// set. It returns a new Selection object, and an empty Selection object if the
// index is invalid.
func (s *Selection) Eq(index int) *Selection {
	if index < 0 {
		index += len(s.Nodes)
	}

	if index >= len(s.Nodes) || index < 0 {
		return newEmptySelection(s.document)
	}

	return s.Slice(index, index+1)
}

// Slice reduces the set of matched elements to a subset specified by a range
ale's avatar
ale committed
48 49 50 51 52 53 54 55 56 57
// of indices. The start index is 0-based and indicates the index of the first
// element to select. The end index is 0-based and indicates the index at which
// the elements stop being selected (the end index is not selected).
//
// The indices may be negative, in which case they represent an offset from the
// end of the selection.
//
// The special value ToEnd may be specified as end index, in which case all elements
// until the end are selected. This works both for a positive and negative start
// index.
ale's avatar
ale committed
58 59 60 61
func (s *Selection) Slice(start, end int) *Selection {
	if start < 0 {
		start += len(s.Nodes)
	}
ale's avatar
ale committed
62 63 64
	if end == ToEnd {
		end = len(s.Nodes)
	} else if end < 0 {
ale's avatar
ale committed
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
		end += len(s.Nodes)
	}
	return pushStack(s, s.Nodes[start:end])
}

// Get retrieves the underlying node at the specified index.
// Get without parameter is not implemented, since the node array is available
// on the Selection object.
func (s *Selection) Get(index int) *html.Node {
	if index < 0 {
		index += len(s.Nodes) // Negative index gets from the end
	}
	return s.Nodes[index]
}

// Index returns the position of the first element within the Selection object
// relative to its sibling elements.
func (s *Selection) Index() int {
	if len(s.Nodes) > 0 {
		return newSingleSelection(s.Nodes[0], s.document).PrevAll().Length()
	}
	return -1
}

// IndexSelector returns the position of the first element within the
// Selection object relative to the elements matched by the selector, or -1 if
// not found.
func (s *Selection) IndexSelector(selector string) int {
	if len(s.Nodes) > 0 {
		sel := s.document.Find(selector)
		return indexInSlice(sel.Nodes, s.Nodes[0])
	}
	return -1
}

// IndexMatcher returns the position of the first element within the
// Selection object relative to the elements matched by the matcher, or -1 if
// not found.
func (s *Selection) IndexMatcher(m Matcher) int {
	if len(s.Nodes) > 0 {
		sel := s.document.FindMatcher(m)
		return indexInSlice(sel.Nodes, s.Nodes[0])
	}
	return -1
}

// IndexOfNode returns the position of the specified node within the Selection
// object, or -1 if not found.
func (s *Selection) IndexOfNode(node *html.Node) int {
	return indexInSlice(s.Nodes, node)
}

// IndexOfSelection returns the position of the first node in the specified
// Selection object within this Selection object, or -1 if not found.
func (s *Selection) IndexOfSelection(sel *Selection) int {
	if sel != nil && len(sel.Nodes) > 0 {
		return indexInSlice(s.Nodes, sel.Nodes[0])
	}
	return -1
}