|
@@ -1,3 +1,12 @@
|
|
|
|
+//! Implementation of a renderer for Dioxus on the web.
|
|
|
|
+//!
|
|
|
|
+//! Oustanding todos:
|
|
|
|
+//! - Removing event listeners (delegation)
|
|
|
|
+//! - Passive event listeners
|
|
|
|
+//! - no-op event listener patch for safari
|
|
|
|
+//! - tests to ensure dyn_into works for various event types.
|
|
|
|
+//! - Partial delegation?>
|
|
|
|
+
|
|
use dioxus_core::{
|
|
use dioxus_core::{
|
|
events::{SyntheticEvent, UserEvent},
|
|
events::{SyntheticEvent, UserEvent},
|
|
mutations::NodeRefMutation,
|
|
mutations::NodeRefMutation,
|
|
@@ -29,7 +38,7 @@ pub struct WebsysDom {
|
|
// map of listener types to number of those listeners
|
|
// map of listener types to number of those listeners
|
|
// This is roughly a delegater
|
|
// This is roughly a delegater
|
|
// TODO: check how infero delegates its events - some are more performant
|
|
// TODO: check how infero delegates its events - some are more performant
|
|
- listeners: FxHashMap<&'static str, (usize, Closure<dyn FnMut(&Event)>)>,
|
|
|
|
|
|
+ listeners: FxHashMap<&'static str, ListenerEntry>,
|
|
|
|
|
|
// We need to make sure to add comments between text nodes
|
|
// We need to make sure to add comments between text nodes
|
|
// We ensure that the text siblings are patched by preventing the browser from merging
|
|
// We ensure that the text siblings are patched by preventing the browser from merging
|
|
@@ -38,6 +47,9 @@ pub struct WebsysDom {
|
|
// -> https://github.com/facebook/react/pull/5753
|
|
// -> https://github.com/facebook/react/pull/5753
|
|
last_node_was_text: bool,
|
|
last_node_was_text: bool,
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+type ListenerEntry = (usize, Closure<dyn FnMut(&Event)>);
|
|
|
|
+
|
|
impl WebsysDom {
|
|
impl WebsysDom {
|
|
pub fn new(root: Element, cfg: WebConfig, sender_callback: Rc<dyn Fn(SchedulerMsg)>) -> Self {
|
|
pub fn new(root: Element, cfg: WebConfig, sender_callback: Rc<dyn Fn(SchedulerMsg)>) -> Self {
|
|
let document = load_document();
|
|
let document = load_document();
|
|
@@ -92,7 +104,6 @@ impl WebsysDom {
|
|
|
|
|
|
pub fn process_edits(&mut self, edits: &mut Vec<DomEdit>) {
|
|
pub fn process_edits(&mut self, edits: &mut Vec<DomEdit>) {
|
|
for edit in edits.drain(..) {
|
|
for edit in edits.drain(..) {
|
|
- // log::info!("Handling edit: {:#?}", edit);
|
|
|
|
match edit {
|
|
match edit {
|
|
DomEdit::PushRoot { id: root } => self.push(root),
|
|
DomEdit::PushRoot { id: root } => self.push(root),
|
|
DomEdit::PopRoot => self.pop(),
|
|
DomEdit::PopRoot => self.pop(),
|
|
@@ -423,34 +434,29 @@ impl WebsysDom {
|
|
}
|
|
}
|
|
|
|
|
|
#[derive(Debug, Default)]
|
|
#[derive(Debug, Default)]
|
|
-pub struct Stack {
|
|
|
|
- pub list: Vec<Node>,
|
|
|
|
|
|
+struct Stack {
|
|
|
|
+ list: Vec<Node>,
|
|
}
|
|
}
|
|
|
|
|
|
impl Stack {
|
|
impl Stack {
|
|
#[inline]
|
|
#[inline]
|
|
- pub fn with_capacity(cap: usize) -> Self {
|
|
|
|
|
|
+ fn with_capacity(cap: usize) -> Self {
|
|
Stack {
|
|
Stack {
|
|
list: Vec::with_capacity(cap),
|
|
list: Vec::with_capacity(cap),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#[inline]
|
|
#[inline]
|
|
- pub fn push(&mut self, node: Node) {
|
|
|
|
|
|
+ fn push(&mut self, node: Node) {
|
|
self.list.push(node);
|
|
self.list.push(node);
|
|
}
|
|
}
|
|
|
|
|
|
#[inline]
|
|
#[inline]
|
|
- pub fn pop(&mut self) -> Node {
|
|
|
|
|
|
+ fn pop(&mut self) -> Node {
|
|
self.list.pop().unwrap()
|
|
self.list.pop().unwrap()
|
|
}
|
|
}
|
|
|
|
|
|
- #[inline]
|
|
|
|
- pub fn clear(&mut self) {
|
|
|
|
- self.list.clear();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- pub fn top(&self) -> &Node {
|
|
|
|
|
|
+ fn top(&self) -> &Node {
|
|
match self.list.last() {
|
|
match self.list.last() {
|
|
Some(a) => a,
|
|
Some(a) => a,
|
|
None => panic!("Called 'top' of an empty stack, make sure to push the root first"),
|
|
None => panic!("Called 'top' of an empty stack, make sure to push the root first"),
|
|
@@ -458,6 +464,8 @@ impl Stack {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// todo: some of these events are being casted to the wrong event type.
|
|
|
|
+// We need tests that simulate clicks/etc and make sure every event type works.
|
|
fn virtual_event_from_websys_event(event: web_sys::Event) -> SyntheticEvent {
|
|
fn virtual_event_from_websys_event(event: web_sys::Event) -> SyntheticEvent {
|
|
use crate::events::*;
|
|
use crate::events::*;
|
|
use dioxus_core::events::on::*;
|
|
use dioxus_core::events::on::*;
|
|
@@ -549,12 +557,13 @@ fn decode_trigger(event: &web_sys::Event) -> anyhow::Result<UserEvent> {
|
|
|
|
|
|
let typ = event.type_();
|
|
let typ = event.type_();
|
|
|
|
|
|
- log::debug!("Event type is {:?}", typ);
|
|
|
|
-
|
|
|
|
- let attrs = target.attributes();
|
|
|
|
- for x in 0..attrs.length() {
|
|
|
|
- let attr: Attr = attrs.item(x).unwrap();
|
|
|
|
- // log::debug!("attrs include: {:#?}, {:#?}", attr.name(), attr.value());
|
|
|
|
|
|
+ // TODO: clean this up
|
|
|
|
+ if cfg!(debug_assertions) {
|
|
|
|
+ let attrs = target.attributes();
|
|
|
|
+ for x in 0..attrs.length() {
|
|
|
|
+ let attr: Attr = attrs.item(x).unwrap();
|
|
|
|
+ // log::debug!("attrs include: {:#?}, {:#?}", attr.name(), attr.value());
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
use anyhow::Context;
|
|
use anyhow::Context;
|
|
@@ -576,12 +585,8 @@ fn decode_trigger(event: &web_sys::Event) -> anyhow::Result<UserEvent> {
|
|
.and_then(|raw_id| raw_id.parse::<u64>().ok())
|
|
.and_then(|raw_id| raw_id.parse::<u64>().ok())
|
|
.context("failed to parse real id")?;
|
|
.context("failed to parse real id")?;
|
|
|
|
|
|
- // Call the trigger
|
|
|
|
- // log::debug!("decoded scope_id: {}, node_id: {:#?}", gi_id, real_id);
|
|
|
|
-
|
|
|
|
let triggered_scope = gi_id;
|
|
let triggered_scope = gi_id;
|
|
- // let triggered_scope: ScopeId = KeyData::from_ffi(gi_id).into();
|
|
|
|
- // log::debug!("Triggered scope is {:#?}", triggered_scope);
|
|
|
|
|
|
+
|
|
Ok(UserEvent {
|
|
Ok(UserEvent {
|
|
name: event_name_from_typ(&typ),
|
|
name: event_name_from_typ(&typ),
|
|
event: virtual_event_from_websys_event(event.clone()),
|
|
event: virtual_event_from_websys_event(event.clone()),
|
|
@@ -590,14 +595,14 @@ fn decode_trigger(event: &web_sys::Event) -> anyhow::Result<UserEvent> {
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
|
|
-pub fn load_document() -> Document {
|
|
|
|
|
|
+pub(crate) fn load_document() -> Document {
|
|
web_sys::window()
|
|
web_sys::window()
|
|
.expect("should have access to the Window")
|
|
.expect("should have access to the Window")
|
|
.document()
|
|
.document()
|
|
.expect("should have access to the Document")
|
|
.expect("should have access to the Document")
|
|
}
|
|
}
|
|
|
|
|
|
-pub fn event_name_from_typ(typ: &str) -> &'static str {
|
|
|
|
|
|
+fn event_name_from_typ(typ: &str) -> &'static str {
|
|
match typ {
|
|
match typ {
|
|
"copy" => "copy",
|
|
"copy" => "copy",
|
|
"cut" => "cut",
|
|
"cut" => "cut",
|