viewpoint_core/context/page_events/
mod.rs

1//! Page event handling for BrowserContext.
2//!
3//! This module provides page and close event handling functionality.
4
5use std::future::Future;
6
7use super::events::{HandlerId, WaitForPageBuilder};
8use super::BrowserContext;
9use crate::error::ContextError;
10use crate::page::Page;
11
12impl BrowserContext {
13    /// Register a handler for new page events.
14    ///
15    /// The handler will be called whenever a new page is created in this context.
16    /// Returns a handler ID that can be used to remove the handler with `off_page`.
17    ///
18    /// # Example
19    ///
20    /// ```no_run
21    /// use viewpoint_core::{Browser, Page};
22    ///
23    /// # async fn example() -> Result<(), viewpoint_core::CoreError> {
24    /// let browser = Browser::launch().headless(true).launch().await?;
25    /// let context = browser.new_context().await?;
26    ///
27    /// let handler_id = context.on_page(|page: Page| async move {
28    ///     println!("New page created: {}", page.url().await.unwrap_or_default());
29    /// }).await;
30    ///
31    /// // Later, remove the handler
32    /// context.off_page(handler_id).await;
33    /// # Ok(())
34    /// # }
35    /// ```
36    pub async fn on_page<F, Fut>(&self, handler: F) -> HandlerId
37    where
38        F: Fn(Page) -> Fut + Send + Sync + 'static,
39        Fut: Future<Output = ()> + Send + 'static,
40    {
41        self.event_manager.on_page(handler).await
42    }
43
44    /// Remove a page event handler by its ID.
45    ///
46    /// Returns `true` if a handler was removed, `false` if the ID was not found.
47    pub async fn off_page(&self, handler_id: HandlerId) -> bool {
48        self.event_manager.off_page(handler_id).await
49    }
50
51    /// Register a handler for context close events.
52    ///
53    /// The handler will be called when the context is about to close,
54    /// before cleanup begins.
55    ///
56    /// # Example
57    ///
58    /// ```no_run
59    /// use viewpoint_core::Browser;
60    ///
61    /// # async fn example() -> Result<(), viewpoint_core::CoreError> {
62    /// let browser = Browser::launch().headless(true).launch().await?;
63    /// let context = browser.new_context().await?;
64    ///
65    /// let handler_id = context.on_close(|| async {
66    ///     println!("Context is closing!");
67    /// }).await;
68    ///
69    /// // Later, remove the handler
70    /// context.off_close(handler_id).await;
71    /// # Ok(())
72    /// # }
73    /// ```
74    pub async fn on_close<F, Fut>(&self, handler: F) -> HandlerId
75    where
76        F: Fn() -> Fut + Send + Sync + 'static,
77        Fut: Future<Output = ()> + Send + 'static,
78    {
79        self.event_manager.on_close(handler).await
80    }
81
82    /// Remove a close event handler by its ID.
83    ///
84    /// Returns `true` if a handler was removed, `false` if the ID was not found.
85    pub async fn off_close(&self, handler_id: HandlerId) -> bool {
86        self.event_manager.off_close(handler_id).await
87    }
88
89    /// Wait for a new page to be created during an action.
90    ///
91    /// This is useful for handling popups or links that open in new tabs.
92    /// The action is executed and the method waits for a new page to be
93    /// created as a result.
94    ///
95    /// # Example
96    ///
97    /// ```no_run
98    /// use viewpoint_core::{Browser, error::ContextError};
99    ///
100    /// # async fn example() -> Result<(), viewpoint_core::CoreError> {
101    /// let browser = Browser::launch().headless(true).launch().await?;
102    /// let context = browser.new_context().await?;
103    /// let page = context.new_page().await?;
104    ///
105    /// let popup = context.wait_for_page(|| async {
106    ///     page.locator("a[target=_blank]").click().await
107    ///         .map_err(|e| ContextError::Internal(e.to_string()))?;
108    ///     Ok(())
109    /// }).wait().await?;
110    ///
111    /// // Now work with the popup page
112    /// popup.goto("https://example.com").goto().await?;
113    /// # Ok(())
114    /// # }
115    /// ```
116    ///
117    /// # Errors
118    ///
119    /// Returns an error if:
120    /// - The action fails
121    /// - No page is created within the timeout (30 seconds)
122    pub fn wait_for_page<F, Fut>(
123        &self,
124        action: F,
125    ) -> WaitForPageBuilder<'_, F, Fut>
126    where
127        F: FnOnce() -> Fut,
128        Fut: Future<Output = Result<(), ContextError>>,
129    {
130        WaitForPageBuilder::new(&self.event_manager, action)
131    }
132}