bump
This commit is contained in:
166
daemon/daemon.go
166
daemon/daemon.go
@@ -450,6 +450,33 @@ func (d *Daemon) handleCommand(w http.ResponseWriter, r *http.Request) {
|
||||
response = Response{Success: true}
|
||||
}
|
||||
|
||||
case "select-element":
|
||||
tabID := cmd.Params["tab"]
|
||||
selector := cmd.Params["selector"]
|
||||
value := cmd.Params["value"]
|
||||
|
||||
// Parse timeouts
|
||||
selectionTimeout := 5 // Default: 5 seconds
|
||||
if timeoutStr, ok := cmd.Params["selection-timeout"]; ok {
|
||||
if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
|
||||
selectionTimeout = parsedTimeout
|
||||
}
|
||||
}
|
||||
|
||||
actionTimeout := 5 // Default: 5 seconds
|
||||
if timeoutStr, ok := cmd.Params["action-timeout"]; ok {
|
||||
if parsedTimeout, err := strconv.Atoi(timeoutStr); err == nil && parsedTimeout > 0 {
|
||||
actionTimeout = parsedTimeout
|
||||
}
|
||||
}
|
||||
|
||||
err := d.selectElement(tabID, selector, value, selectionTimeout, actionTimeout)
|
||||
if err != nil {
|
||||
response = Response{Success: false, Error: err.Error()}
|
||||
} else {
|
||||
response = Response{Success: true}
|
||||
}
|
||||
|
||||
case "eval-js":
|
||||
tabID := cmd.Params["tab"]
|
||||
jsCode := cmd.Params["code"]
|
||||
@@ -1904,6 +1931,55 @@ func (d *Daemon) clickElement(tabID, selector string, selectionTimeout, actionTi
|
||||
return nil
|
||||
}
|
||||
|
||||
// selectElement selects an option in a select dropdown
|
||||
func (d *Daemon) selectElement(tabID, selector, value string, selectionTimeout, actionTimeout int) error {
|
||||
page, err := d.getTab(tabID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Find the element with optional timeout
|
||||
var element *rod.Element
|
||||
if selectionTimeout > 0 {
|
||||
// Use timeout if specified
|
||||
element, err = page.Timeout(time.Duration(selectionTimeout) * time.Second).Element(selector)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find element (timeout after %ds): %w", selectionTimeout, err)
|
||||
}
|
||||
} else {
|
||||
// No timeout
|
||||
element, err = page.Element(selector)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find element: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the element is visible and scrolled into view
|
||||
err = element.ScrollIntoView()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to scroll element into view: %w", err)
|
||||
}
|
||||
|
||||
// For select elements, use rod's built-in Select method
|
||||
// Try to select by text first (most common case)
|
||||
err = element.Select([]string{value}, true, rod.SelectorTypeText)
|
||||
if err != nil {
|
||||
// If text selection failed, the value might be the actual option value
|
||||
// Try to find and select by matching option value using page.Eval
|
||||
script := fmt.Sprintf(`(function(){ var el = document.querySelector("%s"); if(el) { el.value = "%s"; el.dispatchEvent(new Event('change', { bubbles: true })); } })()`, selector, value)
|
||||
// Execute JavaScript and ignore any rod evaluation quirks
|
||||
page.Eval(script)
|
||||
|
||||
// Verify the selection worked by checking the value
|
||||
actualValue, err := element.Attribute("value")
|
||||
if err != nil || actualValue == nil || *actualValue != value {
|
||||
return fmt.Errorf("failed to select option '%s' in element", value)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// evalJS executes JavaScript code in a tab and returns the result
|
||||
func (d *Daemon) evalJS(tabID, jsCode string, timeout int) (string, error) {
|
||||
page, err := d.getTab(tabID)
|
||||
@@ -3605,7 +3681,7 @@ func (d *Daemon) fillFormBulk(tabID, formSelector, fieldsJSON string, timeout in
|
||||
for fieldName, fieldValue := range fields {
|
||||
fieldResult := InteractionResult{
|
||||
Selector: fieldName,
|
||||
Action: "fill",
|
||||
Action: "fill", // Default action, will be updated based on element type
|
||||
Success: false,
|
||||
}
|
||||
|
||||
@@ -3626,18 +3702,9 @@ func (d *Daemon) fillFormBulk(tabID, formSelector, fieldsJSON string, timeout in
|
||||
if timeout > 0 {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
|
||||
element, err = form.Context(ctx).Element(selector)
|
||||
// Don't cancel yet if element found - we need context for filling
|
||||
if err == nil {
|
||||
fieldResult.Selector = selector
|
||||
// Fill the field while context is still valid
|
||||
err = element.SelectAllText()
|
||||
if err == nil {
|
||||
err = element.Input("")
|
||||
}
|
||||
if err == nil {
|
||||
err = element.Input(fieldValue)
|
||||
}
|
||||
cancel() // Now we can cancel
|
||||
cancel() // Cancel context now that we found the element
|
||||
break
|
||||
}
|
||||
cancel() // Cancel if element not found
|
||||
@@ -3645,14 +3712,6 @@ func (d *Daemon) fillFormBulk(tabID, formSelector, fieldsJSON string, timeout in
|
||||
element, err = form.Element(selector)
|
||||
if err == nil {
|
||||
fieldResult.Selector = selector
|
||||
// Fill the field
|
||||
err = element.SelectAllText()
|
||||
if err == nil {
|
||||
err = element.Input("")
|
||||
}
|
||||
if err == nil {
|
||||
err = element.Input(fieldValue)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -3675,18 +3734,9 @@ func (d *Daemon) fillFormBulk(tabID, formSelector, fieldsJSON string, timeout in
|
||||
if timeout > 0 {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
|
||||
element, err = page.Context(ctx).Element(selector)
|
||||
// Don't cancel yet - we need the context for filling
|
||||
if err == nil {
|
||||
fieldResult.Selector = selector
|
||||
// Fill the field while context is still valid
|
||||
err = element.SelectAllText()
|
||||
if err == nil {
|
||||
err = element.Input("")
|
||||
}
|
||||
if err == nil {
|
||||
err = element.Input(fieldValue)
|
||||
}
|
||||
cancel() // Now we can cancel
|
||||
cancel() // Cancel context now that we found the element
|
||||
break
|
||||
}
|
||||
cancel() // Cancel if element not found
|
||||
@@ -3694,14 +3744,6 @@ func (d *Daemon) fillFormBulk(tabID, formSelector, fieldsJSON string, timeout in
|
||||
element, err = page.Element(selector)
|
||||
if err == nil {
|
||||
fieldResult.Selector = selector
|
||||
// Fill the field
|
||||
err = element.SelectAllText()
|
||||
if err == nil {
|
||||
err = element.Input("")
|
||||
}
|
||||
if err == nil {
|
||||
err = element.Input(fieldValue)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -3715,12 +3757,56 @@ func (d *Daemon) fillFormBulk(tabID, formSelector, fieldsJSON string, timeout in
|
||||
continue
|
||||
}
|
||||
|
||||
// Determine the element type and use appropriate action
|
||||
tagName, err := element.Eval("() => this.tagName.toLowerCase()")
|
||||
if err != nil {
|
||||
fieldResult.Error = fmt.Sprintf("failed to fill field: %v", err)
|
||||
fieldResult.Error = fmt.Sprintf("failed to get element tag name: %v", err)
|
||||
result.FilledFields = append(result.FilledFields, fieldResult)
|
||||
result.ErrorCount++
|
||||
continue
|
||||
}
|
||||
|
||||
// Handle different element types
|
||||
if tagName.Value.String() == "select" {
|
||||
// Use select action for select elements
|
||||
fieldResult.Action = "select"
|
||||
err = element.Select([]string{fieldValue}, true, rod.SelectorTypeText)
|
||||
if err != nil {
|
||||
// If text selection failed, try by value
|
||||
script := fmt.Sprintf(`(function(){ var el = document.querySelector("%s"); if(el) { el.value = "%s"; el.dispatchEvent(new Event('change', { bubbles: true })); } })()`, fieldResult.Selector, fieldValue)
|
||||
page.Eval(script)
|
||||
|
||||
// Verify the selection worked
|
||||
actualValue, err := element.Attribute("value")
|
||||
if err != nil || actualValue == nil || *actualValue != fieldValue {
|
||||
fieldResult.Error = fmt.Sprintf("failed to select option '%s'", fieldValue)
|
||||
result.ErrorCount++
|
||||
} else {
|
||||
fieldResult.Success = true
|
||||
result.SuccessCount++
|
||||
}
|
||||
} else {
|
||||
fieldResult.Success = true
|
||||
result.SuccessCount++
|
||||
}
|
||||
} else {
|
||||
fieldResult.Success = true
|
||||
result.SuccessCount++
|
||||
// Use fill action for input, textarea, etc.
|
||||
fieldResult.Action = "fill"
|
||||
err = element.SelectAllText()
|
||||
if err == nil {
|
||||
err = element.Input("")
|
||||
}
|
||||
if err == nil {
|
||||
err = element.Input(fieldValue)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fieldResult.Error = fmt.Sprintf("failed to fill field: %v", err)
|
||||
result.ErrorCount++
|
||||
} else {
|
||||
fieldResult.Success = true
|
||||
result.SuccessCount++
|
||||
}
|
||||
}
|
||||
|
||||
result.FilledFields = append(result.FilledFields, fieldResult)
|
||||
|
Reference in New Issue
Block a user