feat(browser): auto-commit con 44 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
package browser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// CdpFrame representa un frame/iframe del arbol de navegacion.
|
||||
type CdpFrame struct {
|
||||
ID string `json:"id"`
|
||||
ParentID string `json:"parentId"`
|
||||
URL string `json:"url"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// CdpListFrames lista todos los frames de la pagina actual (frame raiz + iframes anidados)
|
||||
// usando Page.getFrameTree. Retorna el arbol aplanado con cada frame y su parentId.
|
||||
func CdpListFrames(c *CDPConn) ([]CdpFrame, error) {
|
||||
if c == nil {
|
||||
return nil, fmt.Errorf("cdp list frames: conexion nula")
|
||||
}
|
||||
|
||||
// Page.enable es idempotente; necesario para que Page.getFrameTree funcione
|
||||
if _, err := c.sendCDP("Page.enable", nil); err != nil {
|
||||
return nil, fmt.Errorf("cdp list frames: Page.enable: %w", err)
|
||||
}
|
||||
|
||||
result, err := c.sendCDP("Page.getFrameTree", nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cdp list frames: Page.getFrameTree: %w", err)
|
||||
}
|
||||
|
||||
frameTree, ok := result["frameTree"].(map[string]any)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cdp list frames: frameTree no encontrado en respuesta")
|
||||
}
|
||||
|
||||
var frames []CdpFrame
|
||||
frameFlatten(frameTree, "", &frames)
|
||||
return frames, nil
|
||||
}
|
||||
|
||||
// frameFlatten recorre recursivamente el arbol de frames CDP y acumula CdpFrame.
|
||||
// parentID es el ID del nodo padre; el frame raiz lo recibe vacio.
|
||||
func frameFlatten(node map[string]any, parentID string, acc *[]CdpFrame) {
|
||||
frameData, ok := node["frame"].(map[string]any)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
f := CdpFrame{
|
||||
ID: stringField(frameData, "id"),
|
||||
ParentID: parentID,
|
||||
URL: stringField(frameData, "url"),
|
||||
Name: stringField(frameData, "name"),
|
||||
}
|
||||
*acc = append(*acc, f)
|
||||
|
||||
// Recorrer hijos
|
||||
children, _ := node["childFrames"].([]any)
|
||||
for _, child := range children {
|
||||
childNode, ok := child.(map[string]any)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
frameFlatten(childNode, f.ID, acc)
|
||||
}
|
||||
}
|
||||
|
||||
// stringField extrae un campo string de un map[string]any de forma segura.
|
||||
func stringField(m map[string]any, key string) string {
|
||||
v, _ := m[key].(string)
|
||||
return v
|
||||
}
|
||||
Reference in New Issue
Block a user