use super::Page;
use crate::error::{Error, Result};
use crate::protocol::browser_context::Viewport;
use crate::server::channel_owner::ChannelOwner;
use serde::Serialize;
use std::sync::Arc;
impl Page {
#[tracing::instrument(level = "debug", skip_all, fields(guid = %self.guid()))]
pub async fn add_style_tag(
&self,
options: AddStyleTagOptions,
) -> Result<Arc<crate::protocol::ElementHandle>> {
let frame = self.main_frame().await?;
frame.add_style_tag(options).await
}
#[tracing::instrument(level = "debug", skip_all, fields(guid = %self.guid()))]
pub async fn set_viewport_size(&self, viewport: crate::protocol::Viewport) -> Result<()> {
if let Ok(mut guard) = self.viewport.write() {
*guard = Some(viewport.clone());
}
self.channel()
.send_no_result(
"setViewportSize",
serde_json::json!({ "viewportSize": viewport }),
)
.await
}
#[tracing::instrument(level = "debug", skip_all, fields(guid = %self.guid()))]
pub async fn emulate_media(
&self,
options: impl Into<Option<EmulateMediaOptions>>,
) -> Result<()> {
let options = options.into();
let mut params = serde_json::json!({});
if let Some(opts) = options {
if let Some(media) = opts.media {
params["media"] = serde_json::to_value(media).map_err(|e| {
crate::error::Error::ProtocolError(format!("Failed to serialize media: {}", e))
})?;
}
if let Some(color_scheme) = opts.color_scheme {
params["colorScheme"] = serde_json::to_value(color_scheme).map_err(|e| {
crate::error::Error::ProtocolError(format!(
"Failed to serialize colorScheme: {}",
e
))
})?;
}
if let Some(reduced_motion) = opts.reduced_motion {
params["reducedMotion"] = serde_json::to_value(reduced_motion).map_err(|e| {
crate::error::Error::ProtocolError(format!(
"Failed to serialize reducedMotion: {}",
e
))
})?;
}
if let Some(forced_colors) = opts.forced_colors {
params["forcedColors"] = serde_json::to_value(forced_colors).map_err(|e| {
crate::error::Error::ProtocolError(format!(
"Failed to serialize forcedColors: {}",
e
))
})?;
}
}
self.channel().send_no_result("emulateMedia", params).await
}
#[tracing::instrument(level = "debug", skip_all, fields(guid = %self.guid()))]
pub async fn add_script_tag(
&self,
options: impl Into<Option<AddScriptTagOptions>>,
) -> Result<Arc<crate::protocol::ElementHandle>> {
let options = options.into();
let opts = options.ok_or_else(|| {
Error::InvalidArgument(
"At least one of content, url, or path must be specified".to_string(),
)
})?;
let frame = self.main_frame().await?;
frame.add_script_tag(opts).await
}
pub fn viewport_size(&self) -> Option<Viewport> {
self.viewport.read().ok()?.clone()
}
}
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct AddStyleTagOptions {
pub content: Option<String>,
pub url: Option<String>,
pub path: Option<String>,
}
impl AddStyleTagOptions {
pub fn builder() -> AddStyleTagOptionsBuilder {
AddStyleTagOptionsBuilder::default()
}
pub(crate) fn validate(&self) -> Result<()> {
if self.content.is_none() && self.url.is_none() && self.path.is_none() {
return Err(Error::InvalidArgument(
"At least one of content, url, or path must be specified".to_string(),
));
}
Ok(())
}
}
#[derive(Debug, Clone, Default)]
pub struct AddStyleTagOptionsBuilder {
content: Option<String>,
url: Option<String>,
path: Option<String>,
}
impl AddStyleTagOptionsBuilder {
pub fn content(mut self, content: impl Into<String>) -> Self {
self.content = Some(content.into());
self
}
pub fn url(mut self, url: impl Into<String>) -> Self {
self.url = Some(url.into());
self
}
pub fn path(mut self, path: impl Into<String>) -> Self {
self.path = Some(path.into());
self
}
pub fn build(self) -> AddStyleTagOptions {
AddStyleTagOptions {
content: self.content,
url: self.url,
path: self.path,
}
}
}
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct AddScriptTagOptions {
pub content: Option<String>,
pub url: Option<String>,
pub path: Option<String>,
pub type_: Option<String>,
}
impl AddScriptTagOptions {
pub fn builder() -> AddScriptTagOptionsBuilder {
AddScriptTagOptionsBuilder::default()
}
pub(crate) fn validate(&self) -> Result<()> {
if self.content.is_none() && self.url.is_none() && self.path.is_none() {
return Err(Error::InvalidArgument(
"At least one of content, url, or path must be specified".to_string(),
));
}
Ok(())
}
}
#[derive(Debug, Clone, Default)]
pub struct AddScriptTagOptionsBuilder {
content: Option<String>,
url: Option<String>,
path: Option<String>,
type_: Option<String>,
}
impl AddScriptTagOptionsBuilder {
pub fn content(mut self, content: impl Into<String>) -> Self {
self.content = Some(content.into());
self
}
pub fn url(mut self, url: impl Into<String>) -> Self {
self.url = Some(url.into());
self
}
pub fn path(mut self, path: impl Into<String>) -> Self {
self.path = Some(path.into());
self
}
pub fn type_(mut self, type_: impl Into<String>) -> Self {
self.type_ = Some(type_.into());
self
}
pub fn build(self) -> AddScriptTagOptions {
AddScriptTagOptions {
content: self.content,
url: self.url,
path: self.path,
type_: self.type_,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "lowercase")]
#[non_exhaustive]
pub enum Media {
Screen,
Print,
#[serde(rename = "no-override")]
NoOverride,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[non_exhaustive]
pub enum ColorScheme {
#[serde(rename = "light")]
Light,
#[serde(rename = "dark")]
Dark,
#[serde(rename = "no-preference")]
NoPreference,
#[serde(rename = "no-override")]
NoOverride,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[non_exhaustive]
pub enum ReducedMotion {
#[serde(rename = "reduce")]
Reduce,
#[serde(rename = "no-preference")]
NoPreference,
#[serde(rename = "no-override")]
NoOverride,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[non_exhaustive]
pub enum ForcedColors {
#[serde(rename = "active")]
Active,
#[serde(rename = "none")]
None_,
#[serde(rename = "no-override")]
NoOverride,
}
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct EmulateMediaOptions {
pub media: Option<Media>,
pub color_scheme: Option<ColorScheme>,
pub reduced_motion: Option<ReducedMotion>,
pub forced_colors: Option<ForcedColors>,
}
impl EmulateMediaOptions {
pub fn builder() -> EmulateMediaOptionsBuilder {
EmulateMediaOptionsBuilder::default()
}
}
#[derive(Debug, Clone, Default)]
pub struct EmulateMediaOptionsBuilder {
media: Option<Media>,
color_scheme: Option<ColorScheme>,
reduced_motion: Option<ReducedMotion>,
forced_colors: Option<ForcedColors>,
}
impl EmulateMediaOptionsBuilder {
pub fn media(mut self, media: Media) -> Self {
self.media = Some(media);
self
}
pub fn color_scheme(mut self, color_scheme: ColorScheme) -> Self {
self.color_scheme = Some(color_scheme);
self
}
pub fn reduced_motion(mut self, reduced_motion: ReducedMotion) -> Self {
self.reduced_motion = Some(reduced_motion);
self
}
pub fn forced_colors(mut self, forced_colors: ForcedColors) -> Self {
self.forced_colors = Some(forced_colors);
self
}
pub fn build(self) -> EmulateMediaOptions {
EmulateMediaOptions {
media: self.media,
color_scheme: self.color_scheme,
reduced_motion: self.reduced_motion,
forced_colors: self.forced_colors,
}
}
}