fix: remove every occurrence of a repeated class

RemoveClass deleted each class with one strings.ReplaceAll pass over the
space-wrapped class list. Two adjacent occurrences share the space
between them, so " a a " holds only one non-overlapping " a " and the
second survived: RemoveClass("a") on class="a a" returned with
HasClass("a") still true. ToggleClass used the same expression and so
toggled such a class the wrong way.

Replace one occurrence at a time, re-scanning from the start, in a helper
shared by both call sites. Whitespace between the remaining classes is
untouched.
This commit is contained in:
dualfroz committed 2026-09-04 07:52:26 +02:00
1 parent 445cd7eabe
commit 048bc98ddf
2 files changed
+81 -4

No files matched your search

+22 -4
View File
@@ -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,25 @@ func (s *Selection) ToggleClass(class ...string) *Selection {
return s
}
// removeClassFromClasses removes every occurrence of cl from the normalized
// class string (a class list wrapped in spaces, as returned by
// getClassesAndAttr).
//
// A single strings.ReplaceAll pass is not enough: two adjacent occurrences
// share the space between them, so " a a " contains only one non-overlapping
// " a " and the second one survives the replacement. Replacing one at a time
// re-scans from the start and reaches it.
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