use crate::{
attributes,
node::{Comment, Element, ElementType, Node},
tag::Tag,
text::Text,
url::Url,
};
use attributes::{Attribute, Value};
use std::collections::HashMap;
impl<'a> Node<'a> {
pub fn comment(text: &str) -> Self {
let comment: Comment = text.to_string().into();
comment.into()
}
pub fn text(text: &str) -> Self {
let text: Text = Text::create(text);
text.into()
}
}
impl<'a> Element<'a, ()> {
pub fn external_style(url: Url) -> Self {
let mut el = Element::<()>::create(Tag::LINK);
let url: Value<'a> = url.into();
el.set_attribute(Attribute::REL, Value::STYLESHEET);
el.set_attribute(Attribute::HREF, url);
el
}
}
impl<'a> Element<'a, Vec<Node<'a>>> {
pub fn push<N>(&mut self, node: N) -> ()
where
N: Into<Node<'a>>,
{
let node = node.into();
self.children.push(node);
}
pub fn anchor(url: Value<'a>, label: Text) -> Self {
let mut element = Element::<Vec<Node>>::create(Tag::A);
element.set_attribute(Attribute::HREF, url);
element.push(label);
element.into()
}
pub fn body<N>(children: Vec<N>) -> Self
where
N: Into<Node<'a>>,
{
let mut el = Element::<Vec<Node>>::create(Tag::BODY);
for child in children {
el.push(child);
}
el
}
pub fn html(
lang: Value<'a>,
header: Element<'a, Vec<Node<'a>>>,
body: Element<'a, Vec<Node<'a>>>,
) -> Self {
let mut el = Element::<Vec<Node>>::create(Tag::HTML);
el.set_attribute(Attribute::LANG, lang);
el.push(header);
el.push(body);
el
}
pub fn title(title: Text) -> Self {
let mut el = Element::<Vec<Node>>::create(Tag::TITLE);
el.push(title);
el
}
pub fn inline_script(text: Text) -> Self {
let mut el = Element::<Vec<Node>>::create(Tag::SCRIPT);
el.push(text);
el
}
pub fn external_script(url: Url) -> Self {
let mut el = Element::<Vec<Node>>::create(Tag::SCRIPT);
let url: Value<'a> = url.into();
el.set_attribute(Attribute::SRC, url);
el
}
pub fn inline_style(text: Text) -> Self {
let mut el = Element::<Vec<Node>>::create(Tag::STYLE);
el.push(text);
el
}
pub fn head() -> Self {
Element::<Vec<Node>>::create(Tag::HEAD)
}
pub fn main() -> Self {
Element::<Vec<Node>>::create(Tag::MAIN)
}
}
impl<'a, T> Element<'a, T>
where
T: ElementType,
{
pub fn create(name: Tag<'a>) -> Self {
let attributes = HashMap::default();
let children = T::default();
let element = Element {
name,
attributes,
children,
};
element
}
pub fn set_bool_attribute(&mut self, key: Attribute<'a>) {
self.attributes.insert(key, None);
}
pub fn has_bool_attribute(&self, key: &Attribute<'a>) -> bool {
let attr = self.attributes.get(key);
let result = attr.is_some();
result
}
pub fn has_attribute(&self, key: &Attribute<'a>) -> bool {
let attr = self.attributes.get(key);
let result = attr.map(|x| x.is_some()).unwrap_or(false);
result
}
pub fn set_attribute(&mut self, key: Attribute<'a>, value: Value<'a>) {
self.attributes.insert(key, Some(value));
}
pub fn get_attribute_value(&self, key: &Attribute<'a>) -> &Option<Value<'a>> {
match self.attributes.get(key) {
None => &None,
Some(value) => value,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::attributes::Attribute;
#[test]
fn has_attribute_bool() {
let mut el = Element::<()>::create(Tag::BODY);
el.attributes.insert(Attribute::ID, None);
let result = el.has_bool_attribute(&Attribute::ID);
assert!(result);
}
#[test]
fn has_attribute() {
let value = Value::STYLESHEET;
let mut el = Element::<()>::create(Tag::BODY);
el.attributes.insert(Attribute::ID, Some(value));
let result = el.has_attribute(&Attribute::ID);
assert!(result);
}
#[test]
fn get_attribute_value() {
let value = Value::STYLESHEET;
let mut el = Element::<()>::create(Tag::BODY);
el.attributes.insert(Attribute::ID, Some(value));
let result = el.get_attribute_value(&Attribute::ID);
let expected = &Some(Value::STYLESHEET);
assert_eq!(result, expected);
}
}