firefox_webdriver/browser/tab/
scroll.rs

1//! Scroll control methods.
2
3use tracing::debug;
4
5use crate::error::Result;
6
7use super::Tab;
8
9// ============================================================================
10// Tab - Scroll
11// ============================================================================
12
13impl Tab {
14    /// Scrolls the page by the specified amount.
15    ///
16    /// # Arguments
17    ///
18    /// * `x` - Horizontal scroll amount in pixels (positive = right)
19    /// * `y` - Vertical scroll amount in pixels (positive = down)
20    ///
21    /// # Example
22    ///
23    /// ```ignore
24    /// // Scroll down 500 pixels
25    /// tab.scroll_by(0, 500).await?;
26    ///
27    /// // Scroll right 200 pixels
28    /// tab.scroll_by(200, 0).await?;
29    /// ```
30    pub async fn scroll_by(&self, x: i32, y: i32) -> Result<()> {
31        debug!(tab_id = %self.inner.tab_id, x = x, y = y, "Scrolling by");
32
33        let script = format!("window.scrollBy({}, {});", x, y);
34        self.execute_script(&script).await?;
35        Ok(())
36    }
37
38    /// Scrolls the page to the specified position.
39    ///
40    /// # Arguments
41    ///
42    /// * `x` - Horizontal position in pixels from left
43    /// * `y` - Vertical position in pixels from top
44    ///
45    /// # Example
46    ///
47    /// ```ignore
48    /// // Scroll to top of page
49    /// tab.scroll_to(0, 0).await?;
50    ///
51    /// // Scroll to position (100, 500)
52    /// tab.scroll_to(100, 500).await?;
53    /// ```
54    pub async fn scroll_to(&self, x: i32, y: i32) -> Result<()> {
55        debug!(tab_id = %self.inner.tab_id, x = x, y = y, "Scrolling to");
56
57        let script = format!("window.scrollTo({}, {});", x, y);
58        self.execute_script(&script).await?;
59        Ok(())
60    }
61
62    /// Scrolls to the top of the page.
63    pub async fn scroll_to_top(&self) -> Result<()> {
64        debug!(tab_id = %self.inner.tab_id, "Scrolling to top");
65        self.scroll_to(0, 0).await
66    }
67
68    /// Scrolls to the bottom of the page.
69    pub async fn scroll_to_bottom(&self) -> Result<()> {
70        debug!(tab_id = %self.inner.tab_id, "Scrolling to bottom");
71
72        self.execute_script("window.scrollTo(0, document.body.scrollHeight);")
73            .await?;
74        Ok(())
75    }
76
77    /// Gets the current scroll position.
78    ///
79    /// # Returns
80    ///
81    /// Tuple of (x, y) scroll position in pixels.
82    pub async fn get_scroll_position(&self) -> Result<(i32, i32)> {
83        let result = self
84            .execute_script("return { x: window.scrollX, y: window.scrollY };")
85            .await?;
86
87        let x = result.get("x").and_then(|v| v.as_i64()).unwrap_or(0) as i32;
88        let y = result.get("y").and_then(|v| v.as_i64()).unwrap_or(0) as i32;
89
90        debug!(tab_id = %self.inner.tab_id, x = x, y = y, "Got scroll position");
91        Ok((x, y))
92    }
93
94    /// Gets the page dimensions (scrollable area).
95    ///
96    /// # Returns
97    ///
98    /// Tuple of (width, height) in pixels.
99    pub async fn get_page_size(&self) -> Result<(i32, i32)> {
100        let result = self
101            .execute_script(
102                r#"
103                const body = document.body;
104                const html = document.documentElement;
105                return {
106                    width: Math.max(body.scrollWidth, body.offsetWidth, html.clientWidth, html.scrollWidth, html.offsetWidth),
107                    height: Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight)
108                };
109                "#,
110            )
111            .await?;
112
113        let width = result.get("width").and_then(|v| v.as_i64()).unwrap_or(0) as i32;
114        let height = result.get("height").and_then(|v| v.as_i64()).unwrap_or(0) as i32;
115
116        debug!(tab_id = %self.inner.tab_id, width = width, height = height, "Got page size");
117        Ok((width, height))
118    }
119
120    /// Gets the viewport dimensions.
121    ///
122    /// # Returns
123    ///
124    /// Tuple of (width, height) in pixels.
125    pub async fn get_viewport_size(&self) -> Result<(i32, i32)> {
126        let result = self
127            .execute_script("return { width: window.innerWidth, height: window.innerHeight };")
128            .await?;
129
130        let width = result.get("width").and_then(|v| v.as_i64()).unwrap_or(0) as i32;
131        let height = result.get("height").and_then(|v| v.as_i64()).unwrap_or(0) as i32;
132
133        debug!(tab_id = %self.inner.tab_id, width = width, height = height, "Got viewport size");
134        Ok((width, height))
135    }
136}