use rstml::node;
use syn::__private::quote::quote;
use syn::__private::TokenStream2;
use syn::spanned::Spanned;
use crate::fns::html::{
tmp,
HTMLCustomAttribute,
HTMLMacro,
HTMLMacroParserError,
HTMLMacroParserErrorKind,
Result,
};
impl HTMLMacro {
pub fn handle_href_method_attribute(
&self,
element: &rstml::node::NodeElement,
tag_name: &str,
_: &mut Vec<TokenStream2>,
attr: &rstml::node::KeyedAttribute,
custom_attr: HTMLCustomAttribute,
) -> Result<TokenStream2> {
assert!(matches!(
custom_attr,
HTMLCustomAttribute::HrefDelete
| HTMLCustomAttribute::HrefPost
| HTMLCustomAttribute::HrefPut
));
if tag_name != "a" {
return Err(HTMLMacroParserError {
span: element.span(),
kind: HTMLMacroParserErrorKind::InvalidTag {
expected: "a",
found: tag_name.to_owned(),
},
});
}
let link_id = element
.attributes()
.iter()
.find_map(|attribute| {
if let node::NodeAttribute::Attribute(node_attr) = attribute {
return node_attr
.key
.to_string()
.eq("id")
.then(|| node_attr.value_literal_string());
}
None
})
.unwrap_or_else(|| {
let uid = uuid::Uuid::new_v4();
format!("lx{}", uid.simple()).into()
})
.unwrap();
let href_value = attr.value();
let tag_attrs = [
tmp::create_attribute("href", href_value),
tmp::create_attribute("form", &link_id),
];
let method = match custom_attr {
| HTMLCustomAttribute::HrefPatch => "PATCH",
| HTMLCustomAttribute::HrefPost => "POST",
| HTMLCustomAttribute::HrefPut => "PUT",
| HTMLCustomAttribute::HrefDelete => "DELETE",
| _ => "",
};
let script_attrs = [tmp::create_attribute("type", "module")];
let script_children = include_str!("../../../js/form_link.js")
.replace("{id}", &link_id)
.replace("{method}", method);
let link_children = self.parse(&element.children)?;
let mut form_children = element
.attributes()
.iter()
.filter_map(|attr| {
let node::NodeAttribute::Attribute(attr) = attr else {
return None;
};
let key_without_data_keyword = &attr.key.to_string()[5..];
let data_key_value = attr.value();
attr.key.to_string().contains("data-").then_some({
tmp::create_void_element(
"input",
&[
tmp::create_attribute("type", "hidden"),
tmp::create_attribute(
"name",
key_without_data_keyword,
),
tmp::create_attribute("value", data_key_value),
],
)
})
})
.collect::<Vec<_>>();
form_children.push(tmp::create_void_element(
"input",
&[
tmp::create_attribute("type", "hidden"),
tmp::create_attribute("name", "_method"),
tmp::create_attribute("value", method),
],
));
let fragment = tmp::create_fragment(&[
tmp::create_element(
"form",
&[
tmp::create_attribute("id", &link_id),
tmp::create_attribute("action", href_value),
tmp::create_attribute("method", "POST"),
],
&form_children,
),
tmp::create_element("a", &tag_attrs, &link_children),
tmp::create_element(
"script",
&script_attrs,
&[quote! {
Node::create_unsafe_html(#script_children)
}],
),
]);
Ok(fragment)
}
}