dom.rs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. use std::{collections::HashMap, rc::Rc, sync::Arc};
  2. use dioxus_core::{
  3. events::{EventTrigger, VirtualEvent},
  4. DomEdit, ElementId, ScopeId,
  5. };
  6. use fxhash::FxHashMap;
  7. use wasm_bindgen::{closure::Closure, JsCast};
  8. use web_sys::{
  9. window, Document, Element, Event, HtmlElement, HtmlInputElement, HtmlOptionElement, Node,
  10. NodeList,
  11. };
  12. use crate::{nodeslab::NodeSlab, WebConfig};
  13. pub struct WebsysDom {
  14. stack: Stack,
  15. /// A map from ElementID (index) to Node
  16. nodes: NodeSlab,
  17. document: Document,
  18. root: Element,
  19. event_receiver: async_channel::Receiver<EventTrigger>,
  20. trigger: Arc<dyn Fn(EventTrigger)>,
  21. // map of listener types to number of those listeners
  22. // This is roughly a delegater
  23. // TODO: check how infero delegates its events - some are more performant
  24. listeners: FxHashMap<&'static str, (usize, Closure<dyn FnMut(&Event)>)>,
  25. // We need to make sure to add comments between text nodes
  26. // We ensure that the text siblings are patched by preventing the browser from merging
  27. // neighboring text nodes. Originally inspired by some of React's work from 2016.
  28. // -> https://reactjs.org/blog/2016/04/07/react-v15.html#major-changes
  29. // -> https://github.com/facebook/react/pull/5753
  30. last_node_was_text: bool,
  31. }
  32. impl WebsysDom {
  33. pub fn new(root: Element, cfg: WebConfig) -> Self {
  34. let document = load_document();
  35. let (sender, receiver) = async_channel::unbounded::<EventTrigger>();
  36. let sender_callback = Arc::new(move |ev| {
  37. let c = sender.clone();
  38. wasm_bindgen_futures::spawn_local(async move {
  39. log::debug!("sending event through channel");
  40. c.send(ev).await.unwrap();
  41. });
  42. });
  43. let mut nodes = NodeSlab::new(2000);
  44. let mut listeners = FxHashMap::default();
  45. // re-hydrate the page - only supports one virtualdom per page
  46. if cfg.hydrate {
  47. // Load all the elements into the arena
  48. let node_list: NodeList = document.query_selector_all("dio_el").unwrap();
  49. let len = node_list.length() as usize;
  50. for x in 0..len {
  51. let node: Node = node_list.get(x as u32).unwrap();
  52. let el: &Element = node.dyn_ref::<Element>().unwrap();
  53. let id: String = el.get_attribute("dio_el").unwrap();
  54. let id = id.parse::<usize>().unwrap();
  55. // this autoresizes the vector if needed
  56. nodes[id] = Some(node);
  57. }
  58. // Load all the event listeners into our listener register
  59. }
  60. let mut stack = Stack::with_capacity(10);
  61. let root_node = root.clone().dyn_into::<Node>().unwrap();
  62. stack.push(root_node);
  63. Self {
  64. stack,
  65. nodes,
  66. listeners,
  67. document,
  68. event_receiver: receiver,
  69. trigger: sender_callback,
  70. root,
  71. last_node_was_text: false,
  72. }
  73. }
  74. pub async fn wait_for_event(&mut self) -> Option<EventTrigger> {
  75. let v = self.event_receiver.recv().await.unwrap();
  76. Some(v)
  77. }
  78. pub fn process_edits(&mut self, edits: &mut Vec<DomEdit>) {
  79. for edit in edits.drain(..) {
  80. log::info!("Handling edit: {:#?}", edit);
  81. match edit {
  82. DomEdit::PushRoot { id: root } => self.push(root),
  83. DomEdit::PopRoot => self.pop(),
  84. DomEdit::AppendChildren { many } => self.append_children(many),
  85. DomEdit::ReplaceWith { n, m } => self.replace_with(n, m),
  86. DomEdit::Remove => self.remove(),
  87. DomEdit::RemoveAllChildren => self.remove_all_children(),
  88. DomEdit::CreateTextNode { text, id } => self.create_text_node(text, id),
  89. DomEdit::CreateElement { tag, id } => self.create_element(tag, None, id),
  90. DomEdit::CreateElementNs { tag, id, ns } => self.create_element(tag, Some(ns), id),
  91. DomEdit::CreatePlaceholder { id } => self.create_placeholder(id),
  92. DomEdit::NewEventListener {
  93. event_name: event,
  94. scope,
  95. mounted_node_id: node,
  96. } => self.new_event_listener(event, scope, node),
  97. DomEdit::RemoveEventListener { event } => todo!(),
  98. DomEdit::SetText { text } => self.set_text(text),
  99. DomEdit::SetAttribute { field, value, ns } => self.set_attribute(field, value, ns),
  100. DomEdit::RemoveAttribute { name } => self.remove_attribute(name),
  101. DomEdit::InsertAfter { n } => self.insert_after(n),
  102. DomEdit::InsertBefore { n } => self.insert_before(n),
  103. }
  104. }
  105. }
  106. fn push(&mut self, root: u64) {
  107. let key = root as usize;
  108. let domnode = &self.nodes[key];
  109. let real_node: Node = match domnode {
  110. Some(n) => n.clone(),
  111. None => todo!(),
  112. };
  113. self.stack.push(real_node);
  114. }
  115. // drop the node off the stack
  116. fn pop(&mut self) {
  117. self.stack.pop();
  118. }
  119. fn append_children(&mut self, many: u32) {
  120. log::debug!("Called [`append_child`]");
  121. let root: Node = self
  122. .stack
  123. .list
  124. .get(self.stack.list.len() - (1 + many as usize))
  125. .unwrap()
  126. .clone();
  127. for _ in 0..many {
  128. let child = self.stack.pop();
  129. if child.dyn_ref::<web_sys::Text>().is_some() {
  130. if self.last_node_was_text {
  131. let comment_node = self
  132. .document
  133. .create_comment("dioxus")
  134. .dyn_into::<Node>()
  135. .unwrap();
  136. self.stack.top().append_child(&comment_node).unwrap();
  137. }
  138. self.last_node_was_text = true;
  139. } else {
  140. self.last_node_was_text = false;
  141. }
  142. root.append_child(&child).unwrap();
  143. }
  144. }
  145. fn replace_with(&mut self, n: u32, m: u32) {
  146. log::debug!("Called [`replace_with`]");
  147. let mut new_nodes = vec![];
  148. for _ in 0..m {
  149. new_nodes.push(self.stack.pop());
  150. }
  151. let mut old_nodes = vec![];
  152. for _ in 0..n {
  153. old_nodes.push(self.stack.pop());
  154. }
  155. for node in &old_nodes[1..] {
  156. node.dyn_ref::<Element>().unwrap().remove();
  157. }
  158. let old = old_nodes[0].clone();
  159. let arr: js_sys::Array = new_nodes.iter().collect();
  160. let el = old.dyn_into::<Element>().unwrap();
  161. el.replace_with_with_node(&arr).unwrap();
  162. // let arr = js_sys::Array::from();
  163. // TODO: use different-sized replace withs
  164. // if m == 1 {
  165. // if old_node.has_type::<Element>() {
  166. // old_node
  167. // .dyn_ref::<Element>()
  168. // .unwrap()
  169. // .replace_with_with_node_1(&new_node)
  170. // .unwrap();
  171. // } else if old_node.has_type::<web_sys::CharacterData>() {
  172. // old_node
  173. // .dyn_ref::<web_sys::CharacterData>()
  174. // .unwrap()
  175. // .replace_with_with_node_1(&new_node)
  176. // .unwrap();
  177. // } else if old_node.has_type::<web_sys::DocumentType>() {
  178. // old_node
  179. // .dyn_ref::<web_sys::DocumentType>()
  180. // .unwrap()
  181. // .replace_with_with_node_1(&new_node)
  182. // .unwrap();
  183. // } else {
  184. // panic!("Cannot replace node: {:?}", old_node);
  185. // }
  186. // }
  187. // self.stack.push(new_node);
  188. }
  189. fn remove(&mut self) {
  190. log::debug!("Called [`remove`]");
  191. todo!()
  192. }
  193. fn remove_all_children(&mut self) {
  194. log::debug!("Called [`remove_all_children`]");
  195. todo!()
  196. }
  197. fn create_placeholder(&mut self, id: u64) {
  198. self.create_element("pre", None, id);
  199. self.set_attribute("hidden", "", None);
  200. }
  201. fn create_text_node(&mut self, text: &str, id: u64) {
  202. // let nid = self.node_counter.next();
  203. let textnode = self
  204. .document
  205. .create_text_node(text)
  206. .dyn_into::<Node>()
  207. .unwrap();
  208. let id = id as usize;
  209. self.stack.push(textnode.clone());
  210. self.nodes[id] = Some(textnode);
  211. }
  212. fn create_element(&mut self, tag: &str, ns: Option<&'static str>, id: u64) {
  213. let tag = wasm_bindgen::intern(tag);
  214. let el = match ns {
  215. Some(ns) => self
  216. .document
  217. .create_element_ns(Some(ns), tag)
  218. .unwrap()
  219. .dyn_into::<Node>()
  220. .unwrap(),
  221. None => self
  222. .document
  223. .create_element(tag)
  224. .unwrap()
  225. .dyn_into::<Node>()
  226. .unwrap(),
  227. };
  228. let id = id as usize;
  229. self.stack.push(el.clone());
  230. self.nodes[id] = Some(el);
  231. // let nid = self.node_counter.?next();
  232. // let nid = self.nodes.insert(el).data().as_ffi();
  233. // log::debug!("Called [`create_element`]: {}, {:?}", tag, nid);
  234. // ElementId::new(nid)
  235. }
  236. fn new_event_listener(&mut self, event: &'static str, scope: ScopeId, real_id: u64) {
  237. // let (_on, event) = event.split_at(2);
  238. let event = wasm_bindgen::intern(event);
  239. // attach the correct attributes to the element
  240. // these will be used by accessing the event's target
  241. // This ensures we only ever have one handler attached to the root, but decide
  242. // dynamically when we want to call a listener.
  243. let el = self.stack.top();
  244. let el = el
  245. .dyn_ref::<Element>()
  246. .expect(&format!("not an element: {:?}", el));
  247. // let scope_id = scope.data().as_ffi();
  248. let scope_id = scope.0 as u64;
  249. el.set_attribute(
  250. &format!("dioxus-event-{}", event),
  251. &format!("{}.{}", scope_id, real_id),
  252. )
  253. .unwrap();
  254. el.set_attribute(&format!("dioxus-event"), &format!("{}", event))
  255. .unwrap();
  256. // Register the callback to decode
  257. if let Some(entry) = self.listeners.get_mut(event) {
  258. entry.0 += 1;
  259. } else {
  260. let trigger = self.trigger.clone();
  261. let handler = Closure::wrap(Box::new(move |event: &web_sys::Event| {
  262. // "Result" cannot be received from JS
  263. // Instead, we just build and immediately execute a closure that returns result
  264. match decode_trigger(event) {
  265. Ok(synthetic_event) => trigger.as_ref()(synthetic_event),
  266. Err(e) => log::error!("Error decoding Dioxus event attribute. {:#?}", e),
  267. };
  268. }) as Box<dyn FnMut(&Event)>);
  269. self.root
  270. .add_event_listener_with_callback(event, (&handler).as_ref().unchecked_ref())
  271. .unwrap();
  272. // Increment the listeners
  273. self.listeners.insert(event.into(), (1, handler));
  274. }
  275. }
  276. fn remove_event_listener(&mut self, event: &str) {
  277. todo!()
  278. }
  279. fn set_text(&mut self, text: &str) {
  280. self.stack.top().set_text_content(Some(text))
  281. }
  282. fn set_attribute(&mut self, name: &str, value: &str, ns: Option<&str>) {
  283. if name == "class" {
  284. match ns {
  285. Some("http://www.w3.org/2000/svg") => {
  286. //
  287. if let Some(el) = self.stack.top().dyn_ref::<web_sys::SvgElement>() {
  288. let r: web_sys::SvgAnimatedString = el.class_name();
  289. r.set_base_val(value);
  290. // el.set_class_name(value);
  291. }
  292. }
  293. _ => {
  294. if let Some(el) = self.stack.top().dyn_ref::<Element>() {
  295. el.set_class_name(value);
  296. }
  297. }
  298. }
  299. } else {
  300. if let Some(el) = self.stack.top().dyn_ref::<Element>() {
  301. el.set_attribute(name, value).unwrap();
  302. }
  303. }
  304. }
  305. fn remove_attribute(&mut self, name: &str) {
  306. let node = self.stack.top();
  307. if let Some(node) = node.dyn_ref::<web_sys::Element>() {
  308. node.remove_attribute(name).unwrap();
  309. }
  310. if let Some(node) = node.dyn_ref::<HtmlInputElement>() {
  311. // Some attributes are "volatile" and don't work through `removeAttribute`.
  312. if name == "value" {
  313. node.set_value("");
  314. }
  315. if name == "checked" {
  316. node.set_checked(false);
  317. }
  318. }
  319. if let Some(node) = node.dyn_ref::<HtmlOptionElement>() {
  320. if name == "selected" {
  321. node.set_selected(true);
  322. }
  323. }
  324. }
  325. fn insert_after(&mut self, n: u32) {
  326. let mut new_nodes = vec![];
  327. for _ in 0..n {
  328. new_nodes.push(self.stack.pop());
  329. }
  330. let after = self.stack.top().clone();
  331. let arr: js_sys::Array = new_nodes.iter().collect();
  332. let el = after.dyn_into::<Element>().unwrap();
  333. el.after_with_node(&arr).unwrap();
  334. // let mut old_nodes = vec![];
  335. // for _ in 0..n {
  336. // old_nodes.push(self.stack.pop());
  337. // }
  338. // let el = self.stack.top();
  339. }
  340. fn insert_before(&mut self, n: u32) {
  341. let n = n as usize;
  342. let root = self
  343. .stack
  344. .list
  345. .get(self.stack.list.len() - n)
  346. .unwrap()
  347. .clone();
  348. for _ in 0..n {
  349. let el = self.stack.pop();
  350. root.insert_before(&el, None).unwrap();
  351. }
  352. }
  353. }
  354. impl<'a> dioxus_core::diff::RealDom<'a> for WebsysDom {
  355. // fn request_available_node(&mut self) -> ElementId {
  356. // let key = self.nodes.insert(None);
  357. // log::debug!("making new key: {:#?}", key);
  358. // ElementId(key.data().as_ffi())
  359. // }
  360. fn raw_node_as_any(&self) -> &mut dyn std::any::Any {
  361. todo!()
  362. }
  363. }
  364. #[derive(Debug, Default)]
  365. pub struct Stack {
  366. pub list: Vec<Node>,
  367. }
  368. impl Stack {
  369. #[inline]
  370. pub fn with_capacity(cap: usize) -> Self {
  371. Stack {
  372. list: Vec::with_capacity(cap),
  373. }
  374. }
  375. #[inline]
  376. pub fn push(&mut self, node: Node) {
  377. self.list.push(node);
  378. }
  379. #[inline]
  380. pub fn pop(&mut self) -> Node {
  381. self.list.pop().unwrap()
  382. }
  383. #[inline]
  384. pub fn clear(&mut self) {
  385. self.list.clear();
  386. }
  387. pub fn top(&self) -> &Node {
  388. match self.list.last() {
  389. Some(a) => a,
  390. None => panic!("Called 'top' of an empty stack, make sure to push the root first"),
  391. }
  392. }
  393. }
  394. fn virtual_event_from_websys_event(event: &web_sys::Event) -> VirtualEvent {
  395. use dioxus_core::events::on::*;
  396. match event.type_().as_str() {
  397. "copy" | "cut" | "paste" => {
  398. struct WebsysClipboardEvent();
  399. impl ClipboardEventInner for WebsysClipboardEvent {}
  400. VirtualEvent::ClipboardEvent(ClipboardEvent(Rc::new(WebsysClipboardEvent())))
  401. }
  402. "compositionend" | "compositionstart" | "compositionupdate" => {
  403. let evt: web_sys::CompositionEvent = event.clone().dyn_into().unwrap();
  404. struct WebsysCompositionEvent(web_sys::CompositionEvent);
  405. impl CompositionEventInner for WebsysCompositionEvent {
  406. fn data(&self) -> String {
  407. todo!()
  408. }
  409. }
  410. VirtualEvent::CompositionEvent(CompositionEvent(Rc::new(WebsysCompositionEvent(evt))))
  411. }
  412. "keydown" | "keypress" | "keyup" => {
  413. struct Event(web_sys::KeyboardEvent);
  414. impl KeyboardEventInner for Event {
  415. fn char_code(&self) -> u32 {
  416. todo!()
  417. }
  418. fn key_code(&self) -> KeyCode {
  419. todo!()
  420. }
  421. fn ctrl_key(&self) -> bool {
  422. todo!()
  423. }
  424. fn key(&self) -> String {
  425. todo!()
  426. }
  427. fn locale(&self) -> String {
  428. todo!()
  429. }
  430. fn location(&self) -> usize {
  431. todo!()
  432. }
  433. fn meta_key(&self) -> bool {
  434. todo!()
  435. }
  436. fn repeat(&self) -> bool {
  437. todo!()
  438. }
  439. fn shift_key(&self) -> bool {
  440. todo!()
  441. }
  442. fn which(&self) -> usize {
  443. todo!()
  444. }
  445. fn get_modifier_state(&self, key_code: usize) -> bool {
  446. todo!()
  447. }
  448. }
  449. let evt: web_sys::KeyboardEvent = event.clone().dyn_into().unwrap();
  450. VirtualEvent::KeyboardEvent(KeyboardEvent(Rc::new(Event(evt))))
  451. }
  452. "focus" | "blur" => {
  453. struct Event(web_sys::FocusEvent);
  454. impl FocusEventInner for Event {}
  455. let evt: web_sys::FocusEvent = event.clone().dyn_into().unwrap();
  456. VirtualEvent::FocusEvent(FocusEvent(Rc::new(Event(evt))))
  457. }
  458. "change" => {
  459. // struct Event(web_sys::Event);
  460. // impl GenericEventInner for Event {
  461. // fn bubbles(&self) -> bool {
  462. // todo!()
  463. // }
  464. // fn cancel_bubble(&self) {
  465. // todo!()
  466. // }
  467. // fn cancelable(&self) -> bool {
  468. // todo!()
  469. // }
  470. // fn composed(&self) -> bool {
  471. // todo!()
  472. // }
  473. // fn composed_path(&self) -> String {
  474. // todo!()
  475. // }
  476. // fn current_target(&self) {
  477. // todo!()
  478. // }
  479. // fn default_prevented(&self) -> bool {
  480. // todo!()
  481. // }
  482. // fn event_phase(&self) -> usize {
  483. // todo!()
  484. // }
  485. // fn is_trusted(&self) -> bool {
  486. // todo!()
  487. // }
  488. // fn prevent_default(&self) {
  489. // todo!()
  490. // }
  491. // fn stop_immediate_propagation(&self) {
  492. // todo!()
  493. // }
  494. // fn stop_propagation(&self) {
  495. // todo!()
  496. // }
  497. // fn target(&self) {
  498. // todo!()
  499. // }
  500. // fn time_stamp(&self) -> usize {
  501. // todo!()
  502. // }
  503. // }
  504. // let evt: web_sys::Event = event.clone().dyn_into().expect("wrong error typ");
  505. // VirtualEvent::Event(GenericEvent(Rc::new(Event(evt))))
  506. todo!()
  507. }
  508. "input" | "invalid" | "reset" | "submit" => {
  509. // is a special react events
  510. let evt: web_sys::InputEvent = event.clone().dyn_into().expect("wrong event type");
  511. let this: web_sys::EventTarget = evt.target().unwrap();
  512. let value = (&this)
  513. .dyn_ref()
  514. .map(|input: &web_sys::HtmlInputElement| input.value())
  515. .or_else(|| {
  516. (&this)
  517. .dyn_ref()
  518. .map(|input: &web_sys::HtmlTextAreaElement| input.value())
  519. })
  520. .or_else(|| {
  521. (&this)
  522. .dyn_ref::<web_sys::HtmlElement>()
  523. .unwrap()
  524. .text_content()
  525. })
  526. .expect("only an InputElement or TextAreaElement or an element with contenteditable=true can have an oninput event listener");
  527. todo!()
  528. // VirtualEvent::FormEvent(FormEvent { value })
  529. }
  530. "click" | "contextmenu" | "doubleclick" | "drag" | "dragend" | "dragenter" | "dragexit"
  531. | "dragleave" | "dragover" | "dragstart" | "drop" | "mousedown" | "mouseenter"
  532. | "mouseleave" | "mousemove" | "mouseout" | "mouseover" | "mouseup" => {
  533. let evt: web_sys::MouseEvent = event.clone().dyn_into().unwrap();
  534. #[derive(Debug)]
  535. pub struct CustomMouseEvent(web_sys::MouseEvent);
  536. impl dioxus_core::events::on::MouseEventInner for CustomMouseEvent {
  537. fn alt_key(&self) -> bool {
  538. self.0.alt_key()
  539. }
  540. fn button(&self) -> i16 {
  541. self.0.button()
  542. }
  543. fn buttons(&self) -> u16 {
  544. self.0.buttons()
  545. }
  546. fn client_x(&self) -> i32 {
  547. self.0.client_x()
  548. }
  549. fn client_y(&self) -> i32 {
  550. self.0.client_y()
  551. }
  552. fn ctrl_key(&self) -> bool {
  553. self.0.ctrl_key()
  554. }
  555. fn meta_key(&self) -> bool {
  556. self.0.meta_key()
  557. }
  558. fn page_x(&self) -> i32 {
  559. self.0.page_x()
  560. }
  561. fn page_y(&self) -> i32 {
  562. self.0.page_y()
  563. }
  564. fn screen_x(&self) -> i32 {
  565. self.0.screen_x()
  566. }
  567. fn screen_y(&self) -> i32 {
  568. self.0.screen_y()
  569. }
  570. fn shift_key(&self) -> bool {
  571. self.0.shift_key()
  572. }
  573. // yikes
  574. // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values
  575. fn get_modifier_state(&self, key_code: &str) -> bool {
  576. self.0.get_modifier_state(key_code)
  577. }
  578. }
  579. VirtualEvent::MouseEvent(MouseEvent(Rc::new(CustomMouseEvent(evt))))
  580. }
  581. "pointerdown" | "pointermove" | "pointerup" | "pointercancel" | "gotpointercapture"
  582. | "lostpointercapture" | "pointerenter" | "pointerleave" | "pointerover" | "pointerout" => {
  583. let evt: web_sys::PointerEvent = event.clone().dyn_into().unwrap();
  584. todo!()
  585. }
  586. "select" => {
  587. // let evt: web_sys::SelectionEvent = event.clone().dyn_into().unwrap();
  588. // not required to construct anything special beyond standard event stuff
  589. todo!()
  590. }
  591. "touchcancel" | "touchend" | "touchmove" | "touchstart" => {
  592. let evt: web_sys::TouchEvent = event.clone().dyn_into().unwrap();
  593. todo!()
  594. }
  595. "scroll" => {
  596. // let evt: web_sys::UIEvent = event.clone().dyn_into().unwrap();
  597. todo!()
  598. }
  599. "wheel" => {
  600. let evt: web_sys::WheelEvent = event.clone().dyn_into().unwrap();
  601. todo!()
  602. }
  603. "animationstart" | "animationend" | "animationiteration" => {
  604. let evt: web_sys::AnimationEvent = event.clone().dyn_into().unwrap();
  605. todo!()
  606. }
  607. "transitionend" => {
  608. let evt: web_sys::TransitionEvent = event.clone().dyn_into().unwrap();
  609. todo!()
  610. }
  611. "abort" | "canplay" | "canplaythrough" | "durationchange" | "emptied" | "encrypted"
  612. | "ended" | "error" | "loadeddata" | "loadedmetadata" | "loadstart" | "pause" | "play"
  613. | "playing" | "progress" | "ratechange" | "seeked" | "seeking" | "stalled" | "suspend"
  614. | "timeupdate" | "volumechange" | "waiting" => {
  615. // not required to construct anything special beyond standard event stuff
  616. // let evt: web_sys::MediaEvent = event.clone().dyn_into().unwrap();
  617. // let evt: web_sys::MediaEvent = event.clone().dyn_into().unwrap();
  618. todo!()
  619. }
  620. "toggle" => {
  621. // not required to construct anything special beyond standard event stuff (target)
  622. // let evt: web_sys::ToggleEvent = event.clone().dyn_into().unwrap();
  623. todo!()
  624. }
  625. _ => {
  626. todo!()
  627. }
  628. }
  629. }
  630. /// This function decodes a websys event and produces an EventTrigger
  631. /// With the websys implementation, we attach a unique key to the nodes
  632. fn decode_trigger(event: &web_sys::Event) -> anyhow::Result<EventTrigger> {
  633. log::debug!("Handling event!");
  634. let target = event
  635. .target()
  636. .expect("missing target")
  637. .dyn_into::<Element>()
  638. .expect("not a valid element");
  639. let typ = event.type_();
  640. use anyhow::Context;
  641. let attrs = target.attributes();
  642. for x in 0..attrs.length() {
  643. let attr = attrs.item(x).unwrap();
  644. log::debug!("attrs include: {:#?}", attr);
  645. }
  646. // The error handling here is not very descriptive and needs to be replaced with a zero-cost error system
  647. let val: String = target
  648. .get_attribute(&format!("dioxus-event-{}", typ))
  649. .context(format!("wrong format - received {:#?}", typ))?;
  650. let mut fields = val.splitn(3, ".");
  651. let gi_id = fields
  652. .next()
  653. .and_then(|f| f.parse::<u64>().ok())
  654. .context("failed to parse gi id")?;
  655. let real_id = fields
  656. .next()
  657. .and_then(|raw_id| raw_id.parse::<u64>().ok())
  658. .context("failed to parse real id")?;
  659. // Call the trigger
  660. log::debug!("decoded scope_id: {}, node_id: {:#?}", gi_id, real_id);
  661. let triggered_scope = gi_id;
  662. // let triggered_scope: ScopeId = KeyData::from_ffi(gi_id).into();
  663. log::debug!("Triggered scope is {:#?}", triggered_scope);
  664. Ok(EventTrigger::new(
  665. virtual_event_from_websys_event(event),
  666. ScopeId(triggered_scope as usize),
  667. Some(ElementId(real_id as usize)),
  668. dioxus_core::events::EventPriority::High,
  669. ))
  670. }
  671. pub fn prepare_websys_dom() -> Element {
  672. load_document().get_element_by_id("dioxusroot").unwrap()
  673. }
  674. pub fn load_document() -> Document {
  675. web_sys::window()
  676. .expect("should have access to the Window")
  677. .document()
  678. .expect("should have access to the Document")
  679. }