wip: add tests and slightly refactor interpreter code

This commit is contained in:
Jonathan Kelley committed 2024-02-23 17:38:04 -08:00
1 parent e0b0afc0a9
commit 53cafefdef
5 files changed
+465 -309

No files matched your search

+13 -4
View File
@@ -4,19 +4,24 @@
//! in the "values" field. //! in the "values" field.
use dioxus::prelude::*; use dioxus::prelude::*;
use std::collections::HashMap;
fn main() { fn main() {
launch_desktop(app); launch(app);
} }
fn app() -> Element { fn app() -> Element {
let mut values = use_signal(|| HashMap::new());
rsx! { rsx! {
div { div {
h1 { "Form" } h1 { "Form" }
form { form {
onsubmit: move |ev| println!("Submitted {:?}", ev.values()), oninput: move |ev| values.set(ev.values()),
oninput: move |ev| println!("Input {:?}", ev.values()), input {
input { r#type: "text", name: "username" } r#type: "text",
name: "username",
oninput: move |ev| values.set(ev.values())
}
input { r#type: "text", name: "full-name" } input { r#type: "text", name: "full-name" }
input { r#type: "password", name: "password" } input { r#type: "password", name: "password" }
input { r#type: "radio", name: "color", value: "red" } input { r#type: "radio", name: "color", value: "red" }
@@ -24,5 +29,9 @@ fn app() -> Element {
button { r#type: "submit", value: "Submit", "Submit the form" } button { r#type: "submit", value: "Submit", "Submit the form" }
} }
} }
div {
h1 { "Oninput Values" }
"{values:#?}"
}
} }
} }
+313 -233
View File
@@ -1,63 +1,68 @@
use std::{collections::HashMap, ops::Deref};
use dioxus::html::geometry::euclid::Vector3D; use dioxus::html::geometry::euclid::Vector3D;
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_core::prelude::consume_context; use dioxus_core::prelude::consume_context;
use dioxus_desktop::DesktopContext; use dioxus_desktop::DesktopContext;
#[path = "./utils.rs"]
mod utils;
pub fn main() { pub fn main() {
check_app_exits(app); utils::check_app_exits(app);
} }
pub(crate) fn check_app_exits(app: fn() -> Element) { static RECEIVED_EVENTS: GlobalSignal<usize> = Signal::global(|| 0);
use dioxus_desktop::tao::window::WindowBuilder;
use dioxus_desktop::Config;
// This is a deadman's switch to ensure that the app exits
let should_panic = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true));
let should_panic_clone = should_panic.clone();
std::thread::spawn(move || {
std::thread::sleep(std::time::Duration::from_secs(60));
if should_panic_clone.load(std::sync::atomic::Ordering::SeqCst) {
eprintln!("App did not exit in time");
std::process::exit(exitcode::SOFTWARE);
}
});
LaunchBuilder::desktop()
.with_cfg(Config::new().with_window(WindowBuilder::new().with_visible(true)))
.launch(app);
// Stop deadman's switch
should_panic.store(false, std::sync::atomic::Ordering::SeqCst);
}
fn mock_event(id: &'static str, value: &'static str) {
use_hook(move || {
spawn(async move {
tokio::time::sleep(std::time::Duration::from_millis(5000)).await;
let js = format!(
r#"
//console.log("ran");
// Dispatch a synthetic event
let event = {};
let element = document.getElementById('{}');
console.log(element, event);
element.dispatchEvent(event);
"#,
value, id
);
eval(&js).await.unwrap();
});
})
}
#[allow(deprecated)]
fn app() -> Element { fn app() -> Element {
let desktop_context: DesktopContext = consume_context(); let desktop_context: DesktopContext = consume_context();
let mut received_events = use_signal(|| 0);
// button let received = RECEIVED_EVENTS();
mock_event( let expected = utils::EXPECTED_EVENTS();
if expected != 0 && received == expected {
println!("all events recieved");
desktop_context.close();
}
rsx! {
div {
test_mounted {}
test_button {}
test_mouse_move_div {}
test_mouse_click_div {}
test_mouse_dblclick_div {}
test_mouse_down_div {}
test_mouse_up_div {}
test_mouse_scroll_div {}
test_key_down_div {}
test_key_up_div {}
test_key_press_div {}
test_focus_in_div {}
test_focus_out_div {}
test_form_input {}
}
}
}
fn test_mounted() -> Element {
rsx! {
div {
width: "100px",
height: "100px",
onmounted: move |evt| async move {
let rect = evt.get_client_rect().await.unwrap();
println!("rect: {:?}", rect);
assert_eq!(rect.width(), 100.0);
assert_eq!(rect.height(), 100.0);
RECEIVED_EVENTS.with_mut(|x| *x += 1);
}
}
}
}
fn test_button() -> Element {
utils::mock_event(
"button", "button",
r#"new MouseEvent("click", { r#"new MouseEvent("click", {
view: window, view: window,
@@ -66,8 +71,26 @@ fn app() -> Element {
button: 0, button: 0,
})"#, })"#,
); );
// mouse_move_div
mock_event( rsx! {
button {
id: "button",
onclick: move |event| {
println!("{:?}", event.data);
assert!(event.data.modifiers().is_empty());
assert!(event.data.held_buttons().is_empty());
assert_eq!(
event.data.trigger_button(),
Some(dioxus_html::input_data::MouseButton::Primary),
);
RECEIVED_EVENTS.with_mut(|x| *x += 1);
}
}
}
}
fn test_mouse_move_div() -> Element {
utils::mock_event(
"mouse_move_div", "mouse_move_div",
r#"new MouseEvent("mousemove", { r#"new MouseEvent("mousemove", {
view: window, view: window,
@@ -76,8 +99,27 @@ fn app() -> Element {
buttons: 2, buttons: 2,
})"#, })"#,
); );
// mouse_click_div
mock_event( rsx! {
div {
id: "mouse_move_div",
onmousemove: move |event| {
println!("{:?}", event.data);
assert!(event.data.modifiers().is_empty());
assert!(
event
.data
.held_buttons()
.contains(dioxus_html::input_data::MouseButton::Secondary),
);
RECEIVED_EVENTS.with_mut(|x| *x += 1);
}
}
}
}
fn test_mouse_click_div() -> Element {
utils::mock_event(
"mouse_click_div", "mouse_click_div",
r#"new MouseEvent("click", { r#"new MouseEvent("click", {
view: window, view: window,
@@ -87,8 +129,31 @@ fn app() -> Element {
button: 2, button: 2,
})"#, })"#,
); );
// mouse_dblclick_div
mock_event( rsx! {
div {
id: "mouse_click_div",
onclick: move |event| {
println!("{:?}", event.data);
assert!(event.data.modifiers().is_empty());
assert!(
event
.data
.held_buttons()
.contains(dioxus_html::input_data::MouseButton::Secondary),
);
assert_eq!(
event.data.trigger_button(),
Some(dioxus_html::input_data::MouseButton::Secondary),
);
RECEIVED_EVENTS.with_mut(|x| *x += 1);
}
}
}
}
fn test_mouse_dblclick_div() -> Element {
utils::mock_event(
"mouse_dblclick_div", "mouse_dblclick_div",
r#"new MouseEvent("dblclick", { r#"new MouseEvent("dblclick", {
view: window, view: window,
@@ -98,8 +163,34 @@ fn app() -> Element {
button: 2, button: 2,
})"#, })"#,
); );
// mouse_down_div
mock_event( rsx! {
div {
id: "mouse_dblclick_div",
ondoubleclick: move |event| {
println!("{:?}", event.data);
assert!(event.data.modifiers().is_empty());
assert!(
event.data.held_buttons().contains(dioxus_html::input_data::MouseButton::Primary),
);
assert!(
event
.data
.held_buttons()
.contains(dioxus_html::input_data::MouseButton::Secondary),
);
assert_eq!(
event.data.trigger_button(),
Some(dioxus_html::input_data::MouseButton::Secondary),
);
RECEIVED_EVENTS.with_mut(|x| *x += 1);
}
}
}
}
fn test_mouse_down_div() -> Element {
utils::mock_event(
"mouse_down_div", "mouse_down_div",
r#"new MouseEvent("mousedown", { r#"new MouseEvent("mousedown", {
view: window, view: window,
@@ -109,8 +200,31 @@ fn app() -> Element {
button: 2, button: 2,
})"#, })"#,
); );
// mouse_up_div
mock_event( rsx! {
div {
id: "mouse_down_div",
onmousedown: move |event| {
println!("{:?}", event.data);
assert!(event.data.modifiers().is_empty());
assert!(
event
.data
.held_buttons()
.contains(dioxus_html::input_data::MouseButton::Secondary),
);
assert_eq!(
event.data.trigger_button(),
Some(dioxus_html::input_data::MouseButton::Secondary),
);
RECEIVED_EVENTS.with_mut(|x| *x += 1);
}
}
}
}
fn test_mouse_up_div() -> Element {
utils::mock_event(
"mouse_up_div", "mouse_up_div",
r#"new MouseEvent("mouseup", { r#"new MouseEvent("mouseup", {
view: window, view: window,
@@ -120,8 +234,26 @@ fn app() -> Element {
button: 0, button: 0,
})"#, })"#,
); );
// wheel_div
mock_event( rsx! {
div {
id: "mouse_up_div",
onmouseup: move |event| {
println!("{:?}", event.data);
assert!(event.data.modifiers().is_empty());
assert!(event.data.held_buttons().is_empty());
assert_eq!(
event.data.trigger_button(),
Some(dioxus_html::input_data::MouseButton::Primary),
);
RECEIVED_EVENTS.with_mut(|x| *x += 1);
}
}
}
}
fn test_mouse_scroll_div() -> Element {
utils::mock_event(
"wheel_div", "wheel_div",
r#"new WheelEvent("wheel", { r#"new WheelEvent("wheel", {
view: window, view: window,
@@ -132,8 +264,26 @@ fn app() -> Element {
bubbles: true, bubbles: true,
})"#, })"#,
); );
// key_down_div
mock_event( rsx! {
div {
id: "wheel_div",
width: "100px",
height: "100px",
background_color: "red",
onwheel: move |event| {
println!("{:?}", event.data);
let dioxus_html::geometry::WheelDelta::Pixels(delta) = event.data.delta() else {
panic!("Expected delta to be in pixels") };
assert_eq!(delta, Vector3D::new(1.0, 2.0, 3.0));
RECEIVED_EVENTS.with_mut(|x| *x += 1);
}
}
}
}
fn test_key_down_div() -> Element {
utils::mock_event(
"key_down_div", "key_down_div",
r#"new KeyboardEvent("keydown", { r#"new KeyboardEvent("keydown", {
key: "a", key: "a",
@@ -153,8 +303,24 @@ fn app() -> Element {
bubbles: true, bubbles: true,
})"#, })"#,
); );
// key_up_div rsx! {
mock_event( input {
id: "key_down_div",
onkeydown: move |event| {
println!("{:?}", event.data);
assert!(event.data.modifiers().is_empty());
assert_eq!(event.data.key().to_string(), "a");
assert_eq!(event.data.code().to_string(), "KeyA");
assert_eq!(event.data.location(), Location::Standard);
assert!(event.data.is_auto_repeating());
assert!(event.data.is_composing());
RECEIVED_EVENTS.with_mut(|x| *x += 1);
}
}
}
}
fn test_key_up_div() -> Element {
utils::mock_event(
"key_up_div", "key_up_div",
r#"new KeyboardEvent("keyup", { r#"new KeyboardEvent("keyup", {
key: "a", key: "a",
@@ -174,8 +340,25 @@ fn app() -> Element {
bubbles: true, bubbles: true,
})"#, })"#,
); );
// key_press_div
mock_event( rsx! {
input {
id: "key_up_div",
onkeyup: move |event| {
println!("{:?}", event.data);
assert!(event.data.modifiers().is_empty());
assert_eq!(event.data.key().to_string(), "a");
assert_eq!(event.data.code().to_string(), "KeyA");
assert_eq!(event.data.location(), Location::Standard);
assert!(!event.data.is_auto_repeating());
assert!(!event.data.is_composing());
RECEIVED_EVENTS.with_mut(|x| *x += 1);
}
}
}
}
fn test_key_press_div() -> Element {
utils::mock_event(
"key_press_div", "key_press_div",
r#"new KeyboardEvent("keypress", { r#"new KeyboardEvent("keypress", {
key: "a", key: "a",
@@ -195,171 +378,7 @@ fn app() -> Element {
bubbles: true, bubbles: true,
})"#, })"#,
); );
// focus_in_div
mock_event(
"focus_in_div",
r#"new FocusEvent("focusin", {bubbles: true})"#,
);
// focus_out_div
mock_event(
"focus_out_div",
r#"new FocusEvent("focusout",{bubbles: true})"#,
);
if received_events() == 13 {
println!("all events recieved");
desktop_context.close();
}
rsx! { rsx! {
div {
div {
width: "100px",
height: "100px",
onmounted: move |evt| async move {
let rect = evt.get_client_rect().await.unwrap();
println!("rect: {:?}", rect);
assert_eq!(rect.width(), 100.0);
assert_eq!(rect.height(), 100.0);
received_events.with_mut(|x| *x += 1);
}
}
button {
id: "button",
onclick: move |event| {
println!("{:?}", event.data);
assert!(event.data.modifiers().is_empty());
assert!(event.data.held_buttons().is_empty());
assert_eq!(
event.data.trigger_button(),
Some(dioxus_html::input_data::MouseButton::Primary),
);
received_events.with_mut(|x| *x += 1);
}
}
div {
id: "mouse_move_div",
onmousemove: move |event| {
println!("{:?}", event.data);
assert!(event.data.modifiers().is_empty());
assert!(
event
.data
.held_buttons()
.contains(dioxus_html::input_data::MouseButton::Secondary),
);
received_events.with_mut(|x| *x += 1);
}
}
div {
id: "mouse_click_div",
onclick: move |event| {
println!("{:?}", event.data);
assert!(event.data.modifiers().is_empty());
assert!(
event
.data
.held_buttons()
.contains(dioxus_html::input_data::MouseButton::Secondary),
);
assert_eq!(
event.data.trigger_button(),
Some(dioxus_html::input_data::MouseButton::Secondary),
);
received_events.with_mut(|x| *x += 1);
}
}
div {
id: "mouse_dblclick_div",
ondoubleclick: move |event| {
println!("{:?}", event.data);
assert!(event.data.modifiers().is_empty());
assert!(
event.data.held_buttons().contains(dioxus_html::input_data::MouseButton::Primary),
);
assert!(
event
.data
.held_buttons()
.contains(dioxus_html::input_data::MouseButton::Secondary),
);
assert_eq!(
event.data.trigger_button(),
Some(dioxus_html::input_data::MouseButton::Secondary),
);
received_events.with_mut(|x| *x += 1);
}
}
div {
id: "mouse_down_div",
onmousedown: move |event| {
println!("{:?}", event.data);
assert!(event.data.modifiers().is_empty());
assert!(
event
.data
.held_buttons()
.contains(dioxus_html::input_data::MouseButton::Secondary),
);
assert_eq!(
event.data.trigger_button(),
Some(dioxus_html::input_data::MouseButton::Secondary),
);
received_events.with_mut(|x| *x += 1);
}
}
div {
id: "mouse_up_div",
onmouseup: move |event| {
println!("{:?}", event.data);
assert!(event.data.modifiers().is_empty());
assert!(event.data.held_buttons().is_empty());
assert_eq!(
event.data.trigger_button(),
Some(dioxus_html::input_data::MouseButton::Primary),
);
received_events.with_mut(|x| *x += 1);
}
}
div {
id: "wheel_div",
width: "100px",
height: "100px",
background_color: "red",
onwheel: move |event| {
println!("{:?}", event.data);
let dioxus_html::geometry::WheelDelta::Pixels(delta) = event.data.delta() else {
panic!("Expected delta to be in pixels") };
assert_eq!(delta, Vector3D::new(1.0, 2.0, 3.0));
received_events.with_mut(|x| *x += 1);
}
}
input {
id: "key_down_div",
onkeydown: move |event| {
println!("{:?}", event.data);
assert!(event.data.modifiers().is_empty());
assert_eq!(event.data.key().to_string(), "a");
assert_eq!(event.data.code().to_string(), "KeyA");
assert_eq!(event.data.location(), Location::Standard);
assert!(event.data.is_auto_repeating());
assert!(event.data.is_composing());
received_events.with_mut(|x| *x += 1);
}
}
input {
id: "key_up_div",
onkeyup: move |event| {
println!("{:?}", event.data);
assert!(event.data.modifiers().is_empty());
assert_eq!(event.data.key().to_string(), "a");
assert_eq!(event.data.code().to_string(), "KeyA");
assert_eq!(event.data.location(), Location::Standard);
assert!(!event.data.is_auto_repeating());
assert!(!event.data.is_composing());
received_events.with_mut(|x| *x += 1);
}
}
input { input {
id: "key_press_div", id: "key_press_div",
onkeypress: move |event| { onkeypress: move |event| {
@@ -370,23 +389,84 @@ fn app() -> Element {
assert_eq!(event.data.location(), Location::Standard); assert_eq!(event.data.location(), Location::Standard);
assert!(!event.data.is_auto_repeating()); assert!(!event.data.is_auto_repeating());
assert!(!event.data.is_composing()); assert!(!event.data.is_composing());
received_events.with_mut(|x| *x += 1); RECEIVED_EVENTS.with_mut(|x| *x += 1);
} }
} }
}
}
fn test_focus_in_div() -> Element {
utils::mock_event(
"focus_in_div",
r#"new FocusEvent("focusin", {bubbles: true})"#,
);
rsx! {
input { input {
id: "focus_in_div", id: "focus_in_div",
onfocusin: move |event| { onfocusin: move |event| {
println!("{:?}", event.data); println!("{:?}", event.data);
received_events.with_mut(|x| *x += 1); RECEIVED_EVENTS.with_mut(|x| *x += 1);
} }
} }
}
}
fn test_focus_out_div() -> Element {
utils::mock_event(
"focus_out_div",
r#"new FocusEvent("focusout",{bubbles: true})"#,
);
rsx! {
input { input {
id: "focus_out_div", id: "focus_out_div",
onfocusout: move |event| { onfocusout: move |event| {
println!("{:?}", event.data); println!("{:?}", event.data);
received_events.with_mut(|x| *x += 1); RECEIVED_EVENTS.with_mut(|x| *x += 1);
} }
} }
} }
} }
fn test_form_input() -> Element {
let mut values = use_signal(|| HashMap::new());
utils::mock_event_with_extra(
"form-username",
r#"new Event("input", {
bubbles: true,
cancelable: true,
composed: true,
})"#,
r#"element.value = "hello";"#,
);
let set_values = move |ev: FormEvent| {
values.set(ev.values());
eprintln!("values: {:?}", values);
values.with_mut(|x| {
assert_eq!(x.get("username").unwrap().deref(), &["hello"]);
});
};
rsx! {
div {
h1 { "Form" }
form {
id: "form",
oninput: move |ev| values.set(ev.values()),
input {
r#type: "text",
name: "username",
id: "form-username",
oninput: set_values,
}
input { r#type: "text", name: "full-name" }
input { r#type: "password", name: "password" }
input { r#type: "radio", name: "color", value: "red" }
input { r#type: "radio", name: "color", value: "blue" }
button { r#type: "submit", value: "Submit", "Submit the form" }
}
}
}
} }
+4 -21
View File
@@ -2,28 +2,11 @@ use dioxus::prelude::*;
use dioxus_core::Element; use dioxus_core::Element;
use dioxus_desktop::DesktopContext; use dioxus_desktop::DesktopContext;
#[path = "./utils.rs"]
mod utils;
fn main() { fn main() {
check_app_exits(check_html_renders); utils::check_app_exits(check_html_renders);
}
pub(crate) fn check_app_exits(app: fn() -> Element) {
use dioxus_desktop::Config;
use tao::window::WindowBuilder;
// This is a deadman's switch to ensure that the app exits
let should_panic = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true));
let should_panic_clone = should_panic.clone();
std::thread::spawn(move || {
std::thread::sleep(std::time::Duration::from_secs(5));
if should_panic_clone.load(std::sync::atomic::Ordering::SeqCst) {
std::process::exit(exitcode::SOFTWARE);
}
});
LaunchBuilder::desktop()
.with_cfg(Config::new().with_window(WindowBuilder::new().with_visible(true)))
.launch(app);
should_panic.store(false, std::sync::atomic::Ordering::SeqCst);
} }
fn use_inner_html(id: &'static str) -> Option<String> { fn use_inner_html(id: &'static str) -> Option<String> {
+55
View File
@@ -0,0 +1,55 @@
use dioxus::prelude::*;
use dioxus_core::Element;
pub fn check_app_exits(app: fn() -> Element) {
use dioxus_desktop::tao::window::WindowBuilder;
use dioxus_desktop::Config;
// This is a deadman's switch to ensure that the app exits
let should_panic = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true));
let should_panic_clone = should_panic.clone();
std::thread::spawn(move || {
std::thread::sleep(std::time::Duration::from_secs(60));
if should_panic_clone.load(std::sync::atomic::Ordering::SeqCst) {
eprintln!("App did not exit in time");
std::process::exit(exitcode::SOFTWARE);
}
});
LaunchBuilder::desktop()
.with_cfg(Config::new().with_window(WindowBuilder::new().with_visible(true)))
.launch(app);
// Stop deadman's switch
should_panic.store(false, std::sync::atomic::Ordering::SeqCst);
}
pub static EXPECTED_EVENTS: GlobalSignal<usize> = Signal::global(|| 0);
pub fn mock_event(id: &'static str, value: &'static str) {
mock_event_with_extra(id, value, "");
}
pub fn mock_event_with_extra(id: &'static str, value: &'static str, extra: &'static str) {
EXPECTED_EVENTS.with_mut(|x| *x += 1);
use_hook(move || {
spawn(async move {
tokio::time::sleep(std::time::Duration::from_millis(5000)).await;
let js = format!(
r#"
//console.log("ran");
// Dispatch a synthetic event
let event = {};
let element = document.getElementById('{}');
console.log(element, event);
{}
element.dispatchEvent(event);
"#,
value, id, extra
);
eval(&js).await.unwrap();
});
})
}
+80 -51
View File
@@ -8,58 +8,16 @@ class InterpreterConfig {
// method is not used by the web implementation // method is not used by the web implementation
async function handler(event, name, bubbles, config) { async function handler(event, name, bubbles, config) {
let target = event.target; let target = event.target;
if (target != null) { if (target == null) {
let preventDefaultRequests = null; return;
// Some events can be triggered on text nodes, which don't have attributes
if (target instanceof Element) {
preventDefaultRequests = target.getAttribute(`dioxus-prevent-default`);
}
if (event.type === "click") {
// todo call prevent default if it's the right type of event
if (config.intercept_link_redirects) {
let a_element = target.closest("a");
if (a_element != null) {
event.preventDefault();
let elementShouldPreventDefault =
preventDefaultRequests && preventDefaultRequests.includes(`onclick`);
let aElementShouldPreventDefault = a_element.getAttribute(
`dioxus-prevent-default`
);
let linkShouldPreventDefault =
aElementShouldPreventDefault &&
aElementShouldPreventDefault.includes(`onclick`);
if (!elementShouldPreventDefault && !linkShouldPreventDefault) {
const href = a_element.getAttribute("href");
if (href !== "" && href !== null && href !== undefined) {
window.ipc.postMessage(
window.interpreter.serializeIpcMessage("browser_open", { href })
);
}
}
}
}
// also prevent buttons from submitting
if (target.tagName === "BUTTON" && event.type == "submit") {
event.preventDefault();
}
} }
const realId = find_real_id(target); const realId = find_real_id(target);
if (realId === null) {
if ( return;
preventDefaultRequests &&
preventDefaultRequests.includes(`on${event.type}`)
) {
event.preventDefault();
} }
if (event.type === "submit") { prevent_defaults(event, target, config);
event.preventDefault();
}
let contents = await serialize_event(event); let contents = await serialize_event(event);
@@ -69,6 +27,7 @@ async function handler(event, name, bubbles, config) {
(event.type === "change" || event.type === "input") (event.type === "change" || event.type === "input")
) { ) {
const type = target.getAttribute("type"); const type = target.getAttribute("type");
if (type === "file") { if (type === "file") {
async function read_files() { async function read_files() {
const files = target.files; const files = target.files;
@@ -138,9 +97,6 @@ async function handler(event, name, bubbles, config) {
} }
} }
if (realId === null) {
return;
}
window.ipc.postMessage( window.ipc.postMessage(
window.interpreter.serializeIpcMessage("user_event", { window.interpreter.serializeIpcMessage("user_event", {
name: name, name: name,
@@ -150,13 +106,84 @@ async function handler(event, name, bubbles, config) {
}) })
); );
} }
// Do our best to prevent the default action of the event
// This should:
// - prevent form submissions from navigating
// - prevent anchor tags from navigating
// - prevent buttons from submitting forms
function prevent_defaults(event, target, config) {
let preventDefaultRequests = null;
// Some events can be triggered on text nodes, which don't have attributes
if (target instanceof Element) {
preventDefaultRequests = target.getAttribute(`dioxus-prevent-default`);
}
if (preventDefaultRequests && preventDefaultRequests.includes(`on${event.type}`)) {
event.preventDefault();
}
if (event.type === "submit") {
event.preventDefault();
}
// Attempt to intercept if the event is a click
intercept_form_submit(event, target, config, preventDefaultRequests);
}
function intercept_form_submit(event, target, config, preventDefaultRequests) {
if (event.type !== "click") {
return;
}
// todo call prevent default if it's the right type of event
if (!config.intercept_link_redirects) {
return;
}
// prevent buttons in forms from submitting the form
if (target.tagName === "BUTTON" && event.type == "submit") {
event.preventDefault();
}
// If the target is an anchor tag, we want to intercept the click too, to prevent the browser from navigating
let a_element = target.closest("a");
if (a_element == null) {
return;
}
event.preventDefault();
let elementShouldPreventDefault =
preventDefaultRequests && preventDefaultRequests.includes(`onclick`);
let aElementShouldPreventDefault = a_element.getAttribute(
`dioxus-prevent-default`
);
let linkShouldPreventDefault =
aElementShouldPreventDefault &&
aElementShouldPreventDefault.includes(`onclick`);
if (!elementShouldPreventDefault && !linkShouldPreventDefault) {
const href = a_element.getAttribute("href");
if (href !== "" && href !== null && href !== undefined) {
window.ipc.postMessage(
window.interpreter.serializeIpcMessage("browser_open", { href })
);
}
}
} }
function find_real_id(target) { function find_real_id(target) {
let realId = null; let realId = null;
if (target instanceof Element) { if (target instanceof Element) {
realId = target.getAttribute(`data-dioxus-id`); realId = target.getAttribute(`data-dioxus-id`);
} }
// walk the tree to find the real element // walk the tree to find the real element
while (realId == null) { while (realId == null) {
// we've reached the root we don't want to send an event // we've reached the root we don't want to send an event
@@ -169,6 +196,7 @@ function find_real_id(target) {
realId = target.getAttribute(`data-dioxus-id`); realId = target.getAttribute(`data-dioxus-id`);
} }
} }
return realId; return realId;
} }
@@ -421,7 +449,8 @@ async function serialize_event(event) {
case "drop": { case "drop": {
let files = null; let files = null;
if (event.dataTransfer && event.dataTransfer.files) { if (event.dataTransfer && event.dataTransfer.files) {
files = await serializeFileList(event.dataTransfer.files); files = ["a", "b", "c"];
// files = await serializeFileList(event.dataTransfer.files);
} }
return { mouse: get_mouse_data(event), files }; return { mouse: get_mouse_data(event), files };