feat(webkit): add WebView state snapshot and callback registration API
Add two new public methods to WebView: - State(): Returns current WebView state (URI, title, loading status, progress, navigation state, zoom level) as a snapshot - SetCallbacks(): Registers or clears WebView event callbacks (load changed, title changed, URI changed, progress changed, close, create) Add compile-time interface check (var _ port.WebView = (*WebView)(nil)) to ensure WebView implements the port.WebView interface. These additions support the coordinator architecture and enable cleaner event handling patterns.
- commit
- 2912397dff14fe354fd50226c2c1833bf491d261
- author
- brice · · 2025-12-15 17:03 UTC
- committer
- brice · · 2025-12-15 21:06 UTC
- parent
- 33d4791
- signature
- unsigned
1 file · +61 -0
M internal/infrastructure/webkit/webview.go +61 -0
| @@ -14,6 +14,9 @@ import ( | |||
| 14 | 14 | "github.com/rs/zerolog" | |
| 15 | 15 | ) | |
| 16 | 16 | ||
| 17 | + | // Compile-time interface check: WebView must implement port.WebView. | |
| 18 | + | var _ port.WebView = (*WebView)(nil) | |
| 19 | + | ||
| 17 | 20 | // WebViewID is an alias to port.WebViewID for clean architecture compliance. | |
| 18 | 21 | // Infrastructure layer uses the type defined in the application port. | |
| 19 | 22 | type WebViewID = port.WebViewID | |
| @@ -426,6 +429,64 @@ func (wv *WebView) GetZoomLevel() float64 { | |||
| 426 | 429 | return wv.inner.GetZoomLevel() | |
| 427 | 430 | } | |
| 428 | 431 | ||
| 432 | + | // State returns the current WebView state as a snapshot. | |
| 433 | + | func (wv *WebView) State() port.WebViewState { | |
| 434 | + | return port.WebViewState{ | |
| 435 | + | URI: wv.uri, | |
| 436 | + | Title: wv.title, | |
| 437 | + | IsLoading: wv.isLoading, | |
| 438 | + | Progress: wv.progress, | |
| 439 | + | CanGoBack: wv.canGoBack, | |
| 440 | + | CanGoFwd: wv.canGoFwd, | |
| 441 | + | ZoomLevel: wv.GetZoomLevel(), | |
| 442 | + | } | |
| 443 | + | } | |
| 444 | + | ||
| 445 | + | // SetCallbacks registers callback handlers for WebView events. | |
| 446 | + | // Pass nil to clear all callbacks. | |
| 447 | + | func (wv *WebView) SetCallbacks(callbacks *port.WebViewCallbacks) { | |
| 448 | + | if callbacks == nil { | |
| 449 | + | wv.OnLoadChanged = nil | |
| 450 | + | wv.OnTitleChanged = nil | |
| 451 | + | wv.OnURIChanged = nil | |
| 452 | + | wv.OnProgressChanged = nil | |
| 453 | + | wv.OnClose = nil | |
| 454 | + | wv.OnCreate = nil | |
| 455 | + | return | |
| 456 | + | } | |
| 457 | + | ||
| 458 | + | // Map port callbacks to webkit callbacks | |
| 459 | + | if callbacks.OnLoadChanged != nil { | |
| 460 | + | wv.OnLoadChanged = func(e LoadEvent) { | |
| 461 | + | callbacks.OnLoadChanged(port.LoadEvent(e)) | |
| 462 | + | } | |
| 463 | + | } | |
| 464 | + | wv.OnTitleChanged = callbacks.OnTitleChanged | |
| 465 | + | wv.OnURIChanged = callbacks.OnURIChanged | |
| 466 | + | wv.OnProgressChanged = callbacks.OnProgressChanged | |
| 467 | + | wv.OnClose = callbacks.OnClose | |
| 468 | + | if callbacks.OnCreate != nil { | |
| 469 | + | wv.OnCreate = func(req PopupRequest) *WebView { | |
| 470 | + | portReq := port.PopupRequest{ | |
| 471 | + | TargetURI: req.TargetURI, | |
| 472 | + | FrameName: req.FrameName, | |
| 473 | + | IsUserGesture: req.IsUserGesture, | |
| 474 | + | ParentViewID: req.ParentID, | |
| 475 | + | } | |
| 476 | + | result := callbacks.OnCreate(portReq) | |
| 477 | + | if result == nil { | |
| 478 | + | return nil | |
| 479 | + | } | |
| 480 | + | // The callback returns port.WebView, we need to convert back | |
| 481 | + | // This assumes the returned WebView is actually a *webkit.WebView | |
| 482 | + | if wkView, ok := result.(*WebView); ok { | |
| 483 | + | return wkView | |
| 484 | + | } | |
| 485 | + | return nil | |
| 486 | + | } | |
| 487 | + | } | |
| 488 | + | } | |
| 489 | + | ||
| 429 | 490 | // ShowDevTools opens the WebKit inspector/developer tools. | |
| 430 | 491 | func (wv *WebView) ShowDevTools() error { | |
| 431 | 492 | if wv.destroyed.Load() { | |
| @@ -14,6 +14,9 @@ import ( | |||||
| 14 | "github.com/rs/zerolog" | 14 | "github.com/rs/zerolog" | ||
| 15 | ) | 15 | ) | ||
| 16 | 16 | ||||
| 17 | + | // Compile-time interface check: WebView must implement port.WebView. | |||
| 18 | + | var _ port.WebView = (*WebView)(nil) | |||
| 19 | + | ||||
| 17 | // WebViewID is an alias to port.WebViewID for clean architecture compliance. | 20 | // WebViewID is an alias to port.WebViewID for clean architecture compliance. | ||
| 18 | // Infrastructure layer uses the type defined in the application port. | 21 | // Infrastructure layer uses the type defined in the application port. | ||
| 19 | type WebViewID = port.WebViewID | 22 | type WebViewID = port.WebViewID | ||
| @@ -426,6 +429,64 @@ func (wv *WebView) GetZoomLevel() float64 { | |||||
| 426 | return wv.inner.GetZoomLevel() | 429 | return wv.inner.GetZoomLevel() | ||
| 427 | } | 430 | } | ||
| 428 | 431 | ||||
| 432 | + | // State returns the current WebView state as a snapshot. | |||
| 433 | + | func (wv *WebView) State() port.WebViewState { | |||
| 434 | + | return port.WebViewState{ | |||
| 435 | + | URI: wv.uri, | |||
| 436 | + | Title: wv.title, | |||
| 437 | + | IsLoading: wv.isLoading, | |||
| 438 | + | Progress: wv.progress, | |||
| 439 | + | CanGoBack: wv.canGoBack, | |||
| 440 | + | CanGoFwd: wv.canGoFwd, | |||
| 441 | + | ZoomLevel: wv.GetZoomLevel(), | |||
| 442 | + | } | |||
| 443 | + | } | |||
| 444 | + | ||||
| 445 | + | // SetCallbacks registers callback handlers for WebView events. | |||
| 446 | + | // Pass nil to clear all callbacks. | |||
| 447 | + | func (wv *WebView) SetCallbacks(callbacks *port.WebViewCallbacks) { | |||
| 448 | + | if callbacks == nil { | |||
| 449 | + | wv.OnLoadChanged = nil | |||
| 450 | + | wv.OnTitleChanged = nil | |||
| 451 | + | wv.OnURIChanged = nil | |||
| 452 | + | wv.OnProgressChanged = nil | |||
| 453 | + | wv.OnClose = nil | |||
| 454 | + | wv.OnCreate = nil | |||
| 455 | + | return | |||
| 456 | + | } | |||
| 457 | + | ||||
| 458 | + | // Map port callbacks to webkit callbacks | |||
| 459 | + | if callbacks.OnLoadChanged != nil { | |||
| 460 | + | wv.OnLoadChanged = func(e LoadEvent) { | |||
| 461 | + | callbacks.OnLoadChanged(port.LoadEvent(e)) | |||
| 462 | + | } | |||
| 463 | + | } | |||
| 464 | + | wv.OnTitleChanged = callbacks.OnTitleChanged | |||
| 465 | + | wv.OnURIChanged = callbacks.OnURIChanged | |||
| 466 | + | wv.OnProgressChanged = callbacks.OnProgressChanged | |||
| 467 | + | wv.OnClose = callbacks.OnClose | |||
| 468 | + | if callbacks.OnCreate != nil { | |||
| 469 | + | wv.OnCreate = func(req PopupRequest) *WebView { | |||
| 470 | + | portReq := port.PopupRequest{ | |||
| 471 | + | TargetURI: req.TargetURI, | |||
| 472 | + | FrameName: req.FrameName, | |||
| 473 | + | IsUserGesture: req.IsUserGesture, | |||
| 474 | + | ParentViewID: req.ParentID, | |||
| 475 | + | } | |||
| 476 | + | result := callbacks.OnCreate(portReq) | |||
| 477 | + | if result == nil { | |||
| 478 | + | return nil | |||
| 479 | + | } | |||
| 480 | + | // The callback returns port.WebView, we need to convert back | |||
| 481 | + | // This assumes the returned WebView is actually a *webkit.WebView | |||
| 482 | + | if wkView, ok := result.(*WebView); ok { | |||
| 483 | + | return wkView | |||
| 484 | + | } | |||
| 485 | + | return nil | |||
| 486 | + | } | |||
| 487 | + | } | |||
| 488 | + | } | |||
| 489 | + | ||||
| 429 | // ShowDevTools opens the WebKit inspector/developer tools. | 490 | // ShowDevTools opens the WebKit inspector/developer tools. | ||
| 430 | func (wv *WebView) ShowDevTools() error { | 491 | func (wv *WebView) ShowDevTools() error { | ||
| 431 | if wv.destroyed.Load() { | 492 | if wv.destroyed.Load() { | ||