소스 검색

Merge branch 'upstream' into query-system

Evan Almloff 2 년 전
부모
커밋
19436e210f

+ 1 - 2
docs/guide/examples/event_prevent_default.rs

@@ -10,8 +10,7 @@ fn App(cx: Scope) -> Element {
     // ANCHOR: prevent_default
 cx.render(rsx! {
     input {
-        prevent_default: "oninput",
-        prevent_default: "onclick",
+        prevent_default: "oninput onclick",
     }
 })
     // ANCHOR_END: prevent_default

+ 2 - 2
docs/guide/src/en/interactivity/event_handlers.md

@@ -31,7 +31,7 @@ Some events will trigger first on the element the event originated at upward. Fo
 
 > For more information about event propigation see [the mdn docs on event bubling](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_bubbling)
 
-If you want to prevent this behavior, you can call `stop_propogation()` on the event:
+If you want to prevent this behavior, you can call `stop_propagation()` on the event:
 
 ```rust
 {{#include ../../../examples/event_nested.rs:rsx}}
@@ -41,7 +41,7 @@ If you want to prevent this behavior, you can call `stop_propogation()` on the e
 
 Some events have a default behavior. For keyboard events, this might be entering the typed character. For mouse events, this might be selecting some text.
 
-In some instances, might want to avoid this default behavior. For this, you can add the `prevent_default` attribute with the name of the handler whose default behavior you want to stop. This attribute is special: you can attach it multiple times for multiple attributes:
+In some instances, might want to avoid this default behavior. For this, you can add the `prevent_default` attribute with the name of the handler whose default behavior you want to stop. This attribute can be used for multiple handlers using their name separated by spaces:
 
 ```rust
 {{#include ../../../examples/event_prevent_default.rs:prevent_default}}

+ 0 - 0
examples/controll_focus.rs → examples/control_focus.rs


+ 4 - 1
packages/desktop/src/file_upload.rs

@@ -4,7 +4,8 @@ use serde::Deserialize;
 
 #[derive(Debug, Deserialize)]
 pub(crate) struct FileDiologRequest {
-    accept: String,
+    #[serde(default)]
+    accept: Option<String>,
     multiple: bool,
     pub event: String,
     pub target: usize,
@@ -16,6 +17,8 @@ pub(crate) fn get_file_event(request: &FileDiologRequest) -> Vec<PathBuf> {
 
     let filters: Vec<_> = request
         .accept
+        .as_deref()
+        .unwrap_or_default()
         .split(',')
         .filter_map(|s| Filters::from_str(s).ok())
         .collect();

+ 8 - 8
packages/desktop/src/protocol.rs

@@ -15,12 +15,12 @@ fn module_loader(root_name: &str) -> String {
     let inputs = document.querySelectorAll("input");
     for (let input of inputs) {
       if (!input.getAttribute("data-dioxus-file-listener")) {
-        input.setAttribute("data-dioxus-file-listener", true);
-        input.addEventListener("click", (event) => {
-          let target = event.target;
-          // prevent file inputs from opening the file dialog on click
-          const type = target.getAttribute("type");
-          if (type === "file") {
+        // prevent file inputs from opening the file dialog on click
+        const type = input.getAttribute("type");
+        if (type === "file") {
+          input.setAttribute("data-dioxus-file-listener", true);
+          input.addEventListener("click", (event) => {
+            let target = event.target;
             let target_id = find_real_id(target);
             if (target_id !== null) {
               const send = (event_name) => {
@@ -30,8 +30,8 @@ fn module_loader(root_name: &str) -> String {
               send("change&input");
             }
             event.preventDefault();
-          }
-        });
+          });
+        }
       }
     }"#,
     );

+ 5 - 1
packages/html/src/events/form.rs

@@ -14,7 +14,11 @@ pub struct FormData {
 
     #[cfg_attr(
         feature = "serialize",
-        serde(skip_serializing, deserialize_with = "deserialize_file_engine")
+        serde(
+            default,
+            skip_serializing,
+            deserialize_with = "deserialize_file_engine"
+        )
     )]
     pub files: Option<std::sync::Arc<dyn FileEngine>>,
 }

+ 35 - 127
packages/interpreter/src/interpreter.js

@@ -206,31 +206,25 @@ class Interpreter {
   }
 
   GetClientRect(id) {
-    const node= this.nodes[id];
+    const node = this.nodes[id];
     if (!node) {
       return;
     }
     const rect = node.getBoundingClientRect();
     return {
       type: "GetClientRect",
-      origin: [
-         rect.x,
-         rect.y,
-      ],
-      size: [
-         rect.width,
-         rect.height,
-      ]
+      origin: [rect.x, rect.y],
+      size: [rect.width, rect.height],
     };
   }
-  
+
   ScrollTo(id, behavior) {
     const node = this.nodes[id];
     if (!node) {
       return false;
     }
     node.scrollIntoView({
-      behavior: behavior
+      behavior: behavior,
     });
     return true;
   }
@@ -248,7 +242,7 @@ class Interpreter {
     }
     return true;
   }
-  
+
   handleEdits(edits) {
     for (let template of edits.templates) {
       this.SaveTemplate(template);
@@ -393,113 +387,19 @@ class Interpreter {
 
         // if this is a mounted listener, we send the event immediately
         if (edit.name === "mounted") {
-            window.ipc.postMessage(
-              serializeIpcMessage("user_event", {
-                name: edit.name,
-                element: edit.id,
-                data: null,
-                bubbles,
-              })
-            );
+          window.ipc.postMessage(
+            serializeIpcMessage("user_event", {
+              name: edit.name,
+              element: edit.id,
+              data: null,
+              bubbles,
+            })
+          );
+        } else {
+          this.NewEventListener(edit.name, edit.id, bubbles, (event) => {
+            handler(event, edit.name, bubbles);
+          });
         }
-
-
-        // this handler is only provided on desktop implementations since this
-        // method is not used by the web implementation
-        let handler = (event) => {
-          let target = event.target;
-          if (target != null) {
-            let realId = target.getAttribute(`data-dioxus-id`);
-            let shouldPreventDefault = target.getAttribute(
-              `dioxus-prevent-default`
-            );
-
-            if (event.type === "click") {
-              // todo call prevent default if it's the right type of event
-              let a_element = target.closest("a");
-              if (a_element != null) {
-                event.preventDefault();
-                if (
-                  shouldPreventDefault !== `onclick` &&
-                  a_element.getAttribute(`dioxus-prevent-default`) !== `onclick`
-                ) {
-                  const href = a_element.getAttribute("href");
-                  if (href !== "" && href !== null && href !== undefined) {
-                    window.ipc.postMessage(
-                      serializeIpcMessage("browser_open", { href })
-                    );
-                  }
-                }
-              }
-
-              // also prevent buttons from submitting
-              if (target.tagName === "BUTTON" && event.type == "submit") {
-                event.preventDefault();
-              }
-            }
-            // walk the tree to find the real element
-            while (realId == null) {
-              // we've reached the root we don't want to send an event
-              if (target.parentElement === null) {
-                return;
-              }
-
-              target = target.parentElement;
-              realId = target.getAttribute(`data-dioxus-id`);
-            }
-
-            shouldPreventDefault = target.getAttribute(
-              `dioxus-prevent-default`
-            );
-
-            let contents = serialize_event(event);
-
-            if (shouldPreventDefault === `on${event.type}`) {
-              event.preventDefault();
-            }
-
-            if (event.type === "submit") {
-              event.preventDefault();
-            }
-
-            if (
-              target.tagName === "FORM" &&
-              (event.type === "submit" || event.type === "input")
-            ) {
-              for (let x = 0; x < target.elements.length; x++) {
-                let element = target.elements[x];
-                let name = element.getAttribute("name");
-                if (name != null) {
-                  if (element.getAttribute("type") === "checkbox") {
-                    // @ts-ignore
-                    contents.values[name] = element.checked ? "true" : "false";
-                  } else if (element.getAttribute("type") === "radio") {
-                    if (element.checked) {
-                      contents.values[name] = element.value;
-                    }
-                  } else {
-                    // @ts-ignore
-                    contents.values[name] =
-                      element.value ?? element.textContent;
-                  }
-                }
-              }
-            }
-
-            if (realId === null) {
-              return;
-            }
-            window.ipc.postMessage(
-              serializeIpcMessage("user_event", {
-                name: edit.name,
-                element: parseInt(realId),
-                data: contents,
-                bubbles,
-              })
-            );
-          }
-        };
-        this.NewEventListener(edit.name, edit.id, bubbles, handler);
         break;
     }
   }
@@ -510,17 +410,24 @@ class Interpreter {
 function handler(event, name, bubbles) {
   let target = event.target;
   if (target != null) {
-    let shouldPreventDefault = target.getAttribute(`dioxus-prevent-default`);
+    let preventDefaultRequests = target.getAttribute(`dioxus-prevent-default`);
 
     if (event.type === "click") {
-      // Prevent redirects from links
+      // todo call prevent default if it's the right type of event
       let a_element = target.closest("a");
       if (a_element != null) {
         event.preventDefault();
-        if (
-          shouldPreventDefault !== `onclick` &&
-          a_element.getAttribute(`dioxus-prevent-default`) !== `onclick`
-        ) {
+
+        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(
@@ -538,9 +445,10 @@ function handler(event, name, bubbles) {
 
     const realId = find_real_id(target);
 
-    shouldPreventDefault = target.getAttribute(`dioxus-prevent-default`);
-
-    if (shouldPreventDefault === `on${event.type}`) {
+    if (
+      preventDefaultRequests &&
+      preventDefaultRequests.includes(`on${event.type}`)
+    ) {
       event.preventDefault();
     }
 

+ 8 - 4
packages/web/src/dom.rs

@@ -56,13 +56,17 @@ impl WebsysDom {
                 let element = walk_event_for_id(event);
                 let bubbles = dioxus_html::event_bubbles(name.as_str());
                 if let Some((element, target)) = element {
-                    if target
+                    if let Some(prevent_requests) = target
                         .get_attribute("dioxus-prevent-default")
                         .as_deref()
-                        .map(|f| f.trim_start_matches("on"))
-                        == Some(&name)
+                        .map(|f| f.split_whitespace())
                     {
-                        event.prevent_default();
+                        if prevent_requests
+                            .map(|f| f.trim_start_matches("on"))
+                            .any(|f| f == name)
+                        {
+                            event.prevent_default();
+                        }
                     }
 
                     let data = virtual_event_from_websys_event(event.clone(), target);