use crate::html::Node as N;
use crate::rcdom::Node;
use crate::rcdom::NodeData;
pub use crate::rcdom::RcDom;
use html5ever::driver::parse_document;
use html5ever::driver::parse_fragment;
use html5ever::driver::ParseOpts;
use html5ever::tendril::stream::TendrilSink;
use html5ever::tree_builder::TreeBuilderOpts;
use html5ever::{namespace_url, ns};
use markup5ever::Attribute;
use markup5ever::{LocalName, QualName};
use std::cell::RefCell;
use std::rc::Rc;
pub(crate) fn parse_html(html: String) -> N {
let full_doc = {
let html = html.to_lowercase();
html.contains("<html")
|| html.contains("<body")
|| html.contains("<head")
|| html.contains("<!DOCTYPE")
};
if full_doc {
parse(html)
} else {
match parse_frag(html, "template".to_owned()) {
N::Document { ref children } => match &children[..] {
[N::Element {
ref name,
ref attrs,
children,
}] if name == "html" && attrs.is_empty() => N::Document {
children: children.clone(),
},
_ => panic!("!!!!!!!!"),
},
_ => panic!("#"),
}
}
}
fn parse(html: String) -> N {
let sink: RcDom = Default::default();
let parser = parse_document(
sink,
ParseOpts {
tokenizer: Default::default(),
tree_builder: TreeBuilderOpts {
scripting_enabled: false,
..Default::default()
},
},
);
let dom = parser.one(html);
nodeify_node(&dom.document)
}
fn parse_frag(html: String, context_local_name: String) -> N {
let sink: RcDom = Default::default();
let parser = parse_fragment(
sink,
Default::default(),
QualName::new(None, ns!(html), LocalName::from(context_local_name)),
vec![],
);
let dom = parser.one(html);
nodeify_node(&dom.document)
}
fn nodeify_node(dom: &Rc<Node>) -> N {
match dom.data {
NodeData::Document => {
let mut children = vec![];
for c in dom.children.borrow().iter() {
children.push(nodeify_node(c));
}
N::Document { children }
}
NodeData::Element {
ref name,
ref attrs,
ref template_contents,
..
} => {
let mut name = name.local.to_string();
let attrs = nodify_attrs(attrs);
let mut children = vec![];
if let Some(contents) = template_contents {
children.push(nodeify_node(&contents));
} else {
for child in dom.children.borrow().iter() {
children.push(nodeify_node(&child));
}
}
if name == "template" && attrs.iter().any(|(name, _val)| name.starts_with("pl-")) {
name = "pl-template".to_owned();
}
N::Element {
name,
attrs,
children,
}
}
NodeData::Text { ref contents } => N::Text {
content: contents.borrow().to_string(),
},
NodeData::Comment { ref contents } => N::Comment {
content: contents.to_string(),
},
NodeData::Doctype {
ref name,
public_id: _,
system_id: _,
} => N::Doctype {
doctype: name.to_string(),
},
_ => {
panic!();
}
}
}
fn nodify_attrs(data: &RefCell<Vec<Attribute>>) -> Vec<(String, String)> {
let mut attrs = vec![];
for attr in data.borrow().iter() {
attrs.push((attr.name.local.to_string(), attr.value.to_string()));
}
attrs
}