mirror of
https://github.com/PuerkitoBio/goquery
synced 2025-09-27 13:12:23 +08:00
add Add() and AndSelf(), with tests
This commit is contained in:
29
array.go
29
array.go
@@ -17,8 +17,9 @@ func (this *Selection) Last() *Selection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Eq() reduces the set of matched elements to the one at the specified index.
|
// 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.
|
// If a negative index is given, it counts backwards starting at the end of the
|
||||||
// It returns a new Selection object, and an empty Selection object if the index is invalid.
|
// set. It returns a new Selection object, and an empty Selection object if the
|
||||||
|
// index is invalid.
|
||||||
func (this *Selection) Eq(index int) *Selection {
|
func (this *Selection) Eq(index int) *Selection {
|
||||||
if index < 0 {
|
if index < 0 {
|
||||||
index += len(this.Nodes)
|
index += len(this.Nodes)
|
||||||
@@ -26,9 +27,10 @@ func (this *Selection) Eq(index int) *Selection {
|
|||||||
return this.Slice(index, index+1)
|
return this.Slice(index, index+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slice() reduces the set of matched elements to a subset specified by a range of indices.
|
// Slice() reduces the set of matched elements to a subset specified by a range
|
||||||
// At the moment, negative indices are not supported.
|
// of indices. At the moment, negative indices are not supported.
|
||||||
func (this *Selection) Slice(start int, end int) *Selection {
|
func (this *Selection) Slice(start int, end int) *Selection {
|
||||||
|
// TODO : Negative indices, like jQuery
|
||||||
return pushStack(this, this.Nodes[start:end])
|
return pushStack(this, this.Nodes[start:end])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,8 +44,8 @@ func (this *Selection) Get(index int) *html.Node {
|
|||||||
return this.Nodes[index]
|
return this.Nodes[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Index() returns the position of the first element within the Selection object relative to
|
// Index() returns the position of the first element within the Selection object
|
||||||
// its sibling elements.
|
// relative to its sibling elements.
|
||||||
func (this *Selection) Index() int {
|
func (this *Selection) Index() int {
|
||||||
// TODO : Eventually refactor with prevAll(), like jQuery's code
|
// TODO : Eventually refactor with prevAll(), like jQuery's code
|
||||||
if len(this.Nodes) > 0 {
|
if len(this.Nodes) > 0 {
|
||||||
@@ -63,8 +65,9 @@ func (this *Selection) Index() int {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
// IndexSelector() returns the position of the first element within the Selection object
|
// IndexSelector() returns the position of the first element within the
|
||||||
// relative to the elements matched by the selector, or -1 if not found.
|
// Selection object relative to the elements matched by the selector, or -1 if
|
||||||
|
// not found.
|
||||||
func (this *Selection) IndexSelector(selector string) int {
|
func (this *Selection) IndexSelector(selector string) int {
|
||||||
if len(this.Nodes) > 0 {
|
if len(this.Nodes) > 0 {
|
||||||
sel := this.document.Find(selector)
|
sel := this.document.Find(selector)
|
||||||
@@ -73,16 +76,16 @@ func (this *Selection) IndexSelector(selector string) int {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
// IndexOfNode() returns the position of the specified node within the Selection object,
|
// IndexOfNode() returns the position of the specified node within the Selection
|
||||||
// or -1 if not found.
|
// object, or -1 if not found.
|
||||||
func (this *Selection) IndexOfNode(node *html.Node) int {
|
func (this *Selection) IndexOfNode(node *html.Node) int {
|
||||||
return indexInSlice(this.Nodes, node)
|
return indexInSlice(this.Nodes, node)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IndexOfSelection() returns the position of the first node in the specified Selection object
|
// IndexOfSelection() returns the position of the first node in the specified
|
||||||
// within this Selection object, or -1 if not found.
|
// Selection object within this Selection object, or -1 if not found.
|
||||||
func (this *Selection) IndexOfSelection(s *Selection) int {
|
func (this *Selection) IndexOfSelection(s *Selection) int {
|
||||||
if len(s.Nodes) > 0 {
|
if s != nil && len(s.Nodes) > 0 {
|
||||||
return indexInSlice(this.Nodes, s.Nodes[0])
|
return indexInSlice(this.Nodes, s.Nodes[0])
|
||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
|
2
doc.go
2
doc.go
@@ -41,7 +41,7 @@ https://github.com/puerkitobio/goquery
|
|||||||
package goquery
|
package goquery
|
||||||
|
|
||||||
// DONE array.go : Positional Manipulation: First(), Last(), Eq(), Get(), Index(), Slice()
|
// DONE array.go : Positional Manipulation: First(), Last(), Eq(), Get(), Index(), Slice()
|
||||||
// TESTS filter.go : Filtering: Filter(), Not(), Has(), End()
|
// DONE filter.go : Filtering: Filter(), Not(), Has(), End()
|
||||||
// expand.go : "Expanding": Add(), AndSelf()
|
// expand.go : "Expanding": Add(), AndSelf()
|
||||||
// query.go : Reflect (query) node: Is(), Contains(), HasClass()
|
// query.go : Reflect (query) node: Is(), Contains(), HasClass()
|
||||||
// property.go : Inspect node: Contents(), Html(), Text(), Attr(), Val(), Length(), Size()
|
// property.go : Inspect node: Contents(), Html(), Text(), Attr(), Val(), Length(), Size()
|
||||||
|
36
expand.go
36
expand.go
@@ -4,24 +4,32 @@ import (
|
|||||||
"exp/html"
|
"exp/html"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO : Should return a new Selection object, use pushStack()
|
// Add() adds the selector string's matching nodes to those in the current
|
||||||
|
// selection and returns a new Selection object.
|
||||||
// Adds matching nodes to the current selection. Returns the same Selection object.
|
// The selector string is run in the context of the document of the current
|
||||||
// The new selector string is run in the context of the document of the Selection object.
|
// Selection object.
|
||||||
func (this *Selection) Add(selector string) *Selection {
|
func (this *Selection) Add(selector string) *Selection {
|
||||||
this.Nodes = appendWithoutDuplicates(this.Nodes, findWithContext(selector, this.document.Root))
|
return this.AddNodes(findWithContext(selector, this.document.Root)...)
|
||||||
return this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds nodes of the specified Selection object to the current selection. Returns the same Selection object.
|
// AddSelection() adds the specified Selection object's nodes to those in the
|
||||||
|
// current selection and returns a new Selection object.
|
||||||
func (this *Selection) AddSelection(sel *Selection) *Selection {
|
func (this *Selection) AddSelection(sel *Selection) *Selection {
|
||||||
this.Nodes = appendWithoutDuplicates(this.Nodes, sel.Nodes)
|
if sel == nil {
|
||||||
return this
|
return this.AddNodes()
|
||||||
|
}
|
||||||
|
return this.AddNodes(sel.Nodes...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds nodes to the current selection. Returns the same Selection object.
|
// AddNodes() adds the specified nodes to those in the
|
||||||
// No verification about the same document origin is done.
|
// current selection and returns a new Selection object.
|
||||||
func (this *Selection) AddNodes(nodes []*html.Node) *Selection {
|
func (this *Selection) AddNodes(nodes ...*html.Node) *Selection {
|
||||||
this.Nodes = appendWithoutDuplicates(this.Nodes, nodes)
|
return pushStack(this, appendWithoutDuplicates(this.Nodes, nodes))
|
||||||
return this
|
}
|
||||||
|
|
||||||
|
// AndSelf() adds the previous set of elements on the stack to the current set.
|
||||||
|
// It returns a new Selection object containing the current Selection combined
|
||||||
|
// with the previous one.
|
||||||
|
func (this *Selection) AndSelf() *Selection {
|
||||||
|
return this.AddSelection(this.prevSel)
|
||||||
}
|
}
|
||||||
|
@@ -5,18 +5,53 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestAdd(t *testing.T) {
|
func TestAdd(t *testing.T) {
|
||||||
var cnt int
|
sel := Doc().Find("div.row-fluid").Add("a")
|
||||||
|
if len(sel.Nodes) != 19 {
|
||||||
EnsureDocLoaded()
|
t.Errorf("Expected 19 nodes, found %v.", len(sel.Nodes))
|
||||||
|
}
|
||||||
sel := Doc().Find("div.row-fluid")
|
}
|
||||||
cnt = len(sel.Nodes)
|
|
||||||
sel2 := sel.Add("a")
|
func TestAddSelection(t *testing.T) {
|
||||||
if sel != sel2 {
|
sel := Doc().Find("div.row-fluid")
|
||||||
t.Error("Expected returned Selection from Add() to be same as 'this'.")
|
sel2 := Doc().Find("a")
|
||||||
|
sel = sel.AddSelection(sel2)
|
||||||
|
if len(sel.Nodes) != 19 {
|
||||||
|
t.Errorf("Expected 19 nodes, found %v.", len(sel.Nodes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddSelectionNil(t *testing.T) {
|
||||||
|
sel := Doc().Find("div.row-fluid")
|
||||||
|
if len(sel.Nodes) != 9 {
|
||||||
|
t.Errorf("Expected div.row-fluid to have 9 nodes, found %v.",
|
||||||
|
len(sel.Nodes))
|
||||||
|
}
|
||||||
|
sel = sel.AddSelection(nil)
|
||||||
|
if len(sel.Nodes) != 9 {
|
||||||
|
t.Errorf("Expected add nil to keep it to 9 nodes, found %v.",
|
||||||
|
len(sel.Nodes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddNodes(t *testing.T) {
|
||||||
|
sel := Doc().Find("div.pvk-gutter")
|
||||||
|
sel2 := Doc().Find(".pvk-content")
|
||||||
|
sel = sel.AddNodes(sel2.Nodes...)
|
||||||
|
if len(sel.Nodes) != 9 {
|
||||||
|
t.Errorf("Expected 9 nodes, found %v.", len(sel.Nodes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddNodesNone(t *testing.T) {
|
||||||
|
sel := Doc().Find("div.pvk-gutter").AddNodes()
|
||||||
|
if len(sel.Nodes) != 6 {
|
||||||
|
t.Errorf("Expected 6 nodes, found %v.", len(sel.Nodes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAndSelf(t *testing.T) {
|
||||||
|
sel := Doc().Find(".span12").Last().AndSelf()
|
||||||
|
if len(sel.Nodes) != 2 {
|
||||||
|
t.Errorf("Expected 2 nodes, found %v.", len(sel.Nodes))
|
||||||
}
|
}
|
||||||
if len(sel.Nodes) <= cnt {
|
|
||||||
t.Error("Expected nodes to be added to Selection.")
|
|
||||||
}
|
|
||||||
t.Logf("%v nodes after div.row-fluid and a were added.", len(sel.Nodes))
|
|
||||||
}
|
}
|
||||||
|
32
filter.go
32
filter.go
@@ -41,15 +41,23 @@ func (this *Selection) NotNodes(nodes ...*html.Node) *Selection {
|
|||||||
return pushStack(this, winnowNodes(this, nodes, false))
|
return pushStack(this, winnowNodes(this, nodes, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterSelection() reduces the set of matched elements to those that match a node in the specified Selection object.
|
// FilterSelection() reduces the set of matched elements to those that match a
|
||||||
|
// node in the specified Selection object.
|
||||||
// It returns a new Selection object for this subset of elements.
|
// It returns a new Selection object for this subset of elements.
|
||||||
func (this *Selection) FilterSelection(s *Selection) *Selection {
|
func (this *Selection) FilterSelection(s *Selection) *Selection {
|
||||||
|
if s == nil {
|
||||||
|
return pushStack(this, winnowNodes(this, nil, true))
|
||||||
|
}
|
||||||
return pushStack(this, winnowNodes(this, s.Nodes, true))
|
return pushStack(this, winnowNodes(this, s.Nodes, true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not() removes elements from the Selection that match a node in the specified Selection object.
|
// Not() removes elements from the Selection that match a node in the specified
|
||||||
|
// Selection object.
|
||||||
// It returns a new Selection object with the matching elements removed.
|
// It returns a new Selection object with the matching elements removed.
|
||||||
func (this *Selection) NotSelection(s *Selection) *Selection {
|
func (this *Selection) NotSelection(s *Selection) *Selection {
|
||||||
|
if s == nil {
|
||||||
|
return pushStack(this, winnowNodes(this, nil, false))
|
||||||
|
}
|
||||||
return pushStack(this, winnowNodes(this, s.Nodes, false))
|
return pushStack(this, winnowNodes(this, s.Nodes, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,14 +66,15 @@ func (this *Selection) Union(s *Selection) *Selection {
|
|||||||
return this.FilterSelection(s)
|
return this.FilterSelection(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Has() reduces the set of matched elements to those that have a descendant that matches the selector.
|
// Has() reduces the set of matched elements to those that have a descendant
|
||||||
|
// that matches the selector.
|
||||||
// It returns a new Selection object with the matching elements.
|
// It returns a new Selection object with the matching elements.
|
||||||
func (this *Selection) Has(selector string) *Selection {
|
func (this *Selection) Has(selector string) *Selection {
|
||||||
sel := this.document.Find(selector)
|
return this.HasSelection(this.document.Find(selector))
|
||||||
return this.HasSelection(sel)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasNodes() reduces the set of matched elements to those that have a descendant that matches one of the nodes.
|
// HasNodes() reduces the set of matched elements to those that have a
|
||||||
|
// descendant that matches one of the nodes.
|
||||||
// It returns a new Selection object with the matching elements.
|
// It returns a new Selection object with the matching elements.
|
||||||
func (this *Selection) HasNodes(nodes ...*html.Node) *Selection {
|
func (this *Selection) HasNodes(nodes ...*html.Node) *Selection {
|
||||||
return this.FilterFunction(func(_ int, s *Selection) bool {
|
return this.FilterFunction(func(_ int, s *Selection) bool {
|
||||||
@@ -79,15 +88,18 @@ func (this *Selection) HasNodes(nodes ...*html.Node) *Selection {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasSelection() reduces the set of matched elements to those that have a descendant that matches one of
|
// HasSelection() reduces the set of matched elements to those that have a
|
||||||
// the nodes of the specified Selection object.
|
// descendant that matches one of the nodes of the specified Selection object.
|
||||||
// It returns a new Selection object with the matching elements.
|
// It returns a new Selection object with the matching elements.
|
||||||
func (this *Selection) HasSelection(sel *Selection) *Selection {
|
func (this *Selection) HasSelection(sel *Selection) *Selection {
|
||||||
|
if sel == nil {
|
||||||
|
return this.HasNodes()
|
||||||
|
}
|
||||||
return this.HasNodes(sel.Nodes...)
|
return this.HasNodes(sel.Nodes...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// End() ends the most recent filtering operation in the current chain and returns
|
// End() ends the most recent filtering operation in the current chain and
|
||||||
// the set of matched elements to its previous state.
|
// returns the set of matched elements to its previous state.
|
||||||
func (this *Selection) End() *Selection {
|
func (this *Selection) End() *Selection {
|
||||||
if this.prevSel != nil {
|
if this.prevSel != nil {
|
||||||
return this.prevSel
|
return this.prevSel
|
||||||
|
@@ -44,6 +44,16 @@ func TestFilterSelection(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFilterSelectionNil(t *testing.T) {
|
||||||
|
var sel2 *Selection
|
||||||
|
|
||||||
|
sel := Doc().Find(".link")
|
||||||
|
sel3 := sel.FilterSelection(sel2)
|
||||||
|
if len(sel3.Nodes) != 0 {
|
||||||
|
t.Errorf("Expected no node, found %v.", len(sel3.Nodes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNot(t *testing.T) {
|
func TestNot(t *testing.T) {
|
||||||
sel := Doc().Find(".span12").Not(".alert")
|
sel := Doc().Find(".span12").Not(".alert")
|
||||||
if len(sel.Nodes) != 1 {
|
if len(sel.Nodes) != 1 {
|
||||||
|
24
utilities.go
24
utilities.go
@@ -19,7 +19,9 @@ func sliceContains(container []*html.Node, contained *html.Node) bool {
|
|||||||
func nodeContains(container *html.Node, contained *html.Node) bool {
|
func nodeContains(container *html.Node, contained *html.Node) bool {
|
||||||
// Check if the parent of the contained node is the container node, traversing
|
// Check if the parent of the contained node is the container node, traversing
|
||||||
// upward until the top is reached, or the container is found.
|
// upward until the top is reached, or the container is found.
|
||||||
for contained = contained.Parent; contained != nil; contained = contained.Parent {
|
for contained = contained.Parent; contained != nil; contained =
|
||||||
|
contained.Parent {
|
||||||
|
|
||||||
if container == contained {
|
if container == contained {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -45,9 +47,12 @@ func indexInSlice(slice []*html.Node, node *html.Node) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Appends the new nodes to the target slice, making sure no duplicate is added.
|
// Appends the new nodes to the target slice, making sure no duplicate is added.
|
||||||
// There is no check to the original state of the target slice, so it may still contain
|
// There is no check to the original state of the target slice, so it may still
|
||||||
// duplicates. The target slice is returned because append() may create a new underlying array.
|
// contain duplicates. The target slice is returned because append() may create
|
||||||
func appendWithoutDuplicates(target []*html.Node, nodes []*html.Node) []*html.Node {
|
// a new underlying array.
|
||||||
|
func appendWithoutDuplicates(target []*html.Node,
|
||||||
|
nodes []*html.Node) []*html.Node {
|
||||||
|
|
||||||
for _, n := range nodes {
|
for _, n := range nodes {
|
||||||
if !isInSlice(target, n) {
|
if !isInSlice(target, n) {
|
||||||
target = append(target, n)
|
target = append(target, n)
|
||||||
@@ -57,8 +62,11 @@ func appendWithoutDuplicates(target []*html.Node, nodes []*html.Node) []*html.No
|
|||||||
return target
|
return target
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop through a selection, returning only those nodes that pass the predicate function.
|
// Loop through a selection, returning only those nodes that pass the predicate
|
||||||
func grep(sel *Selection, predicate func(i int, s *Selection) bool) (result []*html.Node) {
|
// function.
|
||||||
|
func grep(sel *Selection, predicate func(i int,
|
||||||
|
s *Selection) bool,) (result []*html.Node) {
|
||||||
|
|
||||||
for i, n := range sel.Nodes {
|
for i, n := range sel.Nodes {
|
||||||
if predicate(i, newSingleSelection(n, sel.document)) {
|
if predicate(i, newSingleSelection(n, sel.document)) {
|
||||||
result = append(result, n)
|
result = append(result, n)
|
||||||
@@ -67,8 +75,8 @@ func grep(sel *Selection, predicate func(i int, s *Selection) bool) (result []*h
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a new Selection object based on the specified nodes, and keeps the source
|
// Creates a new Selection object based on the specified nodes, and keeps the
|
||||||
// Selection object on the stack (linked list).
|
// source Selection object on the stack (linked list).
|
||||||
func pushStack(fromSel *Selection, nodes []*html.Node) (result *Selection) {
|
func pushStack(fromSel *Selection, nodes []*html.Node) (result *Selection) {
|
||||||
result = &Selection{nodes, fromSel.document, fromSel}
|
result = &Selection{nodes, fromSel.document, fromSel}
|
||||||
return
|
return
|
||||||
|
Reference in New Issue
Block a user