mirror of
https://github.com/MontFerret/ferret.git
synced 2025-11-06 08:39:09 +02:00
Adds function to type value into input (#81)
* adds function to type input * changes per feedback * more PR feedback changes * add context.Background()
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
LET g = DOCUMENT("https://www.google.com/", true)
|
LET g = DOCUMENT("https://www.google.com/", true)
|
||||||
|
|
||||||
INPUT(g, 'input[name="q"]', "ferret")
|
INPUT(g, 'input[name="q"]', "ferret", 25)
|
||||||
CLICK(g, 'input[name="btnK"]')
|
CLICK(g, 'input[name="btnK"]')
|
||||||
|
|
||||||
WAIT_NAVIGATION(g)
|
WAIT_NAVIGATION(g)
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ package dynamic
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"hash/fnv"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/MontFerret/ferret/pkg/html/dynamic/eval"
|
"github.com/MontFerret/ferret/pkg/html/dynamic/eval"
|
||||||
"github.com/MontFerret/ferret/pkg/html/dynamic/events"
|
"github.com/MontFerret/ferret/pkg/html/dynamic/events"
|
||||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||||
@@ -10,13 +14,11 @@ import (
|
|||||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||||
"github.com/mafredri/cdp"
|
"github.com/mafredri/cdp"
|
||||||
"github.com/mafredri/cdp/protocol/dom"
|
"github.com/mafredri/cdp/protocol/dom"
|
||||||
|
"github.com/mafredri/cdp/protocol/input"
|
||||||
"github.com/mafredri/cdp/protocol/page"
|
"github.com/mafredri/cdp/protocol/page"
|
||||||
"github.com/mafredri/cdp/rpcc"
|
"github.com/mafredri/cdp/rpcc"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"hash/fnv"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const BlankPageURL = "about:blank"
|
const BlankPageURL = "about:blank"
|
||||||
@@ -416,27 +418,21 @@ func (doc *HTMLDocument) ClickBySelectorAll(selector values.String) (values.Bool
|
|||||||
return values.False, nil
|
return values.False, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (doc *HTMLDocument) InputBySelector(selector values.String, value core.Value) (values.Boolean, error) {
|
func (doc *HTMLDocument) InputBySelector(selector values.String, value core.Value, delay values.Int) (values.Boolean, error) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
valStr := value.String()
|
||||||
|
|
||||||
res, err := eval.Eval(
|
res, err := eval.Eval(
|
||||||
doc.client,
|
doc.client,
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(`
|
||||||
`
|
|
||||||
var el = document.querySelector(%s);
|
var el = document.querySelector(%s);
|
||||||
|
|
||||||
if (el == null) {
|
if (el == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
el.focus();
|
||||||
var evt = new window.Event('input', { bubbles: true });
|
|
||||||
|
|
||||||
el.value = %s
|
|
||||||
el.dispatchEvent(evt);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
`,
|
`, eval.ParamString(selector.String())),
|
||||||
eval.ParamString(selector.String()),
|
|
||||||
eval.ParamString(value.String()),
|
|
||||||
),
|
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
@@ -445,11 +441,25 @@ func (doc *HTMLDocument) InputBySelector(selector values.String, value core.Valu
|
|||||||
return values.False, err
|
return values.False, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if res.Type() == core.BooleanType {
|
if res.Type() == core.BooleanType && res.(values.Boolean) == values.False {
|
||||||
return res.(values.Boolean), nil
|
return values.False, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return values.False, nil
|
delayMs := time.Duration(delay)
|
||||||
|
|
||||||
|
time.Sleep(delayMs * time.Millisecond)
|
||||||
|
|
||||||
|
for _, ch := range valStr {
|
||||||
|
for _, ev := range []string{"keyDown", "keyUp"} {
|
||||||
|
ke := input.NewDispatchKeyEventArgs(ev).SetText(string(ch))
|
||||||
|
if err := doc.client.Input.DispatchKeyEvent(ctx, ke); err != nil {
|
||||||
|
return values.False, err
|
||||||
|
}
|
||||||
|
time.Sleep(delayMs * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return values.True, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (doc *HTMLDocument) WaitForSelector(selector values.String, timeout values.Int) error {
|
func (doc *HTMLDocument) WaitForSelector(selector values.String, timeout values.Int) error {
|
||||||
|
|||||||
@@ -3,6 +3,12 @@ package dynamic
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"hash/fnv"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/MontFerret/ferret/pkg/html/common"
|
"github.com/MontFerret/ferret/pkg/html/common"
|
||||||
"github.com/MontFerret/ferret/pkg/html/dynamic/eval"
|
"github.com/MontFerret/ferret/pkg/html/dynamic/eval"
|
||||||
"github.com/MontFerret/ferret/pkg/html/dynamic/events"
|
"github.com/MontFerret/ferret/pkg/html/dynamic/events"
|
||||||
@@ -10,12 +16,8 @@ import (
|
|||||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||||
"github.com/mafredri/cdp"
|
"github.com/mafredri/cdp"
|
||||||
"github.com/mafredri/cdp/protocol/dom"
|
"github.com/mafredri/cdp/protocol/dom"
|
||||||
|
"github.com/mafredri/cdp/protocol/input"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"hash/fnv"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const DefaultTimeout = time.Second * 30
|
const DefaultTimeout = time.Second * 30
|
||||||
@@ -586,11 +588,31 @@ func (el *HTMLElement) Click() (values.Boolean, error) {
|
|||||||
return events.DispatchEvent(ctx, el.client, el.id, "click")
|
return events.DispatchEvent(ctx, el.client, el.id, "click")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (el *HTMLElement) Input(value core.Value) error {
|
func (el *HTMLElement) Input(value core.Value, delay values.Int) error {
|
||||||
ctx, cancel := contextWithTimeout()
|
ctx, cancel := contextWithTimeout()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
return el.client.DOM.SetAttributeValue(ctx, dom.NewSetAttributeValueArgs(el.id, "value", value.String()))
|
if err := el.client.DOM.Focus(ctx, dom.NewFocusArgs().SetNodeID(el.id)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
delayMs := time.Duration(delay)
|
||||||
|
|
||||||
|
time.Sleep(delayMs * time.Millisecond)
|
||||||
|
|
||||||
|
valStr := value.String()
|
||||||
|
|
||||||
|
for _, ch := range valStr {
|
||||||
|
for _, ev := range []string{"keyDown", "keyUp"} {
|
||||||
|
ke := input.NewDispatchKeyEventArgs(ev).SetText(string(ch))
|
||||||
|
if err := el.client.Input.DispatchKeyEvent(ctx, ke); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
time.Sleep(delayMs * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (el *HTMLElement) IsConnected() values.Boolean {
|
func (el *HTMLElement) IsConnected() values.Boolean {
|
||||||
|
|||||||
@@ -2,71 +2,92 @@ package html
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/MontFerret/ferret/pkg/html/dynamic"
|
"github.com/MontFerret/ferret/pkg/html/dynamic"
|
||||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sends a value to an underlying input element.
|
* Types a value to an underlying input element.
|
||||||
* @param source (Document | Element) - Event target.
|
* @param source (Document | Element) - Event target.
|
||||||
* @param valueOrSelector (String) - Selector or a value.
|
* @param valueOrSelector (String) - Selector or a value.
|
||||||
* @param value (String) - Target value.
|
* @param value (String) - Target value.
|
||||||
|
* @param delay (Int, optional) - Waits delay milliseconds between keystrokes
|
||||||
* @returns (Boolean) - Returns true if an element was found.
|
* @returns (Boolean) - Returns true if an element was found.
|
||||||
*/
|
*/
|
||||||
func Input(_ context.Context, args ...core.Value) (core.Value, error) {
|
func Input(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||||
err := core.ValidateArgs(args, 2, 3)
|
err := core.ValidateArgs(args, 2, 4)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return values.None, err
|
return values.None, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TYPE(el, "foobar")
|
arg1 := args[0]
|
||||||
if len(args) == 2 {
|
err = core.ValidateType(arg1, core.HTMLDocumentType, core.HTMLElementType)
|
||||||
arg1 := args[0]
|
|
||||||
|
|
||||||
err := core.ValidateType(arg1, core.HTMLElementType)
|
if err != nil {
|
||||||
|
return values.False, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch args[0].(type) {
|
||||||
|
case *dynamic.HTMLDocument:
|
||||||
|
|
||||||
|
doc, ok := arg1.(*dynamic.HTMLDocument)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return values.False, core.Errors(core.ErrInvalidType, ErrNotDynamic)
|
||||||
|
}
|
||||||
|
|
||||||
|
// selector
|
||||||
|
arg2 := args[1]
|
||||||
|
err = core.ValidateType(arg2, core.StringType)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return values.False, err
|
return values.False, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delay := values.Int(0)
|
||||||
|
if len(args) == 4 {
|
||||||
|
arg4 := args[3]
|
||||||
|
|
||||||
|
err = core.ValidateType(arg4, core.IntType)
|
||||||
|
if err != nil {
|
||||||
|
return values.False, err
|
||||||
|
}
|
||||||
|
|
||||||
|
delay = arg4.(values.Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
return doc.InputBySelector(arg2.(values.String), args[2], delay)
|
||||||
|
|
||||||
|
case *dynamic.HTMLElement:
|
||||||
el, ok := arg1.(*dynamic.HTMLElement)
|
el, ok := arg1.(*dynamic.HTMLElement)
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return values.False, core.Errors(core.ErrInvalidType, ErrNotDynamic)
|
return values.False, core.Errors(core.ErrInvalidType, ErrNotDynamic)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = el.Input(args[1])
|
delay := values.Int(0)
|
||||||
|
if len(args) == 3 {
|
||||||
|
arg3 := args[2]
|
||||||
|
|
||||||
|
err = core.ValidateType(arg3, core.IntType)
|
||||||
|
if err != nil {
|
||||||
|
return values.False, err
|
||||||
|
}
|
||||||
|
|
||||||
|
delay = arg3.(values.Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = el.Input(args[1], delay)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return values.False, err
|
return values.False, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return values.True, nil
|
return values.True, nil
|
||||||
|
default:
|
||||||
|
return values.False, core.Errors(core.ErrInvalidArgument)
|
||||||
}
|
}
|
||||||
|
|
||||||
arg1 := args[0]
|
|
||||||
|
|
||||||
err = core.ValidateType(arg1, core.HTMLDocumentType)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return values.False, err
|
|
||||||
}
|
|
||||||
|
|
||||||
arg2 := args[1]
|
|
||||||
|
|
||||||
err = core.ValidateType(arg2, core.StringType)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return values.False, err
|
|
||||||
}
|
|
||||||
|
|
||||||
doc, ok := arg1.(*dynamic.HTMLDocument)
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
return values.False, core.Errors(core.ErrInvalidType, ErrNotDynamic)
|
|
||||||
}
|
|
||||||
|
|
||||||
return doc.InputBySelector(arg2.(values.String), args[2])
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user