mirror of
https://github.com/PuerkitoBio/goquery.git
synced 2026-09-20 11:18:40 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ee0843df1 | ||
|
|
dd800704d1 | ||
|
|
ef5f2ddf71 | ||
|
|
3d22a4dd10 | ||
|
|
b4ef68dec8 | ||
|
|
738783cbc3 | ||
|
|
a80a922806 | ||
|
|
8cb3ddf6e3 |
@@ -1,7 +1,7 @@
|
||||
module github.com/PuerkitoBio/goquery
|
||||
|
||||
require (
|
||||
github.com/andybalholm/cascadia v1.3.4
|
||||
github.com/andybalholm/cascadia v1.3.5
|
||||
golang.org/x/net v0.58.0
|
||||
)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
github.com/andybalholm/cascadia v1.3.4 h1:vM2lgh0Vru9Vwyfm4cQqWP2HHMW0u0+2PAW7Q38Qufg=
|
||||
github.com/andybalholm/cascadia v1.3.4/go.mod h1:BLRmbRjpEtNKieZOCCvYj4RqN+KRA41GBe/5O+G93kM=
|
||||
github.com/andybalholm/cascadia v1.3.5 h1:RLjq12WJy58dN6eCIQrz0bAGZkztHWsEPFxP53Y7Ms8=
|
||||
github.com/andybalholm/cascadia v1.3.5/go.mod h1:BLRmbRjpEtNKieZOCCvYj4RqN+KRA41GBe/5O+G93kM=
|
||||
golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To=
|
||||
golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU=
|
||||
|
||||
+5
-4
@@ -1,6 +1,7 @@
|
||||
package goquery
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
@@ -618,11 +619,11 @@ func (s *Selection) manipulateNodes(ns []*html.Node, reverse bool,
|
||||
|
||||
// net.Html doesn't provide document fragments for insertion, so to get
|
||||
// things in the correct order with After() and Prepend(), the callback
|
||||
// needs to be called on the reverse of the nodes.
|
||||
// needs to be called on the reverse of the nodes. Clone the slice before
|
||||
// reversing so the caller's slice is not modified.
|
||||
if reverse {
|
||||
for i, j := 0, len(ns)-1; i < j; i, j = i+1, j-1 {
|
||||
ns[i], ns[j] = ns[j], ns[i]
|
||||
}
|
||||
ns = slices.Clone(ns)
|
||||
slices.Reverse(ns)
|
||||
}
|
||||
|
||||
for i, sn := range s.Nodes {
|
||||
|
||||
+17
-4
@@ -167,7 +167,7 @@ func (s *Selection) RemoveClass(class ...string) *Selection {
|
||||
} else {
|
||||
classes, attr := getClassesAndAttr(n)
|
||||
for _, rcl := range rclasses {
|
||||
classes = strings.ReplaceAll(classes, " "+rcl+" ", " ")
|
||||
classes = removeClassFromClasses(classes, rcl)
|
||||
}
|
||||
|
||||
setClasses(n, attr, classes)
|
||||
@@ -191,9 +191,8 @@ func (s *Selection) ToggleClass(class ...string) *Selection {
|
||||
for _, n := range s.Nodes {
|
||||
classes, attr := getClassesAndAttr(n)
|
||||
for _, tcl := range tcls {
|
||||
spaceAroundTcl := " " + tcl + " "
|
||||
if strings.Contains(classes, spaceAroundTcl) {
|
||||
classes = strings.ReplaceAll(classes, spaceAroundTcl, " ")
|
||||
if strings.Contains(classes, " "+tcl+" ") {
|
||||
classes = removeClassFromClasses(classes, tcl)
|
||||
} else {
|
||||
classes += tcl + " "
|
||||
}
|
||||
@@ -205,6 +204,20 @@ func (s *Selection) ToggleClass(class ...string) *Selection {
|
||||
return s
|
||||
}
|
||||
|
||||
// removeClassFromClasses removes every occurrence of cl from the normalized
|
||||
// class string. One ReplaceAll pass is not enough: adjacent occurrences
|
||||
// share the space between them, so " a a " holds only one " a ".
|
||||
func removeClassFromClasses(classes, cl string) string {
|
||||
target := " " + cl + " "
|
||||
for {
|
||||
replaced := strings.Replace(classes, target, " ", 1)
|
||||
if replaced == classes {
|
||||
return classes
|
||||
}
|
||||
classes = replaced
|
||||
}
|
||||
}
|
||||
|
||||
func getAttributePtr(attrName string, n *html.Node) *html.Attribute {
|
||||
if n == nil {
|
||||
return nil
|
||||
|
||||
@@ -250,3 +250,62 @@ func TestToggleClass(t *testing.T) {
|
||||
t.Errorf("Expected #nf1 to have no classes, have %q", a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveClassRepeatedInSource(t *testing.T) {
|
||||
cases := []struct {
|
||||
class string
|
||||
remove string
|
||||
expected string
|
||||
}{
|
||||
{"a a", "a", ""},
|
||||
{"a a a", "a", ""},
|
||||
{"a b a", "a", "b"},
|
||||
{"a b a b", "a", "b b"},
|
||||
{"a b a b", "a b", ""},
|
||||
{"a a b", "a", "b"},
|
||||
{"b a a", "a", "b"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
doc, err := NewDocumentFromReader(strings.NewReader(`<div id="t" class="` + c.class + `"></div>`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sel := doc.Find("#t")
|
||||
sel.RemoveClass(c.remove)
|
||||
|
||||
got, _ := sel.Attr("class")
|
||||
if got != c.expected {
|
||||
t.Errorf("class=%q RemoveClass(%q): got class %q, want %q", c.class, c.remove, got, c.expected)
|
||||
}
|
||||
|
||||
for _, removed := range strings.Fields(c.remove) {
|
||||
if sel.HasClass(removed) {
|
||||
t.Errorf("class=%q RemoveClass(%q): still has class %q", c.class, c.remove, removed)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToggleClassRepeatedInSource(t *testing.T) {
|
||||
doc, err := NewDocumentFromReader(strings.NewReader(`<div id="t" class="a a b"></div>`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sel := doc.Find("#t")
|
||||
|
||||
sel.ToggleClass("a")
|
||||
if sel.HasClass("a") {
|
||||
t.Error("expected #t to not have class a after toggling it off")
|
||||
}
|
||||
if !sel.HasClass("b") {
|
||||
t.Error("expected #t to keep class b")
|
||||
}
|
||||
|
||||
sel.ToggleClass("a")
|
||||
if !sel.HasClass("a") {
|
||||
t.Error("expected #t to have class a after toggling it back on")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package goquery
|
||||
|
||||
import "golang.org/x/net/html"
|
||||
import (
|
||||
"slices"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
// Is checks the current matched set of elements against a selector and
|
||||
// returns true if at least one of these elements matches.
|
||||
@@ -11,12 +15,7 @@ func (s *Selection) Is(selector string) bool {
|
||||
// IsMatcher checks the current matched set of elements against a matcher and
|
||||
// returns true if at least one of these elements matches.
|
||||
func (s *Selection) IsMatcher(m Matcher) bool {
|
||||
for _, n := range s.Nodes {
|
||||
if m.Match(n) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return slices.ContainsFunc(s.Nodes, m.Match)
|
||||
}
|
||||
|
||||
// IsFunction checks the current matched set of elements against a predicate and
|
||||
|
||||
Reference in New Issue
Block a user