use crate::Page;
use crate::error::LocatorError;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct BoundingBox {
pub x: f64,
pub y: f64,
pub width: f64,
pub height: f64,
}
#[derive(Debug)]
pub struct ElementHandle<'a> {
pub(crate) object_id: String,
pub(crate) page: &'a Page,
}
impl ElementHandle<'_> {
pub fn object_id(&self) -> &str {
&self.object_id
}
pub async fn box_model(&self) -> Result<Option<BoxModel>, LocatorError> {
#[derive(Debug, serde::Deserialize)]
struct BoxModelResult {
model: Option<BoxModel>,
}
let result: BoxModelResult = self
.page
.connection()
.send_command(
"DOM.getBoxModel",
Some(serde_json::json!({
"objectId": self.object_id
})),
Some(self.page.session_id()),
)
.await?;
Ok(result.model)
}
pub async fn is_attached(&self) -> Result<bool, LocatorError> {
#[derive(Debug, serde::Deserialize)]
struct CallResult {
result: viewpoint_cdp::protocol::runtime::RemoteObject,
}
let result: CallResult = self
.page
.connection()
.send_command(
"Runtime.callFunctionOn",
Some(serde_json::json!({
"objectId": self.object_id,
"functionDeclaration": "function() { return this.isConnected; }",
"returnByValue": true
})),
Some(self.page.session_id()),
)
.await?;
Ok(result
.result
.value
.and_then(|v| v.as_bool())
.unwrap_or(false))
}
pub async fn evaluate<T: serde::de::DeserializeOwned>(
&self,
expression: &str,
) -> Result<T, LocatorError> {
let function = format!("function() {{ return {expression}; }}");
#[derive(Debug, serde::Deserialize)]
struct CallResult {
result: viewpoint_cdp::protocol::runtime::RemoteObject,
#[serde(rename = "exceptionDetails")]
exception_details: Option<viewpoint_cdp::protocol::runtime::ExceptionDetails>,
}
let result: CallResult = self
.page
.connection()
.send_command(
"Runtime.callFunctionOn",
Some(serde_json::json!({
"objectId": self.object_id,
"functionDeclaration": function,
"returnByValue": true
})),
Some(self.page.session_id()),
)
.await?;
if let Some(exception) = result.exception_details {
return Err(LocatorError::EvaluationError(exception.text));
}
let value = result.result.value.unwrap_or(serde_json::Value::Null);
serde_json::from_value(value)
.map_err(|e| LocatorError::EvaluationError(format!("Failed to deserialize: {e}")))
}
}
#[derive(Debug, Clone, serde::Deserialize)]
pub struct BoxModel {
pub content: Vec<f64>,
pub padding: Vec<f64>,
pub border: Vec<f64>,
pub margin: Vec<f64>,
pub width: i32,
pub height: i32,
}