use {
crate::{BrowsingContext, Charset, Document, Node, NodeExt, Nodes, Script},
html5ever::{namespace_url, ns, tendril::Tendril, LocalName, QualName},
langtag::LanguageTag,
rcdom::NodeData,
std::{cell::RefCell, path::Path},
};
macro_rules! api_children_only {
(
$(
#[$link:meta]
$(#[$outer:meta])*
$name:ident, $tag_name:expr
)*
) => {
$(
/// The
#[$link]
/// element.
$(#[$outer])*
pub fn $name(children: Nodes) -> Node {
new_element($tag_name, children)
}
)*
};
}
api_children_only! {
head, "head"
body, "body"
article, "article"
section, "section"
nav, "nav"
aside, "aside"
h1, "h1"
h2, "h2"
h3, "h3"
h4, "h4"
h5, "h5"
h6, "h6"
hgroup, "hgroup"
header, "header"
footer, "footer"
address, "address"
p, "p"
pre, "pre"
blockquote, "blockquote"
ol, "ol"
ul, "ul"
menu, "menu"
li, "li"
dl, "dl"
dt, "dt"
dd, "dd"
figure, "figure"
figcaption, "figcaption"
main, "main"
div, "div"
em, "em"
strong, "strong"
small, "small"
s, "s"
cite, "cite"
q, "q"
dfn, "dfn"
abbr, "abbr"
ruby, "ruby"
rt, "rt"
rp, "rp"
time, "time"
code, "code"
var, "var"
samp, "samp"
kbd, "kbd"
sub, "sub"
sup, "sup"
i, "i"
b, "b"
u, "u"
mark, "mark"
bdi, "bdi"
bdo, "bdo"
span, "span"
wbr, "wbr"
ins, "ins"
del, "del"
picture, "picture"
source, "source"
iframe, "iframe"
embed, "embed"
object, "object"
video, "video"
audio, "audio"
track, "track"
area, "area"
math, "math"
svg, "svg"
table, "table"
caption, "caption"
colgroup, "colgroup"
col, "col"
tbody, "tbody"
thead, "thead"
tfoot, "tfoot"
tr, "tr"
td, "td"
th, "th"
form, "form"
label, "label"
input, "input"
button, "button"
select, "select"
datalist, "datalist"
optgroup, "optgroup"
option, "option"
textarea, "textarea"
output, "output"
progress, "progress"
meter, "meter"
fieldset, "fieldset"
legend, "legend"
details, "details"
summary, "summary"
dialog, "dialog"
noscript, "noscript"
template, "template"
slot, "slot"
canvas, "canvas"
}
fn new_element(tag_name: &str, children: Nodes) -> Node {
let node = rcdom::Node::new(rcdom::NodeData::Element {
name: QualName::new(None, ns!(html), LocalName::from(tag_name)),
attrs: RefCell::new(vec![]),
template_contents: None,
mathml_annotation_xml_integration_point: false,
});
node.append_children(children);
node
}
pub fn document(language: LanguageTag, head: Node, body: Node) -> Document {
let dom = Document::default();
let doctype = rcdom::Node::new(NodeData::Doctype {
name: Tendril::from("html"),
public_id: Tendril::from(""),
system_id: Tendril::from(""),
});
dom.document.children.borrow_mut().push(doctype);
dom.document
.children
.borrow_mut()
.push(html(language, head, body));
dom
}
pub fn html(language: LanguageTag, head: Node, body: Node) -> Node {
let language = match language.language() {
Some(v) => v.primary().as_str().to_owned(),
None => {
crate::error!("Could not find language for creating <html> tag!");
String::new()
}
};
new_element("html", vec![head, body]).attr("lang", &language)
}
pub fn title(title: &str) -> Node {
new_element("title", vec![text(title)])
}
pub fn base(href: &str, target: BrowsingContext) -> Node {
let mut e = new_element("base", vec![]);
if !href.is_empty() {
e = e.attr("href", href);
}
match target {
BrowsingContext::Empty => e,
_ => e.attr("target", &format!("{}", target)),
}
}
pub fn link(type_: &str, href: &str) -> Node {
let mut e = new_element("link", vec![]);
if !href.is_empty() {
e = e.attr("href", href);
}
if !type_.is_empty() {
e = e.attr("type", type_);
}
e
}
pub fn meta() -> Node {
new_element("meta", vec![])
}
pub fn br() -> Node {
new_element("br", vec![])
}
pub fn hr() -> Node {
new_element("hr", vec![])
}
pub fn style(text: Node) -> Node {
new_element("style", vec![text])
}
pub fn a(href: &str, children: Nodes) -> Node {
let mut e = new_element("a", children);
if !href.is_empty() {
e = e.attr("href", href);
}
e
}
pub fn data(value: &str, children: Nodes) -> Node {
new_element("a", children).attr("value", value)
}
pub fn img(src: &Path, title: &str, alt: &str) -> Node {
new_element("img", vec![]).attrs(vec![
("src", &format!("{}", src.display())),
("alt", alt),
("title", title),
])
}
pub fn param(name: &str, value: &str) -> Node {
new_element("param", vec![]).attrs(vec![("name", name), ("value", value)])
}
pub fn map(name: &str, children: Nodes) -> Node {
new_element("map", children).attr("name", name)
}
pub fn script(content: Script) -> Node {
match content {
Script::Src(src) => new_element("script", vec![]).attr("src", src),
Script::Inline(script_text) => {
new_element("script", vec![text(script_text)])
}
}
}
pub fn custom(name: &str, children: Nodes) -> Node {
new_element(name, children)
}
pub fn text(text: &str) -> Node {
rcdom::Node::new(NodeData::Text {
contents: RefCell::new(Tendril::from(text)),
})
}
pub fn charset(charset: &Charset) -> Node {
meta().attr("charset", &charset.to_string())
}
pub fn description(description: &str) -> Node {
meta().attrs(vec![("name", "description"), ("content", description)])
}
pub fn viewport() -> Node {
meta().attrs(vec![
("name", "viewport"),
(
"content",
"width=device-width, initial-scale=1.0, user-scalable=no",
),
])
}