#[rustfmt::skip]
macro_rules! html_elem {
( $el:literal, $elem:ident, $desc:literal, $items:ident() ) => {
html_elem!($el, $elem, $desc, $items(), ElemType::Html);
};
( $el:literal, $elem:ident, $desc:literal, $items:ident(), $tp:expr ) => {
#[doc = concat!(
"`<",
$el,
">`: [",
$desc,
"](",
"https://developer.mozilla.org/en-US/docs/Web/HTML/",
"Reference/Elements/",
stringify!($elem),
") element",
)]
pub struct $elem<'t> {
pub(crate) tree: &'t mut Tree,
pub(crate) depth: usize,
}
#[doc = concat!("`<", $el, ">` items")]
impl<'t> $elem<'t> {
$items!( $el );
#[doc = "Close the element"]
#[doc = ""]
#[doc = concat!(
"- Closes all child elements\n",
"- Adds the closing tag if necessary (e.g. `</",
$el,
">`)"
)]
pub fn close(&'t mut self) -> &'t mut Tree {
self.tree.close_to(self.depth);
self.tree
}
}
#[doc = "Global attributes"]
impl<'t> $elem<'t> {
global_attributes!();
}
impl<'t> Element<'t> for $elem<'t> {
const TAG: &'static str = $el;
const TP: ElemType = $tp;
fn new(tree: &'t mut Tree) -> Self {
$elem { tree, depth: 1 }
}
}
};
}
#[rustfmt::skip]
macro_rules! val_attr {
( $path:expr, $attr:ident, $raw_attr:expr ) => {
#[doc = concat!(
"Add [",
$raw_attr,
"](",
"https://developer.mozilla.org/en-US/docs/",
$path,
$raw_attr,
") attribute",
)]
pub fn $attr<'a, V>(&mut self, val: V) -> &mut Self
where
V: Into<Value<'a>>,
{
self.tree.attr($raw_attr, val);
self
}
};
}
#[rustfmt::skip]
macro_rules! bool_attr {
( $path:expr, $attr:ident, $raw_attr:expr ) => {
#[doc = concat!(
"Add [",
$raw_attr,
"](",
"https://developer.mozilla.org/en-US/docs/",
$path,
$raw_attr,
") Boolean attribute",
)]
pub fn $attr(&mut self) -> &mut Self {
self.tree.attr_bool($raw_attr);
self
}
};
}
macro_rules! html_attr {
( $el:expr, $attr:ident ) => {
val_attr!(
concat!("Web/HTML/Reference/Elements/", $el, "#"),
$attr,
stringify!($attr)
);
};
( $el:expr, $attr:ident, true ) => {
bool_attr!(
concat!("Web/HTML/Reference/Elements/", $el, "#"),
$attr,
stringify!($attr)
);
};
( $el:expr, $attr:ident, $raw_attr:literal ) => {
val_attr!(
concat!("Web/HTML/Reference/Elements/", $el, "#"),
$attr,
$raw_attr
);
};
( $el:expr, $attr:ident, $raw_attr:literal, true ) => {
bool_attr!(
concat!("Web/HTML/Reference/Elements/", $el, "#"),
$attr,
$raw_attr
);
};
}
macro_rules! global_attribute {
( $attr:ident ) => {
val_attr!(
"Web/HTML/Reference/Global_attributes/#",
$attr,
stringify!($attr)
);
};
( $attr:ident, true ) => {
bool_attr!(
"Web/HTML/Reference/Global_attributes/#",
$attr,
stringify!($attr)
);
};
}
macro_rules! aria_attribute {
( $attr:ident, $raw_attr:literal ) => {
val_attr!(
concat!("Web/Accessibility/ARIA/Reference/Attributes/"),
$attr,
$raw_attr
);
};
}
macro_rules! data_attribute {
() => {
pub fn data_<'a, V>(&mut self, name: &str, val: V) -> &mut Self
where
V: Into<Value<'a>>,
{
self.tree.attr(&format!("data-{name}"), val);
self
}
};
}
macro_rules! global_attributes {
() => {
global_attribute!(id);
global_attribute!(class);
global_attribute!(accesskey);
global_attribute!(autocapitalize);
global_attribute!(autocorrect);
global_attribute!(autofocus, true);
global_attribute!(contenteditable);
data_attribute!();
global_attribute!(dir);
global_attribute!(draggable);
global_attribute!(enterkeyhint);
global_attribute!(exportparts);
global_attribute!(hidden);
global_attribute!(inert, true);
global_attribute!(inputmode);
global_attribute!(is);
global_attribute!(itemid);
global_attribute!(itemprop);
global_attribute!(itemref);
global_attribute!(itemscope, true);
global_attribute!(itemtype);
global_attribute!(lang);
global_attribute!(nonce);
global_attribute!(onblur);
global_attribute!(onchange);
global_attribute!(onclick);
global_attribute!(onclose);
global_attribute!(onerror);
global_attribute!(onfocus);
global_attribute!(part);
global_attribute!(popover);
global_attribute!(role);
global_attribute!(slot);
global_attribute!(spellcheck);
global_attribute!(style);
global_attribute!(tabindex);
global_attribute!(title);
global_attribute!(translate);
aria_attribute!(aria_atomic, "aria-atomic");
aria_attribute!(aria_busy, "aria-busy");
aria_attribute!(aria_controls, "aria-controls");
aria_attribute!(aria_current, "aria-current");
aria_attribute!(aria_describedby, "aria-describedby");
aria_attribute!(aria_description, "aria-description");
aria_attribute!(aria_details, "aria-details");
aria_attribute!(aria_disabled, "aria-disabled");
aria_attribute!(aria_errormessage, "aria-errormessage");
aria_attribute!(aria_flowto, "aria-flowto");
aria_attribute!(aria_haspopup, "aria-haspopup");
aria_attribute!(aria_hidden, "aria-hidden");
aria_attribute!(aria_invalid, "aria-invalid");
aria_attribute!(aria_keyshortcuts, "aria-keyshortcuts");
aria_attribute!(aria_label, "aria-label");
aria_attribute!(aria_labelledby, "aria-labelledby");
aria_attribute!(aria_live, "aria-live");
aria_attribute!(aria_owns, "aria-owns");
aria_attribute!(aria_relevant, "aria-relevant");
aria_attribute!(aria_roledescription, "aria-roledescription");
};
}
macro_rules! elem_method {
( $meth:ident, $elem:ident ) => {
#[doc = concat!("Add `", stringify!($elem), "` child element")]
#[allow(clippy::self_named_constructors)]
pub fn $meth(self: &mut Self) -> $elem<'_> {
let depth = self.tree.elem($elem::TAG, $elem::TP);
$elem {
tree: self.tree,
depth,
}
}
};
}
macro_rules! cdata_methods {
() => {
pub fn cdata<'a, V>(&mut self, text: V) -> &mut Self
where
V: Into<Value<'a>>,
{
self.tree.cdata(text);
self
}
pub fn cdata_len<'a, V>(&mut self, text: V, len: usize) -> &mut Self
where
V: Into<Value<'a>>,
{
self.tree.cdata_len(text, len);
self
}
};
}
macro_rules! comment_raw_methods {
() => {
pub fn comment<'v, V>(&mut self, com: V) -> &mut Self
where
V: Into<Value<'v>>,
{
self.tree.comment(com);
self
}
pub fn raw(&mut self, trusted: impl AsRef<str>) -> &mut Self {
self.tree.raw(trusted);
self
}
};
}
macro_rules! metadata_content {
() => {
elem_method!(base, Base);
elem_method!(link, Link);
elem_method!(meta, Meta);
elem_method!(noscript, NoScript);
elem_method!(script, Script);
elem_method!(style_el, Style);
elem_method!(template, Template);
elem_method!(title_el, Title);
comment_raw_methods!();
};
}
macro_rules! flow_content {
($abbr:ident, $cite:ident, $form:ident) => {
cdata_methods!();
elem_method!(a, A);
elem_method!($abbr, Abbr);
elem_method!(address, Address);
elem_method!(article, Article);
elem_method!(aside, Aside);
elem_method!(audio, Audio);
elem_method!(b, B);
elem_method!(bdi, Bdi);
elem_method!(bdo, Bdo);
elem_method!(blockquote, BlockQuote);
elem_method!(br, Br);
elem_method!(button, Button);
elem_method!(canvas, Canvas);
elem_method!($cite, Cite);
elem_method!(code, Code);
elem_method!(data, Data);
elem_method!(datalist, DataList);
elem_method!(del, Del);
elem_method!(details, Details);
elem_method!(dfn, Dfn);
elem_method!(dialog, Dialog);
elem_method!(div, Div);
elem_method!(dl, Dl);
elem_method!(em, Em);
elem_method!(embed, Embed);
elem_method!(fieldset, FieldSet);
elem_method!(figure, Figure);
elem_method!(footer, Footer);
elem_method!($form, Form);
elem_method!(h1, H1);
elem_method!(h2, H2);
elem_method!(h3, H3);
elem_method!(h4, H4);
elem_method!(h5, H5);
elem_method!(h6, H6);
elem_method!(header, Header);
elem_method!(hgroup, HGroup);
elem_method!(hr, Hr);
elem_method!(i, I);
elem_method!(iframe, IFrame);
elem_method!(img, Img);
elem_method!(input, Input);
elem_method!(ins, Ins);
elem_method!(kbd, Kbd);
elem_method!(label, Label);
elem_method!(main, Main);
elem_method!(map, Map);
elem_method!(mark, Mark);
elem_method!(menu, Menu);
elem_method!(meter, Meter);
elem_method!(nav, Nav);
elem_method!(noscript, NoScript);
elem_method!(object, Object);
elem_method!(ol, Ol);
elem_method!(output, Output);
elem_method!(p, P);
elem_method!(picture, Picture);
elem_method!(pre, Pre);
elem_method!(progress, Progress);
elem_method!(q, Q);
elem_method!(ruby, Ruby);
elem_method!(s, S);
elem_method!(samp, Samp);
elem_method!(script, Script);
elem_method!(search, Search);
elem_method!(section, Section);
elem_method!(select, Select);
elem_method!(slot_el, Slot); elem_method!(small, Small);
elem_method!(span, Span);
elem_method!(strong, Strong);
elem_method!(sub, Sub);
elem_method!(sup, Sup);
elem_method!(svg, Svg);
elem_method!(table, Table);
elem_method!(template, Template);
elem_method!(textarea, TextArea);
elem_method!(time, Time);
elem_method!(u, U);
elem_method!(ul, Ul);
elem_method!(var, Var);
elem_method!(video, Video);
elem_method!(wbr, Wbr);
comment_raw_methods!();
};
}
macro_rules! phrasing_content {
($cite:ident) => {
cdata_methods!();
elem_method!(a, A); elem_method!(abbr, Abbr);
elem_method!(area, Area); elem_method!(audio, Audio);
elem_method!(b, B);
elem_method!(bdi, Bdi);
elem_method!(bdo, Bdo);
elem_method!(br, Br);
elem_method!(button, Button);
elem_method!(canvas, Canvas);
elem_method!($cite, Cite);
elem_method!(code, Code);
elem_method!(data, Data);
elem_method!(datalist, DataList);
elem_method!(del, Del); elem_method!(dfn, Dfn);
elem_method!(em, Em);
elem_method!(embed, Embed);
elem_method!(i, I);
elem_method!(iframe, IFrame);
elem_method!(img, Img);
elem_method!(input, Input);
elem_method!(ins, Ins); elem_method!(kbd, Kbd);
elem_method!(label, Label);
elem_method!(link, Link); elem_method!(map, Map); elem_method!(mark, Mark);
elem_method!(meta, Meta); elem_method!(meter, Meter);
elem_method!(noscript, NoScript);
elem_method!(object, Object);
elem_method!(output, Output);
elem_method!(picture, Picture);
elem_method!(progress, Progress);
elem_method!(q, Q);
elem_method!(ruby, Ruby);
elem_method!(s, S);
elem_method!(samp, Samp);
elem_method!(script, Script);
elem_method!(select, Select);
elem_method!(slot_el, Slot);
elem_method!(small, Small);
elem_method!(span, Span);
elem_method!(strong, Strong);
elem_method!(sub, Sub);
elem_method!(sup, Sup);
elem_method!(svg, Svg);
elem_method!(template, Template);
elem_method!(textarea, TextArea);
elem_method!(time, Time);
elem_method!(u, U);
elem_method!(var, Var);
elem_method!(video, Video);
elem_method!(wbr, Wbr);
comment_raw_methods!();
};
}
macro_rules! non_interactive_phrasing_content {
() => {
cdata_methods!();
elem_method!(abbr, Abbr);
elem_method!(area, Area); elem_method!(b, B);
elem_method!(bdi, Bdi);
elem_method!(bdo, Bdo);
elem_method!(br, Br);
elem_method!(canvas, Canvas);
elem_method!(cite, Cite);
elem_method!(code, Code);
elem_method!(data, Data);
elem_method!(datalist, DataList);
elem_method!(del, Del); elem_method!(dfn, Dfn);
elem_method!(em, Em);
elem_method!(i, I);
elem_method!(img, Img); elem_method!(ins, Ins); elem_method!(kbd, Kbd);
elem_method!(link, Link); elem_method!(map, Map); elem_method!(mark, Mark);
elem_method!(meta, Meta); elem_method!(meter, Meter);
elem_method!(noscript, NoScript);
elem_method!(object, Object); elem_method!(output, Output);
elem_method!(picture, Picture);
elem_method!(progress, Progress);
elem_method!(q, Q);
elem_method!(ruby, Ruby);
elem_method!(s, S);
elem_method!(samp, Samp);
elem_method!(script, Script);
elem_method!(slot_el, Slot);
elem_method!(small, Small);
elem_method!(span, Span);
elem_method!(strong, Strong);
elem_method!(sub, Sub);
elem_method!(sup, Sup);
elem_method!(svg, Svg);
elem_method!(template, Template);
elem_method!(time, Time);
elem_method!(u, U);
elem_method!(var, Var);
elem_method!(wbr, Wbr);
comment_raw_methods!();
};
}
macro_rules! text_content {
() => {
cdata_methods!();
comment_raw_methods!();
};
}
macro_rules! address_content {
() => {
cdata_methods!();
elem_method!(a, A);
elem_method!(abbr, Abbr);
elem_method!(audio, Audio);
elem_method!(b, B);
elem_method!(bdi, Bdi);
elem_method!(bdo, Bdo);
elem_method!(blockquote, BlockQuote);
elem_method!(br, Br);
elem_method!(button, Button);
elem_method!(canvas, Canvas);
elem_method!(cite, Cite);
elem_method!(code, Code);
elem_method!(data, Data);
elem_method!(datalist, DataList);
elem_method!(del, Del);
elem_method!(details, Details);
elem_method!(dfn, Dfn);
elem_method!(dialog, Dialog);
elem_method!(div, Div);
elem_method!(dl, Dl);
elem_method!(em, Em);
elem_method!(embed, Embed);
elem_method!(fieldset, FieldSet);
elem_method!(figure, Figure);
elem_method!(form, Form);
elem_method!(hr, Hr);
elem_method!(i, I);
elem_method!(iframe, IFrame);
elem_method!(img, Img);
elem_method!(input, Input);
elem_method!(ins, Ins);
elem_method!(kbd, Kbd);
elem_method!(label, Label);
elem_method!(main, Main);
elem_method!(map, Map);
elem_method!(mark, Mark);
elem_method!(menu, Menu);
elem_method!(meter, Meter);
elem_method!(noscript, NoScript);
elem_method!(object, Object);
elem_method!(ol, Ol);
elem_method!(output, Output);
elem_method!(p, P);
elem_method!(picture, Picture);
elem_method!(pre, Pre);
elem_method!(progress, Progress);
elem_method!(q, Q);
elem_method!(ruby, Ruby);
elem_method!(s, S);
elem_method!(samp, Samp);
elem_method!(script, Script);
elem_method!(search, Search);
elem_method!(select, Select);
elem_method!(slot_el, Slot);
elem_method!(small, Small);
elem_method!(span, Span);
elem_method!(strong, Strong);
elem_method!(sub, Sub);
elem_method!(sup, Sup);
elem_method!(svg, Svg);
elem_method!(table, Table);
elem_method!(template, Template);
elem_method!(textarea, TextArea);
elem_method!(time, Time);
elem_method!(u, U);
elem_method!(ul, Ul);
elem_method!(var, Var);
elem_method!(video, Video);
elem_method!(wbr, Wbr);
comment_raw_methods!();
};
}
#[rustfmt::skip]
macro_rules! svg_elem {
( $el:literal, $elem:ident, $desc:literal, $items:ident() ) => {
svg_elem!($el, $elem, $desc, $items(), ElemType::Xml);
};
( $el:literal, $elem:ident, $desc:literal, $items:ident(), $tp:expr ) => {
#[doc = concat!(
"`<",
$el,
">`: [",
$desc,
"](",
"https://developer.mozilla.org/en-US/docs/Web/SVG/",
"Reference/Element/",
stringify!($elem),
") SVG element",
)]
pub struct $elem<'t> {
pub(crate) tree: &'t mut Tree,
pub(crate) depth: usize,
}
#[doc = concat!("`<", $el, ">` items")]
impl<'t> $elem<'t> {
$items!( $el );
#[doc = "Close the element"]
#[doc = ""]
#[doc = concat!(
"- Closes all child elements\n",
"- Adds the closing tag if necessary (e.g. `</",
$el,
">`)"
)]
pub fn close(&'t mut self) -> &'t mut Tree {
self.tree.close_to(self.depth);
self.tree
}
}
#[doc = "Global SVG attributes"]
impl<'t> $elem<'t> {
svg_global_attributes!();
}
impl<'t> Element<'t> for $elem<'t> {
const TAG: &'static str = $el;
const TP: ElemType = $tp;
fn new(tree: &'t mut Tree) -> Self {
$elem { tree, depth: 1 }
}
}
}
}
macro_rules! svg_attr {
( $attr:ident ) => {
svg_attr!($attr, stringify!($attr));
};
( $attr:ident, $raw_attr:expr ) => {
val_attr!("Web/SVG/Reference/Attribute/", $attr, $raw_attr);
};
( $attr:ident, $raw_attr:expr, true ) => {
bool_attr!("Web/SVG/Reference/Attribute/", $attr, $raw_attr);
};
}
macro_rules! svg_global_attributes {
() => {
svg_attr!(id);
svg_attr!(class);
svg_attr!(style);
svg_attr!(autofocus, "autofocus", true);
svg_attr!(lang);
svg_attr!(tabindex);
svg_attr!(transform);
data_attribute!();
};
}
macro_rules! svg_support_attr {
() => {
svg_attr!(required_extensions, "requiredExtensions");
svg_attr!(system_language, "systemLanguage");
};
}
macro_rules! svg_graphics {
() => {
elem_method!(circle, Circle);
elem_method!(ellipse, Ellipse);
elem_method!(image, Image);
elem_method!(line, Line);
elem_method!(path, Path);
elem_method!(polygon, Polygon);
elem_method!(polyline, Polyline);
elem_method!(rect, Rect);
elem_method!(text, Text);
elem_method!(r#use, Use);
};
}
macro_rules! svg_container {
() => {
elem_method!(a, A);
elem_method!(defs, Defs);
elem_method!(g, G);
elem_method!(marker, Marker);
elem_method!(mask, Mask);
elem_method!(pattern, Pattern);
elem_method!(svg, Svg);
elem_method!(switch, Switch);
elem_method!(symbol, Symbol);
};
}
macro_rules! svg_descriptive {
($title:ident) => {
elem_method!(desc, Desc);
elem_method!(metadata, Metadata);
elem_method!($title, Title);
};
}
macro_rules! svg_gradient {
() => {
elem_method!(linear_gradient, LinearGradient);
elem_method!(radial_gradient, RadialGradient);
elem_method!(stop, Stop);
};
}
macro_rules! svg_other {
() => {
elem_method!(clip_path, ClipPath);
elem_method!(filter, Filter);
elem_method!(foreign_object, ForeignObject);
elem_method!(script, Script);
elem_method!(style_el, Style);
elem_method!(view, View);
};
}
macro_rules! svg_animation {
() => {
elem_method!(animate, Animate);
elem_method!(animate_motion, AnimateMotion);
elem_method!(animate_transform, AnimateTransform);
elem_method!(mpath, MPath);
elem_method!(set, Set);
};
}
macro_rules! svg_content {
($title:ident) => {
svg_graphics!();
svg_container!();
svg_descriptive!($title);
svg_gradient!();
svg_other!();
svg_animation!();
};
}
#[rustfmt::skip]
macro_rules! css_prop {
( $prop:ident, $raw_prop:expr ) => {
#[doc = concat!(
"Add [",
$raw_prop,
"](",
"https://developer.mozilla.org/en-US/docs/",
"Web/CSS/Reference/Properties/",
$raw_prop,
") property",
)]
pub fn $prop<'a, V>(mut self, v: V) -> Self
where
V: Into<crate::css::Val<'a>>,
{
self.push_sep();
self.val.push_str($raw_prop);
self.val.push_str(": ");
let _ = write!(self.val, "{}", v.into());
self
}
};
( $prop:ident ) => {
css_prop!(
$prop,
stringify!($prop)
);
};
}