fix(history): record full URL instead of domain on navigation
Move history recording from navigation start to LoadCommitted event when URI is guaranteed correct. Add SPA navigation detection via OnURIChanged callback for JavaScript-based URL changes like YouTube search. Wires all necessary callbacks to properly save full URLs to history instead of just the domain. Changes: - webkit/webview.go: Add notify::uri signal handler to track URI changes - usecase/navigate.go: Rename recordHistory to public RecordHistory, remove history recording from Execute, fix UpdateHistoryTitle to not create duplicate entries - coordinator/navigation.go: Add RecordHistory method to wire history recording - coordinator/content.go: Add onHistoryRecord callback, SetOnHistoryRecord setter, wire OnURIChanged for SPA navigation, add onSPANavigation handler - ui/app.go: Wire history recording callback in initCoordinators
- commit
- e30e9ed1775f6067b4ec8542c099c2b14871ee06
- author
- brice · · 2025-12-16 20:36 UTC
- committer
- brice · · 2025-12-16 17:18 UTC
- parent
- ec9a433
- signature
- unsigned
5 files · +79 -14
M internal/application/usecase/navigate.go +8 -10
| @@ -57,13 +57,11 @@ func (uc *NavigateUseCase) Execute(ctx context.Context, input NavigateInput) (*N | |||
| 57 | 57 | Msg("navigating to URL") | |
| 58 | 58 | ||
| 59 | 59 | // Navigate to URL (zoom will be applied on LoadCommitted to avoid shift) | |
| 60 | + | // History is recorded on LoadCommitted when URI is guaranteed correct | |
| 60 | 61 | if err := input.WebView.LoadURI(ctx, input.URL); err != nil { | |
| 61 | 62 | return nil, fmt.Errorf("failed to load URL: %w", err) | |
| 62 | 63 | } | |
| 63 | 64 | ||
| 64 | - | // Record in history asynchronously | |
| 65 | - | go uc.recordHistory(ctx, input.URL) | |
| 66 | - | ||
| 67 | 65 | log.Info(). | |
| 68 | 66 | Str("url", input.URL). | |
| 69 | 67 | Msg("navigation initiated") | |
| @@ -73,8 +71,9 @@ func (uc *NavigateUseCase) Execute(ctx context.Context, input NavigateInput) (*N | |||
| 73 | 71 | }, nil | |
| 74 | 72 | } | |
| 75 | 73 | ||
| 76 | - | // recordHistory saves or updates the history entry. | |
| 77 | - | func (uc *NavigateUseCase) recordHistory(ctx context.Context, url string) { | |
| 74 | + | // RecordHistory saves or updates the history entry. | |
| 75 | + | // Should be called on LoadCommitted when URI is guaranteed correct. | |
| 76 | + | func (uc *NavigateUseCase) RecordHistory(ctx context.Context, url string) { | |
| 78 | 77 | log := logging.FromContext(ctx) | |
| 79 | 78 | ||
| 80 | 79 | // Normalize URL to avoid duplicates (e.g., github.com vs github.com/) | |
| @@ -115,11 +114,10 @@ func (uc *NavigateUseCase) UpdateHistoryTitle(ctx context.Context, url, title st | |||
| 115 | 114 | } | |
| 116 | 115 | ||
| 117 | 116 | if entry == nil { | |
| 118 | - | // Entry doesn't exist, create it with title | |
| 119 | - | entry = entity.NewHistoryEntry(url, title) | |
| 120 | - | if err := uc.historyRepo.Save(ctx, entry); err != nil { | |
| 121 | - | return fmt.Errorf("failed to save history: %w", err) | |
| 122 | - | } | |
| 117 | + | // Entry doesn't exist - don't create it here | |
| 118 | + | // Initial navigation should have already created the entry | |
| 119 | + | // This can happen if URL changed during page load (SPA, redirect) | |
| 120 | + | log.Debug().Str("url", url).Msg("no history entry found for URL, skipping title update") | |
| 123 | 121 | return nil | |
| 124 | 122 | } | |
| 125 | 123 | ||
| @@ -57,13 +57,11 @@ func (uc *NavigateUseCase) Execute(ctx context.Context, input NavigateInput) (*N | |||||
| 57 | Msg("navigating to URL") | 57 | Msg("navigating to URL") | ||
| 58 | 58 | ||||
| 59 | // Navigate to URL (zoom will be applied on LoadCommitted to avoid shift) | 59 | // Navigate to URL (zoom will be applied on LoadCommitted to avoid shift) | ||
| 60 | + | // History is recorded on LoadCommitted when URI is guaranteed correct | |||
| 60 | if err := input.WebView.LoadURI(ctx, input.URL); err != nil { | 61 | if err := input.WebView.LoadURI(ctx, input.URL); err != nil { | ||
| 61 | return nil, fmt.Errorf("failed to load URL: %w", err) | 62 | return nil, fmt.Errorf("failed to load URL: %w", err) | ||
| 62 | } | 63 | } | ||
| 63 | 64 | ||||
| 64 | - | // Record in history asynchronously | |||
| 65 | - | go uc.recordHistory(ctx, input.URL) | |||
| 66 | - | ||||
| 67 | log.Info(). | 65 | log.Info(). | ||
| 68 | Str("url", input.URL). | 66 | Str("url", input.URL). | ||
| 69 | Msg("navigation initiated") | 67 | Msg("navigation initiated") | ||
| @@ -73,8 +71,9 @@ func (uc *NavigateUseCase) Execute(ctx context.Context, input NavigateInput) (*N | |||||
| 73 | }, nil | 71 | }, nil | ||
| 74 | } | 72 | } | ||
| 75 | 73 | ||||
| 76 | - | // recordHistory saves or updates the history entry. | 74 | + | // RecordHistory saves or updates the history entry. |
| 77 | - | func (uc *NavigateUseCase) recordHistory(ctx context.Context, url string) { | 75 | + | // Should be called on LoadCommitted when URI is guaranteed correct. |
| 76 | + | func (uc *NavigateUseCase) RecordHistory(ctx context.Context, url string) { | |||
| 78 | log := logging.FromContext(ctx) | 77 | log := logging.FromContext(ctx) | ||
| 79 | 78 | ||||
| 80 | // Normalize URL to avoid duplicates (e.g., github.com vs github.com/) | 79 | // Normalize URL to avoid duplicates (e.g., github.com vs github.com/) | ||
| @@ -115,11 +114,10 @@ func (uc *NavigateUseCase) UpdateHistoryTitle(ctx context.Context, url, title st | |||||
| 115 | } | 114 | } | ||
| 116 | 115 | ||||
| 117 | if entry == nil { | 116 | if entry == nil { | ||
| 118 | - | // Entry doesn't exist, create it with title | 117 | + | // Entry doesn't exist - don't create it here |
| 119 | - | entry = entity.NewHistoryEntry(url, title) | 118 | + | // Initial navigation should have already created the entry |
| 120 | - | if err := uc.historyRepo.Save(ctx, entry); err != nil { | 119 | + | // This can happen if URL changed during page load (SPA, redirect) |
| 121 | - | return fmt.Errorf("failed to save history: %w", err) | 120 | + | log.Debug().Str("url", url).Msg("no history entry found for URL, skipping title update") |
| 122 | - | } | |||
| 123 | return nil | 121 | return nil | ||
| 124 | } | 122 | } | ||
| 125 | 123 | ||||
M internal/infrastructure/webkit/webview.go +16 -0
| @@ -296,6 +296,22 @@ func (wv *WebView) connectSignals() { | |||
| 296 | 296 | sigID = gobject.SignalConnect(wv.inner.GoPointer(), "notify::title", glib.NewCallback(&titleCb)) | |
| 297 | 297 | wv.signalIDs = append(wv.signalIDs, sigID) | |
| 298 | 298 | ||
| 299 | + | // notify::uri signal for URI changes | |
| 300 | + | // This fires when the URI changes (e.g., redirects, SPA navigation via History API) | |
| 301 | + | uriCb := func() { | |
| 302 | + | uri := wv.inner.GetUri() | |
| 303 | + | wv.mu.Lock() | |
| 304 | + | oldUri := wv.uri | |
| 305 | + | wv.uri = uri | |
| 306 | + | wv.mu.Unlock() | |
| 307 | + | ||
| 308 | + | if wv.OnURIChanged != nil && uri != oldUri { | |
| 309 | + | wv.OnURIChanged(uri) | |
| 310 | + | } | |
| 311 | + | } | |
| 312 | + | sigID = gobject.SignalConnect(wv.inner.GoPointer(), "notify::uri", glib.NewCallback(&uriCb)) | |
| 313 | + | wv.signalIDs = append(wv.signalIDs, sigID) | |
| 314 | + | ||
| 299 | 315 | // notify::favicon signal for favicon changes | |
| 300 | 316 | // This fires when the page favicon changes (after page load or dynamic updates) | |
| 301 | 317 | faviconCb := func() { | |
| @@ -296,6 +296,22 @@ func (wv *WebView) connectSignals() { | |||||
| 296 | sigID = gobject.SignalConnect(wv.inner.GoPointer(), "notify::title", glib.NewCallback(&titleCb)) | 296 | sigID = gobject.SignalConnect(wv.inner.GoPointer(), "notify::title", glib.NewCallback(&titleCb)) | ||
| 297 | wv.signalIDs = append(wv.signalIDs, sigID) | 297 | wv.signalIDs = append(wv.signalIDs, sigID) | ||
| 298 | 298 | ||||
| 299 | + | // notify::uri signal for URI changes | |||
| 300 | + | // This fires when the URI changes (e.g., redirects, SPA navigation via History API) | |||
| 301 | + | uriCb := func() { | |||
| 302 | + | uri := wv.inner.GetUri() | |||
| 303 | + | wv.mu.Lock() | |||
| 304 | + | oldUri := wv.uri | |||
| 305 | + | wv.uri = uri | |||
| 306 | + | wv.mu.Unlock() | |||
| 307 | + | ||||
| 308 | + | if wv.OnURIChanged != nil && uri != oldUri { | |||
| 309 | + | wv.OnURIChanged(uri) | |||
| 310 | + | } | |||
| 311 | + | } | |||
| 312 | + | sigID = gobject.SignalConnect(wv.inner.GoPointer(), "notify::uri", glib.NewCallback(&uriCb)) | |||
| 313 | + | wv.signalIDs = append(wv.signalIDs, sigID) | |||
| 314 | + | ||||
| 299 | // notify::favicon signal for favicon changes | 315 | // notify::favicon signal for favicon changes | ||
| 300 | // This fires when the page favicon changes (after page load or dynamic updates) | 316 | // This fires when the page favicon changes (after page load or dynamic updates) | ||
| 301 | faviconCb := func() { | 317 | faviconCb := func() { | ||
M internal/ui/app.go +5 -0
| @@ -310,6 +310,11 @@ func (a *App) initCoordinators(ctx context.Context) { | |||
| 310 | 310 | a.navCoord.UpdateHistoryTitle(ctx, paneID, url, title) | |
| 311 | 311 | }) | |
| 312 | 312 | ||
| 313 | + | // Wire history recording on LoadCommitted (URI is guaranteed correct at this point) | |
| 314 | + | a.contentCoord.SetOnHistoryRecord(func(ctx context.Context, paneID entity.PaneID, url string) { | |
| 315 | + | a.navCoord.RecordHistory(ctx, paneID, url) | |
| 316 | + | }) | |
| 317 | + | ||
| 313 | 318 | // 5. Keyboard Dispatcher | |
| 314 | 319 | a.kbDispatcher = dispatcher.NewKeyboardDispatcher( | |
| 315 | 320 | ctx, | |
| @@ -310,6 +310,11 @@ func (a *App) initCoordinators(ctx context.Context) { | |||||
| 310 | a.navCoord.UpdateHistoryTitle(ctx, paneID, url, title) | 310 | a.navCoord.UpdateHistoryTitle(ctx, paneID, url, title) | ||
| 311 | }) | 311 | }) | ||
| 312 | 312 | ||||
| 313 | + | // Wire history recording on LoadCommitted (URI is guaranteed correct at this point) | |||
| 314 | + | a.contentCoord.SetOnHistoryRecord(func(ctx context.Context, paneID entity.PaneID, url string) { | |||
| 315 | + | a.navCoord.RecordHistory(ctx, paneID, url) | |||
| 316 | + | }) | |||
| 317 | + | ||||
| 313 | // 5. Keyboard Dispatcher | 318 | // 5. Keyboard Dispatcher | ||
| 314 | a.kbDispatcher = dispatcher.NewKeyboardDispatcher( | 319 | a.kbDispatcher = dispatcher.NewKeyboardDispatcher( | ||
| 315 | ctx, | 320 | ctx, | ||
M internal/ui/coordinator/content.go +41 -4
| @@ -38,6 +38,9 @@ type ContentCoordinator struct { | |||
| 38 | 38 | // Callback when title changes (for history persistence) | |
| 39 | 39 | onTitleUpdated func(ctx context.Context, paneID entity.PaneID, url, title string) | |
| 40 | 40 | ||
| 41 | + | // Callback when page is committed (for history recording) | |
| 42 | + | onHistoryRecord func(ctx context.Context, paneID entity.PaneID, url string) | |
| 43 | + | ||
| 41 | 44 | // Gesture action handler for mouse button navigation | |
| 42 | 45 | gestureActionHandler input.ActionHandler | |
| 43 | 46 | } | |
| @@ -71,6 +74,11 @@ func (c *ContentCoordinator) SetOnTitleUpdated(fn func(ctx context.Context, pane | |||
| 71 | 74 | c.onTitleUpdated = fn | |
| 72 | 75 | } | |
| 73 | 76 | ||
| 77 | + | // SetOnHistoryRecord sets the callback for recording history on page commit. | |
| 78 | + | func (c *ContentCoordinator) SetOnHistoryRecord(fn func(ctx context.Context, paneID entity.PaneID, url string)) { | |
| 79 | + | c.onHistoryRecord = fn | |
| 80 | + | } | |
| 81 | + | ||
| 74 | 82 | // SetGestureActionHandler sets the callback for mouse button navigation gestures. | |
| 75 | 83 | func (c *ContentCoordinator) SetGestureActionHandler(handler input.ActionHandler) { | |
| 76 | 84 | c.gestureActionHandler = handler | |
| @@ -112,6 +120,16 @@ func (c *ContentCoordinator) EnsureWebView(ctx context.Context, paneID entity.Pa | |||
| 112 | 120 | } | |
| 113 | 121 | } | |
| 114 | 122 | ||
| 123 | + | // Set up URI change callback for SPA navigation (History API) | |
| 124 | + | // This fires when URL changes via JavaScript without a full page load | |
| 125 | + | wv.OnURIChanged = func(uri string) { | |
| 126 | + | // Only record if not loading (SPA navigation via History API) | |
| 127 | + | // Full page loads are handled by OnLoadCommitted | |
| 128 | + | if !wv.IsLoading() && uri != "" { | |
| 129 | + | c.onSPANavigation(ctx, paneID, uri) | |
| 130 | + | } | |
| 131 | + | } | |
| 132 | + | ||
| 115 | 133 | log.Debug().Str("pane_id", string(paneID)).Msg("webview acquired for pane") | |
| 116 | 134 | return wv, nil | |
| 117 | 135 | } | |
| @@ -423,15 +441,22 @@ func (c *ContentCoordinator) PreloadCachedFavicon(ctx context.Context, paneID en | |||
| 423 | 441 | } | |
| 424 | 442 | } | |
| 425 | 443 | ||
| 426 | - | // onLoadCommitted re-applies zoom when page content starts loading. | |
| 444 | + | // onLoadCommitted re-applies zoom when page content starts loading and records history. | |
| 427 | 445 | // WebKit may reset zoom during document transitions, so we reapply after LoadCommitted. | |
| 446 | + | // History is recorded here because the URI is guaranteed to be correct after commit. | |
| 428 | 447 | func (c *ContentCoordinator) onLoadCommitted(ctx context.Context, paneID entity.PaneID, wv *webkit.WebView) { | |
| 429 | - | if c.zoomUC == nil { | |
| 448 | + | url := wv.URI() | |
| 449 | + | if url == "" { | |
| 430 | 450 | return | |
| 431 | 451 | } | |
| 432 | 452 | ||
| 433 | - | url := wv.URI() | |
| 434 | - | if url == "" { | |
| 453 | + | // Record history - URI is guaranteed to be correct at LoadCommitted | |
| 454 | + | if c.onHistoryRecord != nil { | |
| 455 | + | c.onHistoryRecord(ctx, paneID, url) | |
| 456 | + | } | |
| 457 | + | ||
| 458 | + | // Apply zoom | |
| 459 | + | if c.zoomUC == nil { | |
| 435 | 460 | return | |
| 436 | 461 | } | |
| 437 | 462 | ||
| @@ -442,3 +467,15 @@ func (c *ContentCoordinator) onLoadCommitted(ctx context.Context, paneID entity. | |||
| 442 | 467 | ||
| 443 | 468 | _ = c.zoomUC.ApplyToWebView(ctx, wv, domain) | |
| 444 | 469 | } | |
| 470 | + | ||
| 471 | + | // onSPANavigation records history when URL changes via JavaScript (History API). | |
| 472 | + | // This handles SPA navigation like YouTube search, where the URL changes without a page load. | |
| 473 | + | func (c *ContentCoordinator) onSPANavigation(ctx context.Context, paneID entity.PaneID, url string) { | |
| 474 | + | log := logging.FromContext(ctx) | |
| 475 | + | log.Debug().Str("pane_id", string(paneID)).Str("url", url).Msg("SPA navigation detected") | |
| 476 | + | ||
| 477 | + | // Record history for SPA navigation | |
| 478 | + | if c.onHistoryRecord != nil { | |
| 479 | + | c.onHistoryRecord(ctx, paneID, url) | |
| 480 | + | } | |
| 481 | + | } | |
| @@ -38,6 +38,9 @@ type ContentCoordinator struct { | |||||
| 38 | // Callback when title changes (for history persistence) | 38 | // Callback when title changes (for history persistence) | ||
| 39 | onTitleUpdated func(ctx context.Context, paneID entity.PaneID, url, title string) | 39 | onTitleUpdated func(ctx context.Context, paneID entity.PaneID, url, title string) | ||
| 40 | 40 | ||||
| 41 | + | // Callback when page is committed (for history recording) | |||
| 42 | + | onHistoryRecord func(ctx context.Context, paneID entity.PaneID, url string) | |||
| 43 | + | ||||
| 41 | // Gesture action handler for mouse button navigation | 44 | // Gesture action handler for mouse button navigation | ||
| 42 | gestureActionHandler input.ActionHandler | 45 | gestureActionHandler input.ActionHandler | ||
| 43 | } | 46 | } | ||
| @@ -71,6 +74,11 @@ func (c *ContentCoordinator) SetOnTitleUpdated(fn func(ctx context.Context, pane | |||||
| 71 | c.onTitleUpdated = fn | 74 | c.onTitleUpdated = fn | ||
| 72 | } | 75 | } | ||
| 73 | 76 | ||||
| 77 | + | // SetOnHistoryRecord sets the callback for recording history on page commit. | |||
| 78 | + | func (c *ContentCoordinator) SetOnHistoryRecord(fn func(ctx context.Context, paneID entity.PaneID, url string)) { | |||
| 79 | + | c.onHistoryRecord = fn | |||
| 80 | + | } | |||
| 81 | + | ||||
| 74 | // SetGestureActionHandler sets the callback for mouse button navigation gestures. | 82 | // SetGestureActionHandler sets the callback for mouse button navigation gestures. | ||
| 75 | func (c *ContentCoordinator) SetGestureActionHandler(handler input.ActionHandler) { | 83 | func (c *ContentCoordinator) SetGestureActionHandler(handler input.ActionHandler) { | ||
| 76 | c.gestureActionHandler = handler | 84 | c.gestureActionHandler = handler | ||
| @@ -112,6 +120,16 @@ func (c *ContentCoordinator) EnsureWebView(ctx context.Context, paneID entity.Pa | |||||
| 112 | } | 120 | } | ||
| 113 | } | 121 | } | ||
| 114 | 122 | ||||
| 123 | + | // Set up URI change callback for SPA navigation (History API) | |||
| 124 | + | // This fires when URL changes via JavaScript without a full page load | |||
| 125 | + | wv.OnURIChanged = func(uri string) { | |||
| 126 | + | // Only record if not loading (SPA navigation via History API) | |||
| 127 | + | // Full page loads are handled by OnLoadCommitted | |||
| 128 | + | if !wv.IsLoading() && uri != "" { | |||
| 129 | + | c.onSPANavigation(ctx, paneID, uri) | |||
| 130 | + | } | |||
| 131 | + | } | |||
| 132 | + | ||||
| 115 | log.Debug().Str("pane_id", string(paneID)).Msg("webview acquired for pane") | 133 | log.Debug().Str("pane_id", string(paneID)).Msg("webview acquired for pane") | ||
| 116 | return wv, nil | 134 | return wv, nil | ||
| 117 | } | 135 | } | ||
| @@ -423,15 +441,22 @@ func (c *ContentCoordinator) PreloadCachedFavicon(ctx context.Context, paneID en | |||||
| 423 | } | 441 | } | ||
| 424 | } | 442 | } | ||
| 425 | 443 | ||||
| 426 | - | // onLoadCommitted re-applies zoom when page content starts loading. | 444 | + | // onLoadCommitted re-applies zoom when page content starts loading and records history. |
| 427 | // WebKit may reset zoom during document transitions, so we reapply after LoadCommitted. | 445 | // WebKit may reset zoom during document transitions, so we reapply after LoadCommitted. | ||
| 446 | + | // History is recorded here because the URI is guaranteed to be correct after commit. | |||
| 428 | func (c *ContentCoordinator) onLoadCommitted(ctx context.Context, paneID entity.PaneID, wv *webkit.WebView) { | 447 | func (c *ContentCoordinator) onLoadCommitted(ctx context.Context, paneID entity.PaneID, wv *webkit.WebView) { | ||
| 429 | - | if c.zoomUC == nil { | 448 | + | url := wv.URI() |
| 449 | + | if url == "" { | |||
| 430 | return | 450 | return | ||
| 431 | } | 451 | } | ||
| 432 | 452 | ||||
| 433 | - | url := wv.URI() | 453 | + | // Record history - URI is guaranteed to be correct at LoadCommitted |
| 434 | - | if url == "" { | 454 | + | if c.onHistoryRecord != nil { |
| 455 | + | c.onHistoryRecord(ctx, paneID, url) | |||
| 456 | + | } | |||
| 457 | + | ||||
| 458 | + | // Apply zoom | |||
| 459 | + | if c.zoomUC == nil { | |||
| 435 | return | 460 | return | ||
| 436 | } | 461 | } | ||
| 437 | 462 | ||||
| @@ -442,3 +467,15 @@ func (c *ContentCoordinator) onLoadCommitted(ctx context.Context, paneID entity. | |||||
| 442 | 467 | ||||
| 443 | _ = c.zoomUC.ApplyToWebView(ctx, wv, domain) | 468 | _ = c.zoomUC.ApplyToWebView(ctx, wv, domain) | ||
| 444 | } | 469 | } | ||
| 470 | + | ||||
| 471 | + | // onSPANavigation records history when URL changes via JavaScript (History API). | |||
| 472 | + | // This handles SPA navigation like YouTube search, where the URL changes without a page load. | |||
| 473 | + | func (c *ContentCoordinator) onSPANavigation(ctx context.Context, paneID entity.PaneID, url string) { | |||
| 474 | + | log := logging.FromContext(ctx) | |||
| 475 | + | log.Debug().Str("pane_id", string(paneID)).Str("url", url).Msg("SPA navigation detected") | |||
| 476 | + | ||||
| 477 | + | // Record history for SPA navigation | |||
| 478 | + | if c.onHistoryRecord != nil { | |||
| 479 | + | c.onHistoryRecord(ctx, paneID, url) | |||
| 480 | + | } | |||
| 481 | + | } | |||
M internal/ui/coordinator/navigation.go +9 -0
| @@ -213,6 +213,15 @@ func (c *NavigationCoordinator) UpdateHistoryTitle(ctx context.Context, paneID e | |||
| 213 | 213 | } | |
| 214 | 214 | } | |
| 215 | 215 | ||
| 216 | + | // RecordHistory records a URL in history on page commit. | |
| 217 | + | func (c *NavigationCoordinator) RecordHistory(ctx context.Context, paneID entity.PaneID, url string) { | |
| 218 | + | if c.navigateUC == nil { | |
| 219 | + | return | |
| 220 | + | } | |
| 221 | + | ||
| 222 | + | c.navigateUC.RecordHistory(ctx, url) | |
| 223 | + | } | |
| 224 | + | ||
| 216 | 225 | // ActiveWebView returns the WebView for the active pane (for zoom operations). | |
| 217 | 226 | func (c *NavigationCoordinator) ActiveWebView(ctx context.Context) *webkit.WebView { | |
| 218 | 227 | return c.contentCoord.ActiveWebView(ctx) | |
| @@ -213,6 +213,15 @@ func (c *NavigationCoordinator) UpdateHistoryTitle(ctx context.Context, paneID e | |||||
| 213 | } | 213 | } | ||
| 214 | } | 214 | } | ||
| 215 | 215 | ||||
| 216 | + | // RecordHistory records a URL in history on page commit. | |||
| 217 | + | func (c *NavigationCoordinator) RecordHistory(ctx context.Context, paneID entity.PaneID, url string) { | |||
| 218 | + | if c.navigateUC == nil { | |||
| 219 | + | return | |||
| 220 | + | } | |||
| 221 | + | ||||
| 222 | + | c.navigateUC.RecordHistory(ctx, url) | |||
| 223 | + | } | |||
| 224 | + | ||||
| 216 | // ActiveWebView returns the WebView for the active pane (for zoom operations). | 225 | // ActiveWebView returns the WebView for the active pane (for zoom operations). | ||
| 217 | func (c *NavigationCoordinator) ActiveWebView(ctx context.Context) *webkit.WebView { | 226 | func (c *NavigationCoordinator) ActiveWebView(ctx context.Context) *webkit.WebView { | ||
| 218 | return c.contentCoord.ActiveWebView(ctx) | 227 | return c.contentCoord.ActiveWebView(ctx) | ||