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::BrowserContext;
8use super::events::{HandlerId, WaitForPageBuilder};
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>(&self, action: F) -> WaitForPageBuilder<'_, F, Fut>
123 where
124 F: FnOnce() -> Fut,
125 Fut: Future<Output = Result<(), ContextError>>,
126 {
127 WaitForPageBuilder::new(&self.event_manager, action)
128 }
129}