add Next() and NextFiltered() with tests

This commit is contained in:
Martin Angers
2012-09-04 12:07:59 -04:00
parent ff0cbc32c4
commit ed3b9aca8a
4 changed files with 79 additions and 12 deletions

5
doc.go
View File

@@ -77,7 +77,6 @@ The various methods are split into files based on the category of behavior:
* traversal.go : methods to traverse the HTML document tree.
- Children...()
- Closest()
- Contents()
- Find...()
- Next...()
@@ -103,7 +102,7 @@ package goquery
// DONE expand.go : "Expanding": Add(), AndSelf()
// DONE query.go : Reflect (query) node: Is(), Contains(), HasClass()
// DONE property.go : Inspect node: Html(), Text(), Attr(), Length(), Size()
// traversal.go : Traversal: Contents(), Find(), Children(), Parents...(), Next...(), Prev...(), Closest(), Siblings()
// traversal.go : Traversal: Contents(), Find(), Children(), Parents...(), Next...(), Prev...(), Siblings()
// DONE iteration.go : Iteration: Each(), Map()
// DONE type.go : Selection and Document
@@ -116,7 +115,7 @@ package goquery
// x AndSelf()
// x Attr()
// x Children()
// - Closest() - Tree Traversal
// x Closest() ?
// x Contains()
// x Contents()
// x Each()

8
testdata/page.html vendored
View File

@@ -14,14 +14,14 @@
<link href="/css/pvk.min.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="container-fluid">
<div class="container-fluid" id="cf1">
<div class="row-fluid">
<div class="pvk-gutter">
&nbsp;
</div>
<div class="pvk-content">
<div ng-controller="HeroCtrl" class="hero-unit">
<div class="container-fluid">
<div class="container-fluid" id="cf2">
<div class="row-fluid">
<div class="span12">
<h1>
@@ -55,7 +55,7 @@
&nbsp;
</div>
<div class="pvk-content">
<div class="container-fluid">
<div class="container-fluid" id="cf3">
<div class="row-fluid">
<div ng-cloak="" view-on-display="" ng-controller="MsgCtrl" ng-class="{'displayed': blockIsDisplayed}" class="message-box">
<div ng-class="{'alert-info': isInfo, 'alert-error': !isInfo, 'displayed': isDisplayed}" class="alert">
@@ -70,7 +70,7 @@
</div>
</div>
</div>
<div class="container-fluid">
<div class="container-fluid" id="cf4">
<div ng-controller="ShareCtrl" ng-hide="isHidden" class="row-fluid center-content"></div>
</div>
<div ng-view=""></div>

View File

@@ -182,7 +182,7 @@ func (this *Selection) ParentsFilteredUntilNodes(filterSelector string, nodes ..
// Siblings() gets the siblings of each element in the Selection. It returns
// a new Selection object containing the matched elements.
func (this *Selection) Siblings() *Selection {
return pushStack(this, getSiblingNodes(this.Nodes))
return pushStack(this, getSiblingNodes(this.Nodes, 0))
}
// SiblingsFiltered() gets the siblings of each element in the Selection
@@ -190,7 +190,26 @@ func (this *Selection) Siblings() *Selection {
// matched elements.
func (this *Selection) SiblingsFiltered(selector string) *Selection {
// Get the Siblings() unfiltered
n := getSiblingNodes(this.Nodes)
n := getSiblingNodes(this.Nodes, 0)
// Create a temporary Selection to filter using winnow
sel := &Selection{n, this.document, nil}
// Filter based on selector
n = winnow(sel, selector, true)
return pushStack(this, n)
}
// Next() gets the immediately following sibling of each element in the
// Selection. It returns a new Selection object containing the matched elements.
func (this *Selection) Next() *Selection {
return pushStack(this, getSiblingNodes(this.Nodes, 1))
}
// 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 (this *Selection) NextFiltered(selector string) *Selection {
// Get the Next() unfiltered
n := getSiblingNodes(this.Nodes, 1)
// Create a temporary Selection to filter using winnow
sel := &Selection{n, this.document, nil}
// Filter based on selector
@@ -222,12 +241,36 @@ func getParentsNodes(nodes []*html.Node, stopSelector string, stopNodes []*html.
}
// Internal implementation of sibling nodes that return a raw slice of matches.
func getSiblingNodes(nodes []*html.Node) []*html.Node {
func getSiblingNodes(nodes []*html.Node, siblingType int) []*html.Node {
// Sibling type means:
// -1 : previous node only
// 1 : next node only
// 0 : all but itself
return mapNodes(nodes, func(i int, n *html.Node) (result []*html.Node) {
var prev *html.Node
// Get the parent and loop through all children
if p := n.Parent; p != nil {
for _, c := range p.Child {
if c != n && c.Type == html.ElementNode {
// Care only about elements
if c.Type == html.ElementNode {
// Is it the existing node?
if c == n && siblingType == -1 {
// We want the previous node only, so append it and return
if prev != nil {
result = append(result, prev)
}
return
} else if prev == n && siblingType == 1 {
// We want only the next node and this is it, so append it and return
result = append(result, c)
return
}
prev = c
if c != n && siblingType == 0 {
// This is not the original node, so append it
result = append(result, c)
}
}
}
}

View File

@@ -132,3 +132,28 @@ func TestSiblingsFiltered(t *testing.T) {
sel := Doc().Root.Find(".pvk-gutter").SiblingsFiltered(".pvk-content")
AssertLength(t, sel.Nodes, 3)
}
func TestNext(t *testing.T) {
sel := Doc().Root.Find("h1").Next()
AssertLength(t, sel.Nodes, 1)
}
func TestNext2(t *testing.T) {
sel := Doc().Root.Find(".close").Next()
AssertLength(t, sel.Nodes, 1)
}
func TestNextNone(t *testing.T) {
sel := Doc().Root.Find("small").Next()
AssertLength(t, sel.Nodes, 0)
}
func TestNextFiltered(t *testing.T) {
sel := Doc().Root.Find(".container-fluid").NextFiltered("div")
AssertLength(t, sel.Nodes, 2)
}
func TestNextFiltered2(t *testing.T) {
sel := Doc().Root.Find(".container-fluid").NextFiltered("[ng-view]")
AssertLength(t, sel.Nodes, 1)
}