dioxus_document/elements/
mod.rs1#![doc = include_str!("../../docs/head.md")]
2
3use std::{cell::RefCell, collections::HashSet, rc::Rc};
4
5use dioxus_core::{Attribute, DynamicNode, Element, RenderError, ScopeId, Template, TemplateNode};
6use dioxus_core_macro::*;
7
8mod link;
9pub use link::*;
10mod stylesheet;
11pub use stylesheet::*;
12mod meta;
13pub use meta::*;
14mod script;
15pub use script::*;
16mod style;
17pub use style::*;
18mod title;
19pub use title::*;
20
21#[allow(unused)]
23fn use_update_warning<T: PartialEq + Clone + 'static>(value: &T, name: &'static str) {
24 #[cfg(debug_assertions)]
25 {
26 use dioxus_core::use_hook;
27
28 let cloned_value = value.clone();
29 let initial = use_hook(move || value.clone());
30
31 if initial != cloned_value {
32 tracing::warn!("Changing the props of `{name}` is not supported ");
33 }
34 }
35}
36
37pub enum ExtractSingleTextNodeError<'a> {
39 RenderError(&'a RenderError),
41 NonTextNode,
43 NonTemplate,
45}
46
47impl ExtractSingleTextNodeError<'_> {
48 pub fn log(&self, component: &str) {
50 match self {
51 ExtractSingleTextNodeError::RenderError(err) => {
52 tracing::error!("Error while rendering {component}: {err}");
53 }
54 ExtractSingleTextNodeError::NonTextNode => {
55 tracing::error!(
56 "Error while rendering {component}: The children of {component} must be a single text node"
57 );
58 }
59 ExtractSingleTextNodeError::NonTemplate => {
60 tracing::error!(
61 "Error while rendering {component}: The children of {component} must be a single text node"
62 );
63 }
64 }
65 }
66}
67
68fn extract_single_text_node(children: &Element) -> Result<String, ExtractSingleTextNodeError<'_>> {
69 let vnode = match children {
70 Element::Ok(vnode) => vnode,
71 Element::Err(err) => {
72 return Err(ExtractSingleTextNodeError::RenderError(err));
73 }
74 };
75 match vnode.template {
79 Template {
81 roots: &[TemplateNode::Text { text }],
82 node_paths: &[],
83 attr_paths: &[],
84 ..
85 } => Ok(text.to_string()),
86 Template {
88 roots: &[TemplateNode::Dynamic { id }],
89 node_paths: &[&[0]],
90 attr_paths: &[],
91 ..
92 } => {
93 let node = &vnode.dynamic_nodes[id];
94 match node {
95 DynamicNode::Text(text) => Ok(text.value.clone()),
96 _ => Err(ExtractSingleTextNodeError::NonTextNode),
97 }
98 }
99 _ => Err(ExtractSingleTextNodeError::NonTemplate),
100 }
101}
102
103fn get_or_insert_root_context<T: Default + Clone + 'static>() -> T {
104 match ScopeId::ROOT.has_context::<T>() {
105 Some(context) => context,
106 None => {
107 let context = T::default();
108 ScopeId::ROOT.provide_context(context.clone());
109 context
110 }
111 }
112}
113
114#[derive(Default, Clone)]
115struct DeduplicationContext(Rc<RefCell<HashSet<String>>>);
116
117impl DeduplicationContext {
118 fn should_insert(&self, href: &str) -> bool {
119 let mut set = self.0.borrow_mut();
120 let present = set.contains(href);
121 if !present {
122 set.insert(href.to_string());
123 true
124 } else {
125 false
126 }
127 }
128}
129
130pub(crate) fn extend_attributes(
132 attributes: &mut Vec<(&'static str, String)>,
133 additional_attributes: &[Attribute],
134) {
135 for additional_attribute in additional_attributes {
136 let attribute_value_as_string = match &additional_attribute.value {
137 dioxus_core::AttributeValue::Text(v) => v.to_string(),
138 dioxus_core::AttributeValue::Float(v) => v.to_string(),
139 dioxus_core::AttributeValue::Int(v) => v.to_string(),
140 dioxus_core::AttributeValue::Bool(v) => v.to_string(),
141 dioxus_core::AttributeValue::Listener(_) | dioxus_core::AttributeValue::Any(_) => {
142 tracing::error!("document::* elements do not support event listeners or any value attributes. Expected displayable attribute, found {:?}", additional_attribute.value);
143 continue;
144 }
145 dioxus_core::AttributeValue::None => {
146 continue;
147 }
148 };
149 attributes.push((additional_attribute.name, attribute_value_as_string));
150 }
151}