use std::sync::Arc;
use serde_json::{Value, json};
use crate::cdp::core::CdpCore;
use crate::cdp::element::ChromiumElement;
use crate::locator::{self, Query};
use crate::{Error, Result};
pub struct ChromiumShadowRoot {
core: Arc<CdpCore>,
object_id: String,
}
impl ChromiumShadowRoot {
pub(crate) fn new(core: Arc<CdpCore>, object_id: String) -> Self {
Self { core, object_id }
}
pub async fn ele(&self, selector: &str) -> Result<ChromiumElement> {
let css = css_only(selector)?;
match self
.core
.call_handle(
&self.object_id,
"function(s){ return this.querySelector(s); }",
vec![json!({ "value": css })],
)
.await?
{
Some(oid) => Ok(ChromiumElement::new(self.core.clone(), oid)),
None => Err(Error::ElementNotFound(selector.to_string())),
}
}
pub async fn eles(&self, selector: &str) -> Result<Vec<ChromiumElement>> {
let css = css_only(selector)?;
let Some(arr) = self
.core
.call_handle(
&self.object_id,
"function(s){ return Array.from(this.querySelectorAll(s)); }",
vec![json!({ "value": css })],
)
.await?
else {
return Ok(Vec::new());
};
let oids = self.core.array_object_ids(&arr).await?;
Ok(oids
.into_iter()
.map(|oid| ChromiumElement::new(self.core.clone(), oid))
.collect())
}
pub async fn html(&self) -> Result<String> {
let v = self
.core
.call_value(
&self.object_id,
"function(){ return this.innerHTML ?? ''; }",
vec![],
)
.await?;
Ok(v.as_str().unwrap_or_default().to_string())
}
pub async fn run_js(&self, body: &str) -> Result<Value> {
self.core
.call_value(&self.object_id, &format!("function(){{ {body} }}"), vec![])
.await
}
pub async fn s_ele(&self, selector: &str) -> Result<crate::static_element::StaticElement> {
crate::static_element::StaticElement::parse(&self.html().await?)?.ele(selector)
}
pub async fn s_eles(
&self,
selector: &str,
) -> Result<Vec<crate::static_element::StaticElement>> {
crate::static_element::StaticElement::parse(&self.html().await?)?.eles(selector)
}
}
fn css_only(selector: &str) -> Result<String> {
match locator::parse(selector) {
Query::Css(s) => Ok(s),
Query::Xpath(_) => Err(Error::msg("Shadow DOM 内不支持 xpath,请用 CSS 定位")),
}
}