hatmel/
model.rs

1/// The HTML namespace (xhtml)
2pub const NS_HTML: &str = "http://www.w3.org/1999/xhtml";
3/// Empty (default) namespace
4pub const NS_DEFAULT: &str = "";
5
6/// Shortcut for string caching of local names
7pub type LocalName = string_cache::Atom<super::LocalNameStaticSet>;
8/// Shortcut for string caching of ns prefixes
9pub type Prefix = string_cache::Atom<super::PrefixStaticSet>;
10/// Shortcut for string caching of namespaces
11pub type Namespace = string_cache::Atom<super::NamespaceStaticSet>;
12/// The node handle in the tree you can use to query the doc
13pub type Handle = usize;
14
15/// Compare two namespaces for equality or equivalence in case of
16/// empty (default) namespace and html namespace which is the default
17pub fn namespace_equals_or_html(ns1: &str, ns2: &str) -> bool {
18    match (ns1, ns2) {
19        (NS_DEFAULT, NS_HTML) | (NS_HTML, NS_DEFAULT) => true,
20        (want, have) => want == have,
21    }
22}
23
24/// A document's quirks mode, for compatibility with old browsers. See [quirks mode on wikipedia]
25/// for more information.
26///
27/// [quirks mode on wikipedia]: https://en.wikipedia.org/wiki/Quirks_mode
28#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
29pub enum QuirksMode {
30    /// Full quirks mode
31    Quirks,
32    /// Almost standards mode
33    LimitedQuirks,
34    /// Standards mode
35    NoQuirks,
36}
37
38/// Represents an HTML element in the DOM tree
39#[derive(Default, Debug, Clone)]
40pub struct Element {
41    pub name: LocalName,
42    pub namespace: Namespace,
43    pub prefix: Option<Prefix>,
44    pub attrs: Vec<Attribute>,
45    pub kind: ElementKind,
46}
47/// Represents an HTML attribute in the DOM tree
48#[derive(Default, Debug, Clone)]
49pub struct Attribute {
50    pub name: LocalName,
51    pub namespace: Namespace,
52    pub prefix: Option<Prefix>,
53    pub value: super::StrTendril,
54}
55
56/// Most elements are equal, except...
57#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
58pub enum ElementKind {
59    /// The usual element
60    #[default]
61    Regular,
62    /// Template element is not part of the document per se
63    Template,
64    /// a.k.a. mathml_annotation_xml_integration_point?
65    MathmlPoint,
66}
67
68/// Represents the node content in the DOM tree
69#[derive(Debug, Clone)]
70pub enum Content {
71    Document,
72    Element(Element),
73    Comment {
74        text: String,
75    },
76    ProcessingInstruction {
77        target: String,
78        data: String,
79    },
80    Text {
81        text: String,
82    },
83    DocType {
84        name: String,
85        public_id: String,
86        system_id: String,
87    },
88}
89impl Content {
90    /// Get the element name (if the node is an element) and return the local name and the namespace
91    pub fn element_name(&self) -> Option<(&str, &str)> {
92        match self {
93            // these nodes are not elements
94            Content::Document
95            | Content::Element(Element {
96                kind: ElementKind::Template,
97                ..
98            })
99            | Content::Comment { .. }
100            | Content::ProcessingInstruction { .. }
101            | Content::Text { .. }
102            | Content::DocType { .. } => None,
103            // hey! it's a regular element!
104            Content::Element(Element {
105                name, namespace, ..
106            }) => Some((name, namespace)),
107        }
108    }
109    /// Get attributes if the node is an element
110    pub(crate) fn attributes(&self) -> impl DoubleEndedIterator<Item = &Attribute> {
111        match self {
112            // these nodes are not elements
113            Content::Document
114            | Content::Element(Element {
115                kind: ElementKind::Template,
116                ..
117            })
118            | Content::Comment { .. }
119            | Content::ProcessingInstruction { .. }
120            | Content::Text { .. }
121            | Content::DocType { .. } => [].iter(),
122            // hey! it's a regular element!
123            Content::Element(Element { attrs, .. }) => attrs.iter(),
124        }
125    }
126    /// Check if the node is a template element
127    pub fn is_template(&self) -> bool {
128        matches!(
129            self,
130            Content::Element(Element {
131                kind: ElementKind::Template,
132                ..
133            })
134        )
135    }
136}
137impl Default for Content {
138    fn default() -> Self {
139        Self::Document
140    }
141}
142impl std::fmt::Display for Content {
143    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144        match self {
145            Content::Document => f.write_str("document"),
146            Content::Element(Element { name, attrs, .. }) => {
147                f.write_fmt(format_args!("{}", name))?;
148                for attr in attrs {
149                    f.write_fmt(format_args!(" {}={:?}", attr.name, attr.value.to_string()))?;
150                }
151                Ok(())
152            }
153            Content::Comment { text } => f.write_fmt(format_args!("<!-- {text:?} -->")),
154            Content::ProcessingInstruction { target, data } => {
155                f.write_fmt(format_args!("<?{target} {data} ?>"))
156            }
157            Content::Text { text } => f.write_fmt(format_args!("{text:?}")),
158            Content::DocType {
159                name,
160                public_id,
161                system_id,
162            } => f.write_fmt(format_args!("<!DOCTYPE {name} {public_id} {system_id}>")),
163        }
164    }
165}