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}