145 lines
3.3 KiB
Rust
145 lines
3.3 KiB
Rust
use std::collections::{HashMap,HashSet};
|
|
use std;
|
|
|
|
use css;
|
|
|
|
#[derive(Clone)]
|
|
pub struct Attr {
|
|
attrs: HashMap<String, String>,
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct EData {
|
|
pub name: String,
|
|
pub attr: Attr,
|
|
}
|
|
|
|
impl EData {
|
|
pub fn id(&self) -> Option<&String> {
|
|
self.attr.attrs.get("id")
|
|
}
|
|
|
|
pub fn classes(&self) -> HashSet<&str> {
|
|
match self.attr.attrs.get("class") {
|
|
Some(classlist) => classlist.split(' ').collect(),
|
|
None => HashSet::new()
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct SData {
|
|
attr: Attr,
|
|
content: css::Stylesheet,
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub enum NType {
|
|
Text(String),
|
|
Comment(String),
|
|
Element(EData),
|
|
Stylesheet(SData)
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct Node {
|
|
pub children: Vec<Node>,
|
|
pub ntype: NType,
|
|
}
|
|
|
|
pub fn text(d: String) -> Node {
|
|
Node { children: Vec::new(), ntype: NType::Text(d) }
|
|
}
|
|
|
|
pub fn comment(d: String) -> Node {
|
|
Node { children: Vec::new(), ntype: NType::Comment(d) }
|
|
}
|
|
|
|
pub fn elem(name: String, attr: Attr, children: Vec<Node>) -> Node {
|
|
Node {
|
|
children: children,
|
|
ntype: NType::Element(EData {
|
|
name: name,
|
|
attr: attr,
|
|
}),
|
|
}
|
|
}
|
|
|
|
pub fn attr(attrs: HashMap<String, String>) -> Attr {
|
|
Attr { attrs }
|
|
}
|
|
|
|
pub fn style(style: String, attr: Attr) -> Node {
|
|
Node {
|
|
children: Vec::new(),
|
|
ntype: NType::Stylesheet(SData {
|
|
content: css::parse(style),
|
|
attr: attr,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for Node {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
match self.ntype {
|
|
NType::Text(ref s) => write!(f, "{}", s),
|
|
NType::Comment(ref s) => write!(f, "<!--{}-->", s),
|
|
NType::Element(ref d) => {
|
|
write!(f, "<{}{}>", d.name, d.attr);
|
|
for child in self.children.iter() {
|
|
write!(f, "{}", child);
|
|
}
|
|
write!(f, "</{}>", d.name)
|
|
},
|
|
NType::Stylesheet(ref s) => {
|
|
write!(f, "<style {}>{}</style>", s.attr, s.content)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for Attr {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
for (k, v) in self.attrs.iter() {
|
|
write!(f, " {}=\"{}\"", k, v);
|
|
}
|
|
return Result::Ok(())
|
|
}
|
|
}
|
|
|
|
|
|
pub fn find_node(name: String, node: &Node) -> Option<Node> {
|
|
match node.ntype {
|
|
NType::Text(_) | NType::Comment(_) => None,
|
|
NType::Element(ref d) => {
|
|
if d.name == name {
|
|
return Some(node.clone());
|
|
}
|
|
for ref child in &node.children {
|
|
if let Some(n) = find_node(name.clone(), child) {
|
|
return Some(n);
|
|
}
|
|
}
|
|
return None;
|
|
},
|
|
NType::Stylesheet(_) =>
|
|
if name == "style" {
|
|
return Some(node.clone());
|
|
} else {
|
|
return None;
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn find_style(node: &Node) -> Option<css::Stylesheet> {
|
|
match find_node("style".to_string(), node) {
|
|
Some(n) => {
|
|
match n.ntype {
|
|
NType::Stylesheet(d) => Some(d.content),
|
|
_ => None
|
|
}
|
|
}
|
|
_ => None
|
|
}
|
|
}
|