From 437a1dc2a14db009457c73d191519cc841699d1c Mon Sep 17 00:00:00 2001 From: Martin Angers Date: Thu, 30 Aug 2012 22:47:12 -0400 Subject: [PATCH] work on filter.go, needs tests now --- doc.go | 4 +-- filter.go | 91 +++++++++++++++++++++++++++++++++++----------------- query.go | 18 +++++++++++ utilities.go | 18 ----------- 4 files changed, 81 insertions(+), 50 deletions(-) diff --git a/doc.go b/doc.go index 49d99af..504eafe 100644 --- a/doc.go +++ b/doc.go @@ -41,7 +41,7 @@ https://github.com/puerkitobio/goquery package goquery // DONE array.go : Positional Manipulation: First(), Last(), Eq(), Get(), Index(), Slice() -// filter.go : Filtering: Filter(), Not(), Has(), End() +// TESTS filter.go : Filtering: Filter(), Not(), Has(), End() // expand.go : "Expanding": Add(), AndSelf() // query.go : Reflect (query) node: Is(), Contains(), HasClass() // property.go : Inspect node: Contents(), Html(), Text(), Attr(), Val(), Length(), Size() @@ -62,7 +62,7 @@ package goquery // x Contains() (static function?) - Utilities - needs tests // - Contents() (similar to Children(), but includes text and comment nodes, so Children() should filter them out) - Misc. Traversing // x Each() - Traversing -// - End() - Misc. Traversing +// x End() - Misc. Traversing // x Eq() - Filtering // x Filter() - Filtering // x Find() : Complete with Selection object and Node object as selectors - Tree Traversal diff --git a/filter.go b/filter.go index 09607d5..d29251b 100644 --- a/filter.go +++ b/filter.go @@ -5,42 +5,98 @@ import ( "exp/html" ) +// Filter() reduces the set of matched elements to those that match the selector string. +// It returns a new Selection object for this subset of matching elements. func (this *Selection) Filter(selector string) *Selection { return pushStack(this, winnow(this, selector, true)) } +// Not() removes elements from the Selection that match the selector string. +// It returns a new Selection object with the matching elements removed. func (this *Selection) Not(selector string) *Selection { return pushStack(this, winnow(this, selector, false)) } +// FilterFunction() reduces the set of matched elements to those that pass the function's test. +// It returns a new Selection object for this subset of elements. func (this *Selection) FilterFunction(f func(int, *Selection) bool) *Selection { return pushStack(this, winnowFunction(this, f, true)) } +// Not() removes elements from the Selection that pass the function's test. +// It returns a new Selection object with the matching elements removed. func (this *Selection) NotFunction(f func(int, *Selection) bool) *Selection { return pushStack(this, winnowFunction(this, f, false)) } +// FilterNodes() reduces the set of matched elements to those that match the specified nodes. +// It returns a new Selection object for this subset of elements. func (this *Selection) FilterNodes(nodes ...*html.Node) *Selection { return pushStack(this, winnowNodes(this, nodes, true)) } +// Not() removes elements from the Selection that match the specified nodes. +// It returns a new Selection object with the matching elements removed. func (this *Selection) NotNodes(nodes ...*html.Node) *Selection { 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. +// It returns a new Selection object for this subset of elements. func (this *Selection) FilterSelection(s *Selection) *Selection { return pushStack(this, winnowNodes(this, s.Nodes, true)) } +// 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. func (this *Selection) NotSelection(s *Selection) *Selection { return pushStack(this, winnowNodes(this, s.Nodes, false)) } +// Union() is an alias for FilterSelection(). func (this *Selection) Union(s *Selection) *Selection { return this.FilterSelection(s) } +// 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. +func (this *Selection) Has(selector string) *Selection { + sel := 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. +// It returns a new Selection object with the matching elements. +func (this *Selection) HasNodes(nodes ...*html.Node) *Selection { + return this.FilterFunction(func(_ int, s *Selection) bool { + // Add all nodes that contain one of the specified nodes + for _, n := range nodes { + if s.Contains(n) { + return true + } + } + return false + }) +} + +// HasSelection() reduces the set of matched elements to those that have a descendant that matches one of +// the nodes of the specified Selection object. +// It returns a new Selection object with the matching elements. +func (this *Selection) HasSelection(sel *Selection) *Selection { + return this.HasNodes(sel.Nodes...) +} + +// End() ends the most recent filtering operation in the current chain and returns +// the set of matched elements to its previous state. +func (this *Selection) End() *Selection { + if this.prevSel != nil { + return this.prevSel + } + return newEmptySelection(this.document) +} + +// Filter based on a selector string, and the indicator to keep (Filter) or +// to get rid of (Not) the matching elements. func winnow(sel *Selection, selector string, keep bool) []*html.Node { cs := cascadia.MustCompile(selector) @@ -50,49 +106,24 @@ func winnow(sel *Selection, selector string, keep bool) []*html.Node { } else { // Use grep return grep(sel, func(i int, s *Selection) bool { - return !cs(s.Get(0)) + return !cs.Match(s.Get(0)) }) } return nil } +// Filter based on an array of nodes, and the indicator to keep (Filter) or +// to get rid of (Not) the matching elements. func winnowNodes(sel *Selection, nodes []*html.Node, keep bool) []*html.Node { return grep(sel, func(i int, s *Selection) bool { return isInSlice(nodes, s.Get(0)) == keep }) } -// Identical functionality for FilterFunction() and NotFunction(), only keep changes. +// Filter based on a function test, and the indicator to keep (Filter) or +// to get rid of (Not) the matching elements. func winnowFunction(sel *Selection, f func(int, *Selection) bool, keep bool) []*html.Node { return grep(sel, func(i int, s *Selection) bool { return f(i, s) == keep }) } - -func (this *Selection) Has(selector string) *Selection { - sel := this.document.Find(selector) - - return this.HasSelection(sel) -} - -func (this *Selection) HasNode(node *html.Node) *Selection { - return this.FilterFunction(func(_ int, s *Selection) bool { - // Add all nodes that contain the node specified - if s.Contains(node) { - return true - } - return false - }) -} - -func (this *Selection) HasSelection(sel *Selection) *Selection { - return this.FilterFunction(func(_ int, s *Selection) bool { - // Add all nodes that contain one of the nodes in the selection - for _, n := range sel.Nodes { - if s.Contains(n) { - return true - } - } - return false - }) -} diff --git a/query.go b/query.go index ba89293..a7de052 100644 --- a/query.go +++ b/query.go @@ -24,3 +24,21 @@ func (this *Selection) HasClass(class string) bool { } return false } + +// Contains() returns true if the specified Node is within, +// at any depth, one of the nodes in the Selection object. +// It is NOT inclusive, to behave like jQuery's implementation, and +// unlike Javascript's .contains(), so if the contained +// node is itself in the selection, it returns false. +func (this *Selection) Contains(n *html.Node) bool { + return sliceContains(this.Nodes, n) +} + +// Contains() returns true if the specified Node is within, +// at any depth, the root node of the Document object. +// It is NOT inclusive, to behave like jQuery's implementation, and +// unlike Javascript's .contains(), so if the contained +// node is itself in the selection, it returns false. +func (this *Document) Contains(n *html.Node) bool { + return sliceContains([]*html.Node{this.Root}, n) +} diff --git a/utilities.go b/utilities.go index 61490fc..7fcb1bb 100644 --- a/utilities.go +++ b/utilities.go @@ -4,24 +4,6 @@ import ( "exp/html" ) -// Contains() returns true if the specified Node is within, -// at any depth, one of the nodes in the Selection object. -// It is NOT inclusive, to behave like jQuery's implementation, and -// unlike Javascript's .contains(), so if the contained -// node is itself in the selection, it returns false. -func (this *Selection) Contains(n *html.Node) bool { - return sliceContains(this.Nodes, n) -} - -// Contains() returns true if the specified Node is within, -// at any depth, the root node of the Document object. -// It is NOT inclusive, to behave like jQuery's implementation, and -// unlike Javascript's .contains(), so if the contained -// node is itself in the selection, it returns false. -func (this *Document) Contains(n *html.Node) bool { - return sliceContains([]*html.Node{this.Root}, n) -} - // Loop through all container nodes to search for the target node. func sliceContains(container []*html.Node, contained *html.Node) bool { for _, n := range container {