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