Browse Source

prevent default file input behavior on desktop

Evan Almloff 2 years ago
parent
commit
d7eae79509
2 changed files with 115 additions and 93 deletions
  1. 17 1
      packages/desktop/src/protocol.rs
  2. 98 92
      packages/interpreter/src/interpreter.js

+ 17 - 1
packages/desktop/src/protocol.rs

@@ -9,10 +9,26 @@ use wry::{
 };
 
 fn module_loader(root_name: &str) -> String {
+    let js = INTERPRETER_JS.replace(
+        "/*POST_HANDLE_EDITS*/",
+        r#"// Prevent file inputs from opening the file dialog on click
+    let inputs = document.querySelectorAll("input");
+    for (let input of inputs) {
+      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") {
+          window.ipc.postMessage(serializeIpcMessage("file_diolog", { accept: target.getAttribute("accept"), multiple: target.hasAttribute("multiple") }));
+          event.preventDefault();
+        }
+      });
+    }"#,
+    );
     format!(
         r#"
 <script>
-    {INTERPRETER_JS}
+    {js}
 
     let rootname = "{root_name}";
     let root = window.document.getElementById(rootname);

+ 98 - 92
packages/interpreter/src/interpreter.js

@@ -17,8 +17,7 @@ class ListenerMap {
       } else {
         this.global[event_name].active++;
       }
-    }
-    else {
+    } else {
       const id = element.getAttribute("data-dioxus-id");
       if (!this.local[id]) {
         this.local[id] = {};
@@ -32,11 +31,13 @@ class ListenerMap {
     if (bubbles) {
       this.global[event_name].active--;
       if (this.global[event_name].active === 0) {
-        this.root.removeEventListener(event_name, this.global[event_name].callback);
+        this.root.removeEventListener(
+          event_name,
+          this.global[event_name].callback
+        );
         delete this.global[event_name];
       }
-    }
-    else {
+    } else {
       const id = element.getAttribute("data-dioxus-id");
       delete this.local[id][event_name];
       if (this.local[id].length === 0) {
@@ -143,8 +144,7 @@ class Interpreter {
   SetAttribute(id, field, value, ns) {
     if (value === null) {
       this.RemoveAttribute(id, field, ns);
-    }
-    else {
+    } else {
       const node = this.nodes[id];
       this.SetAttributeInner(node, field, value, ns);
     }
@@ -212,6 +212,8 @@ class Interpreter {
     for (let edit of edits.edits) {
       this.handleEdit(edit);
     }
+
+    /*POST_HANDLE_EDITS*/
   }
 
   SaveTemplate(template) {
@@ -342,105 +344,109 @@ class Interpreter {
         this.RemoveEventListener(edit.id, edit.name);
         break;
       case "NewEventListener":
-
         let bubbles = event_bubbles(edit.name);
+        this.NewEventListener(edit.name, edit.id, bubbles, handler);
+        break;
+    }
+  }
+}
 
-        // 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`
+// this handler is only provided on desktop implementations since this
+// method is not used by the web implementation
+function handler(event) {
+  console.log(event);
+  let target = event.target;
+  if (target != null) {
+    let shouldPreventDefault = target.getAttribute(`dioxus-prevent-default`);
+
+    if (event.type === "click") {
+      // Prevent redirects from links
+      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 })
             );
+          }
+        }
+      }
 
-            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`);
-            }
+      // also prevent buttons from submitting
+      if (target.tagName === "BUTTON" && event.type == "submit") {
+        event.preventDefault();
+      }
+    }
 
-            shouldPreventDefault = target.getAttribute(
-              `dioxus-prevent-default`
-            );
+    const realId = find_real_id(target);
 
-            let contents = serialize_event(event);
+    shouldPreventDefault = target.getAttribute(`dioxus-prevent-default`);
 
-            if (shouldPreventDefault === `on${event.type}`) {
-              event.preventDefault();
-            }
+    let contents = serialize_event(event);
 
-            if (event.type === "submit") {
-              event.preventDefault();
-            }
+    if (shouldPreventDefault === `on${event.type}`) {
+      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 (event.type === "submit") {
+      event.preventDefault();
+    }
 
-            if (realId === null) {
-              return;
+    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;
             }
-            window.ipc.postMessage(
-              serializeIpcMessage("user_event", {
-                name: edit.name,
-                element: parseInt(realId),
-                data: contents,
-                bubbles,
-              })
-            );
+          } else {
+            // @ts-ignore
+            contents.values[name] = element.value ?? element.textContent;
           }
-        };
-        this.NewEventListener(edit.name, edit.id, bubbles, handler);
-        break;
+        }
+      }
+    }
+
+    if (realId === null) {
+      return;
     }
+    window.ipc.postMessage(
+      serializeIpcMessage("user_event", {
+        name: edit.name,
+        element: parseInt(realId),
+        data: contents,
+        bubbles,
+      })
+    );
+  }
+}
+
+function find_real_id(target) {
+  let realId = target.getAttribute(`data-dioxus-id`);
+  // 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`);
   }
+  return realId;
 }
 
 function get_mouse_data(event) {