use web_sys::HtmlElement;
use super::{CssProperty, Property, StyleStringBuilder};
pub struct StyleBuilder<'a> {
element: &'a HtmlElement,
properties: Vec<(Property, String)>,
}
impl<'a> Clone for StyleBuilder<'a> {
fn clone(&self) -> Self {
Self {
element: self.element,
properties: self.properties.clone(),
}
}
}
impl<'a> StyleBuilder<'a> {
pub fn new(element: &'a HtmlElement) -> Self {
Self {
element,
properties: Vec::new(),
}
}
pub fn add(mut self, property: CssProperty, value: &str) -> Self {
self.properties
.push((Property::Known(property), value.to_string()));
self
}
pub fn add_custom(mut self, property: &str, value: &str) -> Self {
self.properties
.push((Property::Custom(property.to_string()), value.to_string()));
self
}
pub fn add_px(mut self, property: CssProperty, pixels: u32) -> Self {
self.properties
.push((Property::Known(property), format!("{}px", pixels)));
self
}
pub fn add_all(mut self, properties: &[(CssProperty, &str)]) -> Self {
for &(property, value) in properties {
self.properties
.push((Property::Known(property), value.to_string()));
}
self
}
pub fn apply(self) {
if self.properties.is_empty() {
return;
}
let style = self.element.style();
for (property, value) in self.properties {
let _ = style.set_property(property.as_str(), &value);
}
}
pub fn apply_smart(self) -> usize {
if self.properties.is_empty() {
return 0;
}
let style = self.element.style();
let mut updated = 0;
for (property, value) in self.properties {
let property_name = property.as_str();
let current_value = style.get_property_value(property_name).unwrap_or_default();
if current_value != value && style.set_property(property_name, &value).is_ok() {
updated += 1;
}
}
updated
}
pub fn build_string<F>(f: F) -> String
where
F: FnOnce(StyleStringBuilder) -> StyleStringBuilder,
{
f(StyleStringBuilder::new()).build()
}
pub fn build_clean<F>(f: F) -> String
where
F: FnOnce(StyleStringBuilder) -> StyleStringBuilder,
{
f(StyleStringBuilder::new()).build_clean()
}
}
#[derive(Debug, Clone)]
enum AttributeValue {
String(String),
Bool(bool),
}
pub struct AttributeBuilder<'a> {
element: &'a HtmlElement,
attributes: Vec<(String, AttributeValue)>,
}
impl<'a> Clone for AttributeBuilder<'a> {
fn clone(&self) -> Self {
Self {
element: self.element,
attributes: self.attributes.clone(),
}
}
}
impl<'a> AttributeBuilder<'a> {
pub fn new(element: &'a HtmlElement) -> Self {
Self {
element,
attributes: Vec::new(),
}
}
pub fn add(mut self, name: &str, value: &str) -> Self {
self.attributes
.push((name.to_string(), AttributeValue::String(value.to_string())));
self
}
pub fn add_bool(mut self, name: &str, value: bool) -> Self {
self.attributes
.push((name.to_string(), AttributeValue::Bool(value)));
self
}
pub fn add_data(self, name: &str, value: &str) -> Self {
self.add(&format!("data-{}", name), value)
}
pub fn apply(self) {
if self.attributes.is_empty() {
return;
}
for (name, value) in self.attributes {
match value {
AttributeValue::String(v) => {
let _ = self.element.set_attribute(&name, &v);
}
AttributeValue::Bool(v) => {
if v {
let _ = self.element.set_attribute(&name, "");
} else {
let _ = self.element.remove_attribute(&name);
}
}
}
}
}
}