New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enable filtering visible nodes as an option #636
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,6 +34,7 @@ type Selector struct { | |
by func(context.Context, *cdp.Node) ([]cdp.NodeID, error) | ||
wait func(context.Context, *cdp.Frame, ...cdp.NodeID) ([]*cdp.Node, error) | ||
after func(context.Context, ...*cdp.Node) error | ||
filter func(context.Context, *cdp.Node) (bool, error) | ||
raw bool | ||
} | ||
|
||
|
@@ -194,6 +195,24 @@ func (s *Selector) Do(ctx context.Context) error { | |
if nodes == nil || err != nil { | ||
continue | ||
} | ||
|
||
if s.filter != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, we should think about moving this before "wait" in the future, but that would require an API-breaking refactor. because, ideally, the steps would be:
This is useful, because imagine if you wanted to do We don't have to do this change here, but I would add a TODO. |
||
for i, node := range nodes { | ||
is, err := s.filter(ctx, node) | ||
if err != nil { | ||
continue | ||
} | ||
|
||
if !is { | ||
nodes = append(nodes[0:i], nodes[i+1:]...) | ||
} | ||
|
||
if len(nodes) < s.exp { | ||
continue | ||
} | ||
} | ||
} | ||
|
||
if s.after != nil { | ||
if err := s.after(ctx, nodes...); err != nil { | ||
return err | ||
|
@@ -277,6 +296,12 @@ func ByFunc(f func(context.Context, *cdp.Node) ([]cdp.NodeID, error)) QueryOptio | |
} | ||
} | ||
|
||
func FilterFunc(f func(context.Context, *cdp.Node) (bool, error)) QueryOption { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this needs docs |
||
return func(s *Selector) { | ||
s.filter = f | ||
} | ||
} | ||
|
||
// ByQuery is an element query action option to select a single element by the | ||
// DOM.querySelector command. | ||
// | ||
|
@@ -416,23 +441,11 @@ func NodeReady(s *Selector) { | |
// nodes have been sent by the browser and are visible. | ||
func NodeVisible(s *Selector) { | ||
WaitFunc(s.waitReady(func(ctx context.Context, n *cdp.Node) error { | ||
// check box model | ||
_, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(ctx) | ||
if err != nil { | ||
if isCouldNotComputeBoxModelError(err) { | ||
return ErrNotVisible | ||
} | ||
|
||
return err | ||
} | ||
|
||
// check visibility | ||
var res bool | ||
err = EvaluateAsDevTools(snippet(visibleJS, cashX(true), s, n), &res).Do(ctx) | ||
visible, err := isNodeVisible(ctx, n, s) | ||
if err != nil { | ||
return err | ||
} | ||
if !res { | ||
if !visible { | ||
return ErrNotVisible | ||
} | ||
return nil | ||
|
@@ -443,29 +456,24 @@ func NodeVisible(s *Selector) { | |
// nodes have been sent by the browser and are not visible. | ||
func NodeNotVisible(s *Selector) { | ||
WaitFunc(s.waitReady(func(ctx context.Context, n *cdp.Node) error { | ||
// check box model | ||
_, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(ctx) | ||
if err != nil { | ||
if isCouldNotComputeBoxModelError(err) { | ||
return nil | ||
} | ||
|
||
return err | ||
} | ||
|
||
// check visibility | ||
var res bool | ||
err = EvaluateAsDevTools(snippet(visibleJS, cashX(true), s, n), &res).Do(ctx) | ||
visible, err := isNodeVisible(ctx, n, s) | ||
if err != nil { | ||
return err | ||
} | ||
if res { | ||
if visible { | ||
return ErrVisible | ||
} | ||
return nil | ||
}))(s) | ||
} | ||
|
||
func FilterVisible(s *Selector) { | ||
FilterFunc(func(ctx context.Context, n *cdp.Node) (b bool, err error) { | ||
b, e := isNodeVisible(ctx, n, s) | ||
return b,e | ||
})(s) | ||
} | ||
|
||
// NodeEnabled is an element query option to wait until all queried element | ||
// nodes have been sent by the browser and are enabled (ie, do not have a | ||
// 'disabled' attribute). | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package chromedp | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this file is tiny, I would not add it. just add the funcs elsewhere like util.go, even though I hate that name. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why are small files a problem? |
||
|
||
import ( | ||
"context" | ||
"github.com/chromedp/cdproto" | ||
"github.com/chromedp/cdproto/cdp" | ||
"github.com/chromedp/cdproto/dom" | ||
) | ||
|
||
// isCouldNotComputeBoxModelError unwraps err as a MessageError and determines | ||
// if it is a compute box model error. | ||
func isCouldNotComputeBoxModelError(err error) bool { | ||
e, ok := err.(*cdproto.Error) | ||
return ok && e.Code == -32000 && e.Message == "Could not compute box model." | ||
} | ||
|
||
func isNodeVisible(ctx context.Context, n *cdp.Node, s *Selector) (bool, error) { | ||
// check box model | ||
_, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(ctx) | ||
if err != nil { | ||
if isCouldNotComputeBoxModelError(err) { | ||
return false, nil | ||
} | ||
|
||
return false, err | ||
} | ||
|
||
// check visibility | ||
var res bool | ||
err = EvaluateAsDevTools(snippet(visibleJS, cashX(true), s, n), &res).Do(ctx) | ||
if err != nil { | ||
return false, err | ||
} | ||
if !res { | ||
return false, nil | ||
} | ||
return true, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move this before wait