1
0
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:
Adam Argo
2018-10-08 20:07:08 -07:00
committed by Tim Voronov
parent 05a7582bba
commit 3829dffb91
4 changed files with 112 additions and 59 deletions

View File

@@ -3,6 +3,10 @@ package dynamic
import (
"context"
"fmt"
"hash/fnv"
"sync"
"time"
"github.com/MontFerret/ferret/pkg/html/dynamic/eval"
"github.com/MontFerret/ferret/pkg/html/dynamic/events"
"github.com/MontFerret/ferret/pkg/runtime/core"
@@ -10,13 +14,11 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/mafredri/cdp"
"github.com/mafredri/cdp/protocol/dom"
"github.com/mafredri/cdp/protocol/input"
"github.com/mafredri/cdp/protocol/page"
"github.com/mafredri/cdp/rpcc"
"github.com/pkg/errors"
"github.com/rs/zerolog"
"hash/fnv"
"sync"
"time"
)
const BlankPageURL = "about:blank"
@@ -416,27 +418,21 @@ func (doc *HTMLDocument) ClickBySelectorAll(selector values.String) (values.Bool
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(
doc.client,
fmt.Sprintf(
`
fmt.Sprintf(`
var el = document.querySelector(%s);
if (el == null) {
return false;
}
var evt = new window.Event('input', { bubbles: true });
el.value = %s
el.dispatchEvent(evt);
el.focus();
return true;
`,
eval.ParamString(selector.String()),
eval.ParamString(value.String()),
),
`, eval.ParamString(selector.String())),
true,
false,
)
@@ -445,11 +441,25 @@ func (doc *HTMLDocument) InputBySelector(selector values.String, value core.Valu
return values.False, err
}
if res.Type() == core.BooleanType {
return res.(values.Boolean), nil
if res.Type() == core.BooleanType && res.(values.Boolean) == values.False {
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 {

View File

@@ -3,6 +3,12 @@ package dynamic
import (
"context"
"encoding/json"
"hash/fnv"
"strconv"
"strings"
"sync"
"time"
"github.com/MontFerret/ferret/pkg/html/common"
"github.com/MontFerret/ferret/pkg/html/dynamic/eval"
"github.com/MontFerret/ferret/pkg/html/dynamic/events"
@@ -10,12 +16,8 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/mafredri/cdp"
"github.com/mafredri/cdp/protocol/dom"
"github.com/mafredri/cdp/protocol/input"
"github.com/rs/zerolog"
"hash/fnv"
"strconv"
"strings"
"sync"
"time"
)
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")
}
func (el *HTMLElement) Input(value core.Value) error {
func (el *HTMLElement) Input(value core.Value, delay values.Int) error {
ctx, cancel := contextWithTimeout()
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 {

View File

@@ -2,71 +2,92 @@ package html
import (
"context"
"github.com/MontFerret/ferret/pkg/html/dynamic"
"github.com/MontFerret/ferret/pkg/runtime/core"
"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 valueOrSelector (String) - Selector or a value.
* @param value (String) - Target value.
* @param delay (Int, optional) - Waits delay milliseconds between keystrokes
* @returns (Boolean) - Returns true if an element was found.
*/
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 {
return values.None, err
}
// TYPE(el, "foobar")
if len(args) == 2 {
arg1 := args[0]
arg1 := args[0]
err = core.ValidateType(arg1, core.HTMLDocumentType, core.HTMLElementType)
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 {
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)
if !ok {
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 {
return values.False, err
}
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])
}