mutations.rs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. use crate::dom::UiEvent;
  2. use crate::dom::WebsysDom;
  3. use dioxus_core::prelude::*;
  4. use dioxus_core::WriteMutations;
  5. use dioxus_core::{AttributeValue, ElementId};
  6. use dioxus_html::event_bubbles;
  7. use dioxus_html::PlatformEventData;
  8. use dioxus_interpreter_js::minimal_bindings;
  9. use wasm_bindgen::JsCast;
  10. use wasm_bindgen::JsValue;
  11. impl WebsysDom {
  12. pub(crate) fn create_template_node(&self, v: &TemplateNode) -> web_sys::Node {
  13. use TemplateNode::*;
  14. match v {
  15. Element {
  16. tag,
  17. namespace,
  18. attrs,
  19. children,
  20. ..
  21. } => {
  22. let el = match namespace {
  23. Some(ns) => self.document.create_element_ns(Some(ns), tag).unwrap(),
  24. None => self.document.create_element(tag).unwrap(),
  25. };
  26. for attr in *attrs {
  27. if let TemplateAttribute::Static {
  28. name,
  29. value,
  30. namespace,
  31. } = attr
  32. {
  33. minimal_bindings::setAttributeInner(
  34. el.clone().into(),
  35. name,
  36. JsValue::from_str(value),
  37. *namespace,
  38. );
  39. }
  40. }
  41. for child in *children {
  42. let _ = el.append_child(&self.create_template_node(child));
  43. }
  44. el.dyn_into().unwrap()
  45. }
  46. Text { text } => self.document.create_text_node(text).dyn_into().unwrap(),
  47. DynamicText { .. } => self.document.create_text_node("p").dyn_into().unwrap(),
  48. Dynamic { .. } => {
  49. let el = self.document.create_element("pre").unwrap();
  50. let _ = el.toggle_attribute("hidden");
  51. el.dyn_into().unwrap()
  52. }
  53. }
  54. }
  55. pub fn flush_edits(&mut self) {
  56. self.interpreter.flush();
  57. // Now that we've flushed the edits and the dom nodes exist, we can send the mounted events.
  58. #[cfg(feature = "mounted")]
  59. self.flush_queued_mounted_events();
  60. }
  61. #[cfg(feature = "mounted")]
  62. fn flush_queued_mounted_events(&mut self) {
  63. for id in self.queued_mounted_events.drain(..) {
  64. let node = self.interpreter.base().get_node(id.0 as u32);
  65. if let Some(element) = node.dyn_ref::<web_sys::Element>() {
  66. let _ = self.event_channel.unbounded_send(UiEvent {
  67. name: "mounted".to_string(),
  68. bubbles: false,
  69. element: id,
  70. data: PlatformEventData::new(Box::new(element.clone())),
  71. });
  72. }
  73. }
  74. }
  75. #[cfg(feature = "mounted")]
  76. pub(crate) fn send_mount_event(&mut self, id: ElementId) {
  77. self.queued_mounted_events.push(id);
  78. }
  79. }
  80. impl WriteMutations for WebsysDom {
  81. fn register_template(&mut self, template: Template) {
  82. let mut roots = vec![];
  83. for root in template.roots {
  84. roots.push(self.create_template_node(root))
  85. }
  86. self.templates
  87. .insert(template.name.to_owned(), self.max_template_id);
  88. self.interpreter
  89. .base()
  90. .save_template(roots, self.max_template_id);
  91. self.max_template_id += 1
  92. }
  93. fn append_children(&mut self, id: ElementId, m: usize) {
  94. self.interpreter.append_children(id.0 as u32, m as u16)
  95. }
  96. fn assign_node_id(&mut self, path: &'static [u8], id: ElementId) {
  97. self.interpreter
  98. .assign_id(path.as_ptr() as u32, path.len() as u8, id.0 as u32)
  99. }
  100. fn create_placeholder(&mut self, id: ElementId) {
  101. self.interpreter.create_placeholder(id.0 as u32)
  102. }
  103. fn create_text_node(&mut self, value: &str, id: ElementId) {
  104. self.interpreter.create_text_node(value, id.0 as u32)
  105. }
  106. fn hydrate_text_node(&mut self, path: &'static [u8], value: &str, id: ElementId) {
  107. self.interpreter
  108. .hydrate_text(path.as_ptr() as u32, path.len() as u8, value, id.0 as u32)
  109. }
  110. fn load_template(&mut self, name: &'static str, index: usize, id: ElementId) {
  111. if let Some(tmpl_id) = self.templates.get(name) {
  112. self.interpreter
  113. .load_template(*tmpl_id, index as u16, id.0 as u32)
  114. }
  115. }
  116. fn replace_node_with(&mut self, id: ElementId, m: usize) {
  117. self.interpreter.replace_with(id.0 as u32, m as u16)
  118. }
  119. fn replace_placeholder_with_nodes(&mut self, path: &'static [u8], m: usize) {
  120. self.interpreter
  121. .replace_placeholder(path.as_ptr() as u32, path.len() as u8, m as u16)
  122. }
  123. fn insert_nodes_after(&mut self, id: ElementId, m: usize) {
  124. self.interpreter.insert_after(id.0 as u32, m as u16)
  125. }
  126. fn insert_nodes_before(&mut self, id: ElementId, m: usize) {
  127. self.interpreter.insert_before(id.0 as u32, m as u16)
  128. }
  129. fn set_attribute(
  130. &mut self,
  131. name: &'static str,
  132. ns: Option<&'static str>,
  133. value: &AttributeValue,
  134. id: ElementId,
  135. ) {
  136. match value {
  137. AttributeValue::Text(txt) => {
  138. self.interpreter
  139. .set_attribute(id.0 as u32, name, txt, ns.unwrap_or_default())
  140. }
  141. AttributeValue::Float(f) => self.interpreter.set_attribute(
  142. id.0 as u32,
  143. name,
  144. &f.to_string(),
  145. ns.unwrap_or_default(),
  146. ),
  147. AttributeValue::Int(n) => self.interpreter.set_attribute(
  148. id.0 as u32,
  149. name,
  150. &n.to_string(),
  151. ns.unwrap_or_default(),
  152. ),
  153. AttributeValue::Bool(b) => self.interpreter.set_attribute(
  154. id.0 as u32,
  155. name,
  156. if *b { "true" } else { "false" },
  157. ns.unwrap_or_default(),
  158. ),
  159. AttributeValue::None => {
  160. self.interpreter
  161. .remove_attribute(id.0 as u32, name, ns.unwrap_or_default())
  162. }
  163. _ => unreachable!(),
  164. }
  165. }
  166. fn set_node_text(&mut self, value: &str, id: ElementId) {
  167. self.interpreter.set_text(id.0 as u32, value)
  168. }
  169. fn create_event_listener(&mut self, name: &'static str, id: ElementId) {
  170. // mounted events are fired immediately after the element is mounted.
  171. if name == "mounted" {
  172. #[cfg(feature = "mounted")]
  173. self.send_mount_event(id);
  174. return;
  175. }
  176. self.interpreter
  177. .new_event_listener(name, id.0 as u32, event_bubbles(name) as u8);
  178. }
  179. fn remove_event_listener(&mut self, name: &'static str, id: ElementId) {
  180. if name == "mounted" {
  181. return;
  182. }
  183. self.interpreter
  184. .remove_event_listener(name, id.0 as u32, event_bubbles(name) as u8);
  185. }
  186. fn remove_node(&mut self, id: ElementId) {
  187. self.interpreter.remove(id.0 as u32)
  188. }
  189. fn push_root(&mut self, id: ElementId) {
  190. self.interpreter.push_root(id.0 as u32)
  191. }
  192. }