More fullstack fixes (#4737)
* allow `--server` only builds! * rollback example * capture `/:route` routes * fix: properly implement file uploads in forms * implement desktop form uploads * Performant serialization of form bytes * finish up file stuff * cleanups * add request headers to streaming context * remove some unwraps
This commit is contained in:
1 parent
fc01a002fd
commit
92792aded9
47 files changed
+1241
-703
No files matched your search
@@ -85,7 +85,8 @@ features = [
|
||||
"File",
|
||||
"FileList",
|
||||
"FileReader",
|
||||
"ReadableStream"
|
||||
"ReadableStream",
|
||||
"FormData"
|
||||
]
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
use std::{any::Any, collections::HashMap};
|
||||
|
||||
use super::WebEventExt;
|
||||
use crate::WebFileData;
|
||||
use dioxus_html::{FileData, FormValue, HasFileData, HasFormData};
|
||||
use js_sys::Array;
|
||||
use wasm_bindgen::JsValue;
|
||||
use std::any::Any;
|
||||
use wasm_bindgen::{prelude::wasm_bindgen, JsCast};
|
||||
use web_sys::{Element, Event};
|
||||
|
||||
use super::WebEventExt;
|
||||
use web_sys::{Element, Event, FileReader};
|
||||
|
||||
pub(crate) struct WebFormData {
|
||||
element: Element,
|
||||
@@ -67,26 +65,29 @@ impl HasFormData for WebFormData {
|
||||
.expect("only an InputElement or TextAreaElement or an element with contenteditable=true can have an oninput event listener")
|
||||
}
|
||||
|
||||
fn values(&self) -> HashMap<String, FormValue> {
|
||||
let mut values = HashMap::new();
|
||||
|
||||
fn insert_value(map: &mut HashMap<String, FormValue>, key: String, new_value: String) {
|
||||
map.entry(key.clone()).or_default().0.push(new_value);
|
||||
}
|
||||
fn values(&self) -> Vec<(String, FormValue)> {
|
||||
let mut values = Vec::new();
|
||||
|
||||
// try to fill in form values
|
||||
if let Some(form) = self.element.dyn_ref::<web_sys::HtmlFormElement>() {
|
||||
let form_data = get_form_data(form);
|
||||
for value in form_data.entries().into_iter().flatten() {
|
||||
if let Ok(array) = value.dyn_into::<Array>() {
|
||||
let form_data = web_sys::FormData::new_with_form(form).unwrap();
|
||||
|
||||
for entry in form_data.entries().into_iter().flatten() {
|
||||
if let Ok(array) = entry.dyn_into::<Array>() {
|
||||
if let Some(name) = array.get(0).as_string() {
|
||||
if let Ok(item_values) = array.get(1).dyn_into::<Array>() {
|
||||
item_values
|
||||
.iter()
|
||||
.filter_map(|v| v.as_string())
|
||||
.for_each(|v| insert_value(&mut values, name.clone(), v));
|
||||
} else if let Ok(item_value) = array.get(1).dyn_into::<JsValue>() {
|
||||
insert_value(&mut values, name, item_value.as_string().unwrap());
|
||||
let value = array.get(1);
|
||||
if let Some(file) = value.dyn_ref::<web_sys::File>() {
|
||||
if file.name().is_empty() {
|
||||
values.push((name, FormValue::File(None)));
|
||||
} else {
|
||||
let data =
|
||||
WebFileData::new(file.clone(), FileReader::new().unwrap());
|
||||
let as_file = FileData::new(data);
|
||||
|
||||
values.push((name, FormValue::File(Some(as_file))));
|
||||
}
|
||||
} else if let Some(s) = value.as_string() {
|
||||
values.push((name, FormValue::Text(s)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,7 +95,9 @@ impl HasFormData for WebFormData {
|
||||
} else if let Some(select) = self.element.dyn_ref::<web_sys::HtmlSelectElement>() {
|
||||
// try to fill in select element values
|
||||
let options = get_select_data(select);
|
||||
values.insert("options".to_string(), FormValue(options));
|
||||
for option in &options {
|
||||
values.push((select.name(), FormValue::Text(option.clone())));
|
||||
}
|
||||
}
|
||||
|
||||
values
|
||||
@@ -103,6 +106,14 @@ impl HasFormData for WebFormData {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
&self.event as &dyn Any
|
||||
}
|
||||
|
||||
fn valid(&self) -> bool {
|
||||
self.event
|
||||
.target()
|
||||
.and_then(|t| t.dyn_into::<web_sys::HtmlInputElement>().ok())
|
||||
.map(|input| input.check_validity())
|
||||
.unwrap_or(true)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasFileData for WebFormData {
|
||||
@@ -135,20 +146,3 @@ export function get_select_data(select) {
|
||||
extern "C" {
|
||||
fn get_select_data(select: &web_sys::HtmlSelectElement) -> Vec<String>;
|
||||
}
|
||||
|
||||
// web-sys does not expose the keys api for form data, so we need to manually bind to it
|
||||
#[wasm_bindgen(inline_js = r#"
|
||||
export function get_form_data(form) {
|
||||
let values = new Map();
|
||||
const formData = new FormData(form);
|
||||
|
||||
for (let name of formData.keys()) {
|
||||
values.set(name, formData.getAll(name));
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
"#)]
|
||||
extern "C" {
|
||||
fn get_form_data(form: &web_sys::HtmlFormElement) -> js_sys::Map;
|
||||
}
|
||||
Reference in new issue
Block a user