lewp_html/api.rs
1use {
2 crate::{BrowsingContext, Charset, Document, Node, NodeExt, Nodes, Script},
3 html5ever::{namespace_url, ns, tendril::Tendril, LocalName, QualName},
4 langtag::LanguageTag,
5 rcdom::NodeData,
6 std::{cell::RefCell, path::Path},
7};
8
9/// Defines an element that only takes children as input variable.
10macro_rules! api_children_only {
11 (
12 $(
13 #[$link:meta]
14 $(#[$outer:meta])*
15 $name:ident, $tag_name:expr
16 )*
17 ) => {
18 $(
19 /// The
20 #[$link]
21 /// element.
22 $(#[$outer])*
23 pub fn $name(children: Nodes) -> Node {
24 new_element($tag_name, children)
25 }
26 )*
27 };
28}
29
30api_children_only! {
31 /// [head](https://html.spec.whatwg.org/dev/semantics.html#the-head-element)
32 head, "head"
33 /// [body](https://html.spec.whatwg.org/dev/sections.html#the-body-element)
34 body, "body"
35 /// [article](https://html.spec.whatwg.org/dev/sections.html#the-article-element)
36 article, "article"
37 /// [section](https://html.spec.whatwg.org/dev/sections.html#the-section-element)
38 section, "section"
39 /// [nav](https://html.spec.whatwg.org/dev/sections.html#the-nav-element)
40 nav, "nav"
41 /// [aside](https://html.spec.whatwg.org/dev/sections.html#the-aside-element)
42 aside, "aside"
43 /// [h1](https://html.spec.whatwg.org/dev/sections.html#the-h1,-h2,-h3,-h4,-h5,-and-h6-elements)
44 h1, "h1"
45 /// [h2](https://html.spec.whatwg.org/dev/sections.html#the-h1,-h2,-h3,-h4,-h5,-and-h6-elements)
46 h2, "h2"
47 /// [h3](https://html.spec.whatwg.org/dev/sections.html#the-h1,-h2,-h3,-h4,-h5,-and-h6-elements)
48 h3, "h3"
49 /// [h4](https://html.spec.whatwg.org/dev/sections.html#the-h1,-h2,-h3,-h4,-h5,-and-h6-elements)
50 h4, "h4"
51 /// [h5](https://html.spec.whatwg.org/dev/sections.html#the-h1,-h2,-h3,-h4,-h5,-and-h6-elements)
52 h5, "h5"
53 /// [h6](https://html.spec.whatwg.org/dev/sections.html#the-h1,-h2,-h3,-h4,-h5,-and-h6-elements)
54 h6, "h6"
55 /// [hgroup](https://html.spec.whatwg.org/dev/sections.html#the-hgroup-element)
56 hgroup, "hgroup"
57 /// [header](https://html.spec.whatwg.org/dev/sections.html#the-header-element)
58 header, "header"
59 /// [footer](https://html.spec.whatwg.org/dev/sections.html#the-footer-element)
60 footer, "footer"
61 /// [address](https://html.spec.whatwg.org/dev/sections.html#the-address-element)
62 address, "address"
63 /// [p](https://html.spec.whatwg.org/dev/grouping-content.html#the-p-element)
64 p, "p"
65 /// [pre](https://html.spec.whatwg.org/dev/grouping-content.html#the-pre-element)
66 pre, "pre"
67 /// [blockquote](https://html.spec.whatwg.org/dev/grouping-content.html#the-blockquote-element)
68 blockquote, "blockquote"
69 /// [ol](https://html.spec.whatwg.org/dev/grouping-content.html#the-ol-element)
70 ol, "ol"
71 /// [ul](https://html.spec.whatwg.org/dev/grouping-content.html#the-ul-element)
72 ul, "ul"
73 /// [menu](https://html.spec.whatwg.org/dev/grouping-content.html#the-menu-element)
74 menu, "menu"
75 /// [li](https://html.spec.whatwg.org/dev/grouping-content.html#the-li-element)
76 li, "li"
77 /// [dl](https://html.spec.whatwg.org/dev/grouping-content.html#the-dl-element)
78 dl, "dl"
79 /// [dt](https://html.spec.whatwg.org/dev/grouping-content.html#the-dt-element)
80 dt, "dt"
81 /// [dd](https://html.spec.whatwg.org/dev/grouping-content.html#the-dd-element)
82 dd, "dd"
83 /// [figure](https://html.spec.whatwg.org/dev/grouping-content.html#the-figure-element)
84 figure, "figure"
85 /// [figcaption](https://html.spec.whatwg.org/dev/grouping-content.html#the-figcaption-element)
86 figcaption, "figcaption"
87 /// [main](https://html.spec.whatwg.org/dev/grouping-content.html#the-main-element)
88 main, "main"
89 /// [div](https://html.spec.whatwg.org/dev/grouping-content.html#the-div-element)
90 div, "div"
91 /// [em](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-em-element)
92 em, "em"
93 /// [strong](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-strong-element)
94 strong, "strong"
95 /// [small](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-small-element)
96 small, "small"
97 /// [s](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-s-element)
98 s, "s"
99 /// [cite](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-cite-element)
100 cite, "cite"
101 /// [q](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-q-element)
102 q, "q"
103 /// [dfn](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-dfn-element)
104 dfn, "dfn"
105 /// [abbr](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-abbr-element)
106 abbr, "abbr"
107 /// [ruby](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-ruby-element)
108 ruby, "ruby"
109 /// [rt](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-rt-element)
110 rt, "rt"
111 /// [rp](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-rp-element)
112 rp, "rp"
113 /// [time](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-time-element)
114 time, "time"
115 /// [code](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-code-element)
116 code, "code"
117 /// [var](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-var-element)
118 var, "var"
119 /// [samp](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-samp-element)
120 samp, "samp"
121 /// [kbd](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-kbd-element)
122 kbd, "kbd"
123 /// [sub](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-sub-and-sup-elements)
124 sub, "sub"
125 /// [sup](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-sub-and-sup-elements)
126 sup, "sup"
127 /// [i](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-i-element)
128 i, "i"
129 /// [b](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-b-element)
130 b, "b"
131 /// [u](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-u-element)
132 u, "u"
133 /// [mark](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-mark-element)
134 mark, "mark"
135 /// [bdi](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-bdi-element)
136 bdi, "bdi"
137 /// [bdo](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-bdo-element)
138 bdo, "bdo"
139 /// [span](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-span-element)
140 span, "span"
141 /// [wbr](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-wbr-element)
142 wbr, "wbr"
143 /// [ins](https://html.spec.whatwg.org/dev/edits.html#the-ins-element)
144 ins, "ins"
145 /// [del](https://html.spec.whatwg.org/dev/edits.html#the-del-element)
146 del, "del"
147 /// [picture](https://html.spec.whatwg.org/dev/embedded-content.html#the-picture-element)
148 picture, "picture"
149 /// [source](https://html.spec.whatwg.org/dev/embedded-content.html#the-source-element)
150 source, "source"
151 /// [iframe](https://html.spec.whatwg.org/dev/iframe-embed-object.html#the-iframe-element)
152 iframe, "iframe"
153 /// [embed](https://html.spec.whatwg.org/dev/iframe-embed-object.html#the-embed-element)
154 embed, "embed"
155 /// [object](https://html.spec.whatwg.org/dev/iframe-embed-object.html#the-object-element)
156 object, "object"
157 /// [video](https://html.spec.whatwg.org/dev/media.html#the-video-element)
158 video, "video"
159 /// [audio](https://html.spec.whatwg.org/dev/media.html#the-audio-element)
160 audio, "audio"
161 /// [track](https://html.spec.whatwg.org/dev/media.html#the-track-element)
162 track, "track"
163 /// [area](https://html.spec.whatwg.org/dev/image-maps.html#the-area-element)
164 area, "area"
165 /// [math](https://html.spec.whatwg.org/dev/embedded-content-other.html#mathml)
166 math, "math"
167 /// [svg](https://html.spec.whatwg.org/dev/embedded-content-other.html#svg-0)
168 svg, "svg"
169 /// [table](https://html.spec.whatwg.org/dev/tables.html#the-table-element)
170 table, "table"
171 /// [caption](https://html.spec.whatwg.org/dev/tables.html#the-caption-element)
172 caption, "caption"
173 /// [colgroup](https://html.spec.whatwg.org/dev/tables.html#the-colgroup-element)
174 colgroup, "colgroup"
175 /// [col](https://html.spec.whatwg.org/dev/tables.html#the-col-element)
176 col, "col"
177 /// [tbody](https://html.spec.whatwg.org/dev/tables.html#the-tbody-element)
178 tbody, "tbody"
179 /// [thead](https://html.spec.whatwg.org/dev/tables.html#the-thead-element)
180 thead, "thead"
181 /// [tfoot](https://html.spec.whatwg.org/dev/tables.html#the-tfoot-element)
182 tfoot, "tfoot"
183 /// [tr](https://html.spec.whatwg.org/dev/tables.html#the-tr-element)
184 tr, "tr"
185 /// [td](https://html.spec.whatwg.org/dev/tables.html#the-td-element)
186 td, "td"
187 /// [th](https://html.spec.whatwg.org/dev/tables.html#the-th-element)
188 th, "th"
189 /// [form](https://html.spec.whatwg.org/dev/forms.html#the-form-element)
190 form, "form"
191 /// [label](https://html.spec.whatwg.org/dev/forms.html#the-label-element)
192 label, "label"
193 /// [input](https://html.spec.whatwg.org/dev/input.html#the-input-element)
194 input, "input"
195 /// [button](https://html.spec.whatwg.org/dev/form-elements.html#the-button-element)
196 button, "button"
197 /// [select](https://html.spec.whatwg.org/dev/form-elements.html#the-select-element)
198 select, "select"
199 /// [datalist](https://html.spec.whatwg.org/dev/form-elements.html#the-datalist-element)
200 datalist, "datalist"
201 /// [optgroup](https://html.spec.whatwg.org/dev/form-elements.html#the-optgroup-element)
202 optgroup, "optgroup"
203 /// [option](https://html.spec.whatwg.org/dev/form-elements.html#the-option-element)
204 option, "option"
205 /// [textarea](https://html.spec.whatwg.org/dev/form-elements.html#the-textarea-element)
206 textarea, "textarea"
207 /// [output](https://html.spec.whatwg.org/dev/form-elements.html#the-output-element)
208 output, "output"
209 /// [progress](https://html.spec.whatwg.org/dev/form-elements.html#the-progress-element)
210 progress, "progress"
211 /// [meter](https://html.spec.whatwg.org/dev/form-elements.html#the-meter-element)
212 meter, "meter"
213 /// [fieldset](https://html.spec.whatwg.org/dev/form-elements.html#the-fieldset-element)
214 fieldset, "fieldset"
215 /// [legend](https://html.spec.whatwg.org/dev/form-elements.html#the-legend-element)
216 legend, "legend"
217 /// [details](https://html.spec.whatwg.org/dev/interactive-elements.html#the-details-element)
218 details, "details"
219 /// [summary](https://html.spec.whatwg.org/dev/interactive-elements.html#the-summary-element)
220 summary, "summary"
221 /// [dialog](https://html.spec.whatwg.org/dev/interactive-elements.html#the-dialog-element)
222 dialog, "dialog"
223 /// [noscript](https://html.spec.whatwg.org/dev/scripting.html#the-noscript-element)
224 noscript, "noscript"
225 /// [template](https://html.spec.whatwg.org/dev/scripting.html#the-template-element)
226 template, "template"
227 /// [slot](https://html.spec.whatwg.org/dev/scripting.html#the-slot-element)
228 slot, "slot"
229 /// [canvas](https://html.spec.whatwg.org/dev/canvas.html#the-canvas-element)
230 canvas, "canvas"
231}
232
233/// Helper function to create a tag node.
234fn new_element(tag_name: &str, children: Nodes) -> Node {
235 let node = rcdom::Node::new(rcdom::NodeData::Element {
236 name: QualName::new(None, ns!(html), LocalName::from(tag_name)),
237 attrs: RefCell::new(vec![]),
238 template_contents: None,
239 mathml_annotation_xml_integration_point: false,
240 });
241 node.append_children(children);
242 node
243}
244
245/// Creates a new document with the given `<html>` node.
246pub fn document(language: LanguageTag, head: Node, body: Node) -> Document {
247 let dom = Document::default();
248 let doctype = rcdom::Node::new(NodeData::Doctype {
249 name: Tendril::from("html"),
250 public_id: Tendril::from(""),
251 system_id: Tendril::from(""),
252 });
253 dom.document.children.borrow_mut().push(doctype);
254 dom.document
255 .children
256 .borrow_mut()
257 .push(html(language, head, body));
258 dom
259}
260
261/// Creates a [html](https://html.spec.whatwg.org/dev/semantics.html#the-html-element) element.
262pub fn html(language: LanguageTag, head: Node, body: Node) -> Node {
263 let language = match language.language() {
264 Some(v) => v.primary().as_str().to_owned(),
265 None => {
266 crate::error!("Could not find language for creating <html> tag!");
267 String::new()
268 }
269 };
270 new_element("html", vec![head, body]).attr("lang", &language)
271}
272
273/// Creates a [title](https://html.spec.whatwg.org/dev/semantics.html#the-title-element) element.
274pub fn title(title: &str) -> Node {
275 new_element("title", vec![text(title)])
276}
277
278/// Creates a [base](https://html.spec.whatwg.org/dev/semantics.html#the-base-element) element.
279pub fn base(href: &str, target: BrowsingContext) -> Node {
280 let mut e = new_element("base", vec![]);
281 if !href.is_empty() {
282 e = e.attr("href", href);
283 }
284 match target {
285 BrowsingContext::Empty => e,
286 _ => e.attr("target", &format!("{}", target)),
287 }
288}
289
290/// Creates a [link](https://html.spec.whatwg.org/dev/semantics.html#the-link-element) element.
291pub fn link(type_: &str, href: &str) -> Node {
292 let mut e = new_element("link", vec![]);
293 if !href.is_empty() {
294 e = e.attr("href", href);
295 }
296 if !type_.is_empty() {
297 e = e.attr("type", type_);
298 }
299 e
300}
301
302/// Creates a [meta](https://html.spec.whatwg.org/dev/semantics.html#the-meta-element) element
303/// without attributes.
304pub fn meta() -> Node {
305 new_element("meta", vec![])
306}
307
308/// Creates a [br](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-br-element) element.
309pub fn br() -> Node {
310 new_element("br", vec![])
311}
312
313/// Creates a [hr](https://html.spec.whatwg.org/dev/grouping-content.html#the-hr-element) element.
314pub fn hr() -> Node {
315 new_element("hr", vec![])
316}
317
318/// Creates a [style](https://html.spec.whatwg.org/dev/semantics.html#the-style-element) element.
319pub fn style(text: Node) -> Node {
320 new_element("style", vec![text])
321}
322
323/// Creates an [anchor](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-a-element) element.
324pub fn a(href: &str, children: Nodes) -> Node {
325 let mut e = new_element("a", children);
326 if !href.is_empty() {
327 e = e.attr("href", href);
328 }
329 e
330}
331
332/// Creates an [data](https://html.spec.whatwg.org/dev/text-level-semantics.html#the-data-element) element.
333pub fn data(value: &str, children: Nodes) -> Node {
334 new_element("a", children).attr("value", value)
335}
336
337/// Creates an [img](https://html.spec.whatwg.org/dev/embedded-content.html#the-img-element) element.
338pub fn img(src: &Path, title: &str, alt: &str) -> Node {
339 new_element("img", vec![]).attrs(vec![
340 ("src", &format!("{}", src.display())),
341 ("alt", alt),
342 ("title", title),
343 ])
344}
345
346/// Creates an [param](https://html.spec.whatwg.org/dev/iframe-embed-object.html#the-param-element) element.
347pub fn param(name: &str, value: &str) -> Node {
348 new_element("param", vec![]).attrs(vec![("name", name), ("value", value)])
349}
350
351/// Creates an [map](https://html.spec.whatwg.org/dev/image-maps.html#the-map-element) element.
352pub fn map(name: &str, children: Nodes) -> Node {
353 new_element("map", children).attr("name", name)
354}
355/// Creates an [script](https://html.spec.whatwg.org/dev/scripting.html#the-script-element) element.
356pub fn script(content: Script) -> Node {
357 match content {
358 Script::Src(src) => new_element("script", vec![]).attr("src", src),
359 Script::Inline(script_text) => {
360 new_element("script", vec![text(script_text)])
361 }
362 }
363}
364
365/// Creates an element with the given custom name.
366pub fn custom(name: &str, children: Nodes) -> Node {
367 new_element(name, children)
368}
369
370/// Creates a text node.
371pub fn text(text: &str) -> Node {
372 rcdom::Node::new(NodeData::Text {
373 contents: RefCell::new(Tendril::from(text)),
374 })
375}
376
377/// Creates a `<meta>` charset tag node.
378pub fn charset(charset: &Charset) -> Node {
379 meta().attr("charset", &charset.to_string())
380}
381
382/// Creates a `<meta>` tag node with description.
383pub fn description(description: &str) -> Node {
384 meta().attrs(vec![("name", "description"), ("content", description)])
385}
386
387/// Creates a `<meta>` viewport tag node.
388pub fn viewport() -> Node {
389 meta().attrs(vec![
390 ("name", "viewport"),
391 (
392 "content",
393 "width=device-width, initial-scale=1.0, user-scalable=no",
394 ),
395 ])
396}