Skip to main content

blitz_html/
html_document.rs

1use std::ops::{Deref, DerefMut};
2
3use crate::DocumentHtmlParser;
4
5use blitz_dom::{BaseDocument, DEFAULT_CSS, DocGuard, DocGuardMut, Document, DocumentConfig};
6
7pub struct HtmlDocument {
8    inner: BaseDocument,
9}
10
11impl Deref for HtmlDocument {
12    type Target = BaseDocument;
13    fn deref(&self) -> &BaseDocument {
14        &self.inner
15    }
16}
17impl DerefMut for HtmlDocument {
18    fn deref_mut(&mut self) -> &mut Self::Target {
19        &mut self.inner
20    }
21}
22impl From<HtmlDocument> for BaseDocument {
23    fn from(doc: HtmlDocument) -> BaseDocument {
24        doc.inner
25    }
26}
27impl Document for HtmlDocument {
28    fn inner(&self) -> DocGuard<'_> {
29        DocGuard::Ref(&self.inner)
30    }
31
32    fn inner_mut(&mut self) -> DocGuardMut<'_> {
33        DocGuardMut::Ref(&mut self.inner)
34    }
35}
36
37impl HtmlDocument {
38    /// Parse HTML (or XHTML) into an [`HtmlDocument`].
39    ///
40    /// The content is sniffed to decide between HTML and XML parsing. Callers which
41    /// know the document is XHTML from out-of-band information (a `Content-Type`
42    /// header or an `.xht`/`.xhtml` file extension) should use
43    /// [`from_xml`](Self::from_xml) instead, as the sniffing cannot detect all
44    /// XHTML documents.
45    pub fn from_html(html: &str, config: DocumentConfig) -> Self {
46        Self::parse_with(html, config, DocumentHtmlParser::parse_into_mutator)
47    }
48
49    /// Parse XML (XHTML) into an [`HtmlDocument`]
50    pub fn from_xml(xml: &str, config: DocumentConfig) -> Self {
51        Self::parse_with(xml, config, DocumentHtmlParser::parse_xml_into_mutator)
52    }
53
54    fn parse_with(
55        content: &str,
56        mut config: DocumentConfig,
57        parse: impl for<'a, 'd> Fn(&'a mut blitz_dom::DocumentMutator<'d>, &str),
58    ) -> Self {
59        if let Some(ss) = &mut config.ua_stylesheets {
60            if !ss.iter().any(|s| s == DEFAULT_CSS) {
61                ss.push(String::from(DEFAULT_CSS));
62            }
63        }
64        let mut doc = BaseDocument::new(config);
65        let mut mutr = doc.mutate();
66        parse(&mut mutr, content);
67        drop(mutr);
68        HtmlDocument { inner: doc }
69    }
70
71    /// Convert the [`HtmlDocument`] into it's inner [`BaseDocument`]
72    pub fn into_inner(self) -> BaseDocument {
73        self.into()
74    }
75}