nusa 0.1.9

web-frontend features for kagura
Documentation
use crate::v_node::v_element::{VAttributeValue, VAttributeValues, VAttributes};
use std::rc::Rc;

pub struct Attributes {
    index_id: Option<String>,
    data: VAttributes,
}

impl Attributes {
    pub fn new() -> Self {
        Self {
            index_id: None,
            data: VAttributes::new(),
        }
    }

    pub fn into_attributes(self) -> (Option<String>, VAttributes) {
        (self.index_id, self.data)
    }

    pub fn index_id(mut self, key: String) -> Self {
        self.index_id = Some(key);
        self
    }

    pub fn insert_with_delimiter(
        mut self,
        name: impl Into<String>,
        value: VAttributeValue,
        delimiter: impl Into<String>,
    ) -> Self {
        let name = name.into();

        if let Some(attr_values) = self.data.get_mut(&name) {
            attr_values.values.push_back(value);
        } else {
            let attr_values = VAttributeValues {
                values: vec![value].into(),
                delimiter: delimiter.into(),
            };
            self.data.insert(name, attr_values);
        }

        self
    }

    pub fn insert(self, name: impl Into<String>, value: VAttributeValue) -> Self {
        self.insert_with_delimiter(name, value, " ")
    }

    pub fn delimit(mut self, name: impl Into<String>, delimiter: impl Into<String>) -> Self {
        let name = name.into();

        if let Some(attr_values) = self.data.get_mut(&name) {
            attr_values.delimiter = delimiter.into();
        } else {
            let attr_values = VAttributeValues {
                values: vec![].into(),
                delimiter: delimiter.into(),
            };
            self.data.insert(name, attr_values);
        }

        self
    }

    pub fn string(self, name: impl Into<String>, value: impl Into<String>) -> Self {
        self.insert(name, VAttributeValue::Str(Rc::new(value.into())))
    }

    pub fn nut(self, name: impl Into<String>, value: u64) -> Self {
        self.insert(name, VAttributeValue::Nut(value))
    }

    pub fn int(self, name: impl Into<String>, value: i64) -> Self {
        self.insert(name, VAttributeValue::Int(value))
    }

    pub fn num(self, name: impl Into<String>, value: f64) -> Self {
        self.insert(name, VAttributeValue::Num(value))
    }

    pub fn flag(self, name: impl Into<String>, value: bool) -> Self {
        if value {
            self.insert(name, VAttributeValue::None)
        } else {
            self
        }
    }

    pub fn style(self, style_name: impl Into<String>, value: impl Into<String>) -> Self {
        self.insert_with_delimiter(
            "style",
            VAttributeValue::Str(Rc::new(format!("{}:{}", style_name.into(), value.into()))),
            ";",
        )
    }
}

macro_rules! attr {
    ($name:tt : String / $dlm:tt as $f_name:ident) => {
        pub fn $f_name(self, value: impl Into<String>) -> Self {
            self.insert_with_delimiter($name, VAttributeValue::Str(Rc::new(value.into())), $dlm)
        }
    };

    ($name:tt : u64 / $dlm:tt as $f_name:ident) => {
        pub fn $f_name(self, value: u64) -> Self {
            self.insert_with_delimiter($name, VAttributeValue::Nut(value), $dlm)
        }
    };

    ($name:tt : i64 / $dlm:tt as $f_name:ident) => {
        pub fn $f_name(self, value: i64) -> Self {
            self.insert_with_delimiter($name, VAttributeValue::Int(value), $dlm)
        }
    };

    ($name:tt : f64 / $dlm:tt as $f_name:ident) => {
        pub fn $f_name(self, value: f64) -> Self {
            self.insert_with_delimiter($name, VAttributeValue::Num(value), $dlm)
        }
    };

    ($name:tt : bool / $dlm:tt as $f_name:ident) => {
        pub fn $f_name(self, value: bool) -> Self {
            if value {
                self.insert_with_delimiter($name, VAttributeValue::None, $dlm)
            } else {
                self
            }
        }
    };
}

impl Attributes {
    attr!("checked": bool / " " as checked);
    attr!("class": String / " " as class);
    attr!("draggable": String / " " as draggable);
    attr!("hidden": bool / " " as hidden);
    attr!("href": String / " " as href);
    attr!("id": String / " " as id);
    attr!("placeholder": String / "" as placeholder);
    attr!("src": String / " " as src);
    attr!("title": String / " " as title);
    attr!("type": String / " " as type_);
    attr!("value": String / " " as value);
}

impl std::default::Default for Attributes {
    fn default() -> Self {
        Self::new()
    }
}