package browser import ( "fmt" "strconv" "strings" ) // CdpClick hace click en el primer elemento que coincide con el selector CSS. // Obtiene las coordenadas del elemento via Runtime.evaluate y luego despacha // eventos mousedown, mouseup y click via Input.dispatchMouseEvent. func CdpClick(c *CDPConn, selector string) error { if c == nil { return fmt.Errorf("cdp click: conexion nula") } // Obtener coordenadas del centro del elemento js := fmt.Sprintf(`(function() { var el = document.querySelector(%q); if (!el) return null; var r = el.getBoundingClientRect(); return JSON.stringify({x: r.left + r.width/2, y: r.top + r.height/2}); })()`, selector) coordStr, err := CdpEvaluate(c, js) if err != nil { return fmt.Errorf("cdp click: obtener coordenadas de %q: %w", selector, err) } if coordStr == "" || coordStr == "null" { return fmt.Errorf("cdp click: elemento %q no encontrado en el DOM", selector) } // Parsear "{x:...,y:...}" — CdpEvaluate ya retorna el JSON como string coordStr = strings.Trim(coordStr, `"`) x, y, err := parseCoords(coordStr) if err != nil { return fmt.Errorf("cdp click: parsear coordenadas %q: %w", coordStr, err) } // Hacer scroll al elemento para que este visible scrollJS := fmt.Sprintf(`document.querySelector(%q).scrollIntoView({block:'center'})`, selector) if _, err := CdpEvaluate(c, scrollJS); err != nil { // No es fatal si el scroll falla _ = err } // Despachar mousedown mouseParams := map[string]any{ "type": "mousePressed", "x": x, "y": y, "button": "left", "clickCount": 1, } if _, err := c.sendCDP("Input.dispatchMouseEvent", mouseParams); err != nil { return fmt.Errorf("cdp click: mousedown: %w", err) } // Despachar mouseup mouseParams["type"] = "mouseReleased" if _, err := c.sendCDP("Input.dispatchMouseEvent", mouseParams); err != nil { return fmt.Errorf("cdp click: mouseup: %w", err) } return nil } // parseCoords extrae x e y de un string JSON como {"x":100,"y":200}. func parseCoords(s string) (float64, float64, error) { // Buscar valores x e y manualmente para evitar dependencia de encoding/json s = strings.TrimSpace(s) s = strings.TrimPrefix(s, "{") s = strings.TrimSuffix(s, "}") var x, y float64 for part := range strings.SplitSeq(s, ",") { kv := strings.SplitN(strings.TrimSpace(part), ":", 2) if len(kv) != 2 { continue } k := strings.Trim(strings.TrimSpace(kv[0]), `"`) v, err := strconv.ParseFloat(strings.TrimSpace(kv[1]), 64) if err != nil { return 0, 0, fmt.Errorf("parsear valor %q: %w", kv[1], err) } switch k { case "x": x = v case "y": y = v } } return x, y, nil }