mirror of
https://github.com/PuerkitoBio/goquery
synced 2025-10-28 10:31:34 +08:00
add Next() and NextFiltered() with tests
This commit is contained in:
5
doc.go
5
doc.go
@@ -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
8
testdata/page.html
vendored
@@ -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">
|
||||
|
||||
</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 @@
|
||||
|
||||
</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>
|
||||
|
||||
51
traversal.go
51
traversal.go
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user