use leptos::{html::Form, prelude::*};
use serde::de::DeserializeOwned;
use web_sys::{CustomEvent, CustomEventInit, Event, EventInit, EventTarget};
use js_sys::Array;
use serde_json::{Map, Number, Value};
use web_sys::FormData;
pub fn get_form_data_from_form_ref(form_ref: &NodeRef<Form>) -> Option<FormData> {
let form = form_ref.to_owned().get_untracked()?;
let form_data = FormData::new_with_form(&form).ok()?;
Some(form_data)
}
pub fn deserialize_form<T: DeserializeOwned>(
form_ref: &NodeRef<Form>,
deserialize_bool: bool,
vec_fields: Option<&[&str]>,
) -> Option<T> {
let form_data = get_form_data_from_form_ref(form_ref)?;
if let Some(entries) = js_sys::try_iter(&form_data).ok()? {
let mut map = Map::new();
for entry in entries {
let pair = entry.ok()?;
let arr = Array::from(&pair);
let key = arr.get(0).as_string()?;
let value = arr.get(1);
let is_vec_field = vec_fields
.map(|fields| fields.contains(&key.as_str()))
.unwrap_or(false);
if let Some(s) = value.as_string() {
let val = if s.is_empty() {
Value::Null
} else if deserialize_bool && (s == "true" || s == "false") {
Value::Bool(s.parse::<bool>().unwrap_or_default())
} else {
let trimmed = s.trim();
if let Ok(i) = trimmed.parse::<i64>() {
Value::Number(Number::from(i))
}
else if let Ok(f) = trimmed.parse::<f64>() {
Number::from_f64(f)
.map(Value::Number)
.unwrap_or(Value::String(trimmed.to_string()))
} else {
Value::String(trimmed.to_string())
}
};
match map.get_mut(&key) {
Some(existing) => match existing {
Value::Array(arr) => {
arr.push(val);
}
prev => {
let new_arr = vec![prev.clone(), val];
*prev = Value::Array(new_arr);
}
},
None => {
if is_vec_field {
map.insert(key, Value::Array(vec![val]));
} else {
map.insert(key, val);
}
}
}
}
}
let value = Value::Object(map);
serde_json::from_value(value).ok()
} else {
None
}
}
pub fn fire_bubbled_and_cancelable_event<T>(
event_type: &str,
bubbles: bool,
cancelable: bool,
element: &T,
) -> ()
where
T: AsRef<EventTarget>,
{
let init = EventInit::new();
init.set_bubbles(bubbles);
init.set_cancelable(cancelable);
let _event = match Event::new_with_event_init_dict(event_type, &init) {
Ok(ev) => {
element.as_ref().dispatch_event(&ev).unwrap_or_default();
}
Err(_e) => {}
};
}
pub fn fire_custom_bubbled_and_cancelable_event<T>(
event_type: &str,
bubbles: bool,
cancelable: bool,
element: &T,
) -> ()
where
T: AsRef<EventTarget>,
{
let init = CustomEventInit::new();
init.set_bubbles(bubbles);
init.set_cancelable(cancelable);
let _event = match CustomEvent::new_with_event_init_dict(event_type, &init) {
Ok(ev) => {
element.as_ref().dispatch_event(&ev).unwrap_or_default();
}
Err(_e) => {}
};
}