use crate::{
attribute::{AttributeValue, IntoAttributeValue},
element::Element,
html_element::HtmlElement,
};
use pastey::paste;
#[derive(Debug, Clone, Copy)]
pub enum HXSwap {
InnerHtml,
OuterHTML,
TextContent,
BeforeBegin,
AfterBegin,
BeforeEnd,
AfterEnd,
Delete,
None,
}
impl std::fmt::Display for HXSwap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
HXSwap::InnerHtml => "innerHtml",
HXSwap::OuterHTML => "outerHTML",
HXSwap::TextContent => "textContent",
HXSwap::BeforeBegin => "beforebegin",
HXSwap::AfterBegin => "afterbegin",
HXSwap::BeforeEnd => "beforeend",
HXSwap::AfterEnd => "afterend",
HXSwap::Delete => "delete",
HXSwap::None => "none",
};
write!(f, "{}", s)
}
}
impl IntoAttributeValue for HXSwap {
fn into_attr(self) -> Option<AttributeValue> {
Some(AttributeValue::Value(self.to_string()))
}
}
#[derive(Debug, Clone)]
pub enum HXTarget<'a> {
This,
Closest(&'a str),
Find,
Next,
NextSelector(&'a str),
Previous,
PreviousSelector(&'a str),
}
impl std::fmt::Display for HXTarget<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
HXTarget::This => "this",
HXTarget::Closest(o) => {
return write!(f, "closest {}", o);
}
HXTarget::Find => "find",
HXTarget::Next => "next",
HXTarget::NextSelector(o) => {
return write!(f, "next {}", o);
}
HXTarget::Previous => "previous",
HXTarget::PreviousSelector(o) => {
return write!(f, "previous {}", o);
}
};
write!(f, "{}", s)
}
}
impl IntoAttributeValue for HXTarget<'_> {
fn into_attr(self) -> Option<AttributeValue> {
Some(AttributeValue::Value(self.to_string()))
}
}
#[derive(Debug, Clone, Copy)]
pub enum HtmxRequestHeader {
HXBoosted,
HXCurrentURL,
HXHistoryRestoreRequest,
HXPrompt,
HXRequest,
HXTarget,
HXTriggerName,
HXTrigger,
}
impl std::fmt::Display for HtmxRequestHeader {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
HtmxRequestHeader::HXBoosted => "HX-Boosted",
HtmxRequestHeader::HXCurrentURL => "HX-Current-URL",
HtmxRequestHeader::HXHistoryRestoreRequest => "HX-History-Restore-Request",
HtmxRequestHeader::HXPrompt => "HX-Prompt",
HtmxRequestHeader::HXRequest => "HX-Request",
HtmxRequestHeader::HXTarget => "HX-Target",
HtmxRequestHeader::HXTriggerName => "HX-Trigger-Name",
HtmxRequestHeader::HXTrigger => "HX-Trigger",
};
write!(f, "{}", s)
}
}
#[derive(Debug, Clone, Copy)]
pub enum HtmxResponseHeader {
HXLocation,
HXPushUrl,
HXRedirect,
HXRefresh,
HXReplaceUrl,
HXReswap,
HXRetarget,
HXReselect,
HXTrigger,
HXTriggerAfterSettle,
HXTriggerAfterSwap,
}
impl std::fmt::Display for HtmxResponseHeader {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
HtmxResponseHeader::HXLocation => "HX-Location",
HtmxResponseHeader::HXPushUrl => "HX-Push-Url",
HtmxResponseHeader::HXRedirect => "HX-Redirect",
HtmxResponseHeader::HXRefresh => "HX-Refresh",
HtmxResponseHeader::HXReplaceUrl => "HX-Replace-Url",
HtmxResponseHeader::HXReswap => "HX-Reswap",
HtmxResponseHeader::HXRetarget => "HX-Retarget",
HtmxResponseHeader::HXReselect => "HX-Reselect",
HtmxResponseHeader::HXTrigger => "HX-Trigger",
HtmxResponseHeader::HXTriggerAfterSettle => "HX-Trigger-After-Settle",
HtmxResponseHeader::HXTriggerAfterSwap => "HX-Trigger-After-Swap",
};
write!(f, "{}", s)
}
}
macro_rules! set_htmx_attr {
($attr:ident = $name:expr; $eg:expr) => {
paste! {
#[doc = "Sets the `" $name "` attribute.\nExample: `" $eg "`"]
pub fn $attr(self, value: impl IntoAttributeValue) -> Self {
self.set_raw_attr($name, value)
}
}
};
($attr:ident = $name:expr) => {
paste! {
#[doc = "Sets the `" $name "` attribute."]
pub fn $attr(self, value: impl IntoAttributeValue) -> Self {
self.set_raw_attr($name, value)
}
}
};
($attr:ident) => {
paste! {
#[doc = "Sets the `" $attr "` attribute."]
pub fn $attr(self, value: impl IntoAttributeValue) -> Self {
self.set_raw_attr(stringify!([< $attr:lower >]), value)
}
}
};
($attr:ident$(=$name:expr)?$(;$eg:expr)?, $($rest:ident$(=$name_rest:expr)?$(;$eg_rest:expr)?),+) => {
set_htmx_attr!($attr$(=$name)?$(;$eg)?);
set_htmx_attr!($($rest$(=$name_rest)?$(;$eg_rest)?),+);
};
}
impl HtmlElement {
set_htmx_attr!(
hx_boost = "hx-boost"; r#"a().hx_boost("true")"#,
hx_confirm = "hx-confirm",
hx_delete = "hx-delete",
hx_disable = "hx-disable",
hx_disabled_elt = "hx-disabled-elt",
hx_ext = "hx-ext",
hx_get = "hx-get",
hx_headers = "hx-headers",
hx_history = "hx-history",
hx_history_elt = "hx-history-elt",
hx_include = "hx-include",
hx_indicator = "hx-indicator",
hx_inherit = "hx-inherit",
hx_params = "hx-params",
hx_patch = "hx-patch",
hx_post = "hx-post",
hx_preserve = "hx-preserve",
hx_prompt = "hx-prompt",
hx_push_url = "hx-push-url",
hx_put = "hx-put",
hx_replace_url = "hx-replace-url",
hx_request = "hx-request",
hx_select = "hx-select",
hx_select_oob = "hx-select-oob",
hx_swap = "hx-swap"; "div().hx_swap(HXSwap::OuterHTML)",
hx_swap_oob = "hx-swap-oob",
hx_sync = "hx-sync",
hx_target = "hx-target"; r#"div().hx_target(HXTarget::Closest("form"))"#,
hx_trigger = "hx-trigger",
hx_validate = "hx-validate",
hx_vals = "hx-vals"; r##"div().hx_vals(format!(r#"{{"key": "{x}"}}"#))"##,
sse_connect = "sse-connect",
sse_swap = "sse-swap",
ws_connect = "ws-connect",
ws_send = "ws-send"
);
}
#[cfg(test)]
mod test {
use super::*;
use crate::{html_element::*, render::Render};
#[test]
fn hx_attr_works() {
let token = "asdoiu12309usad";
let res = p()
.hx_get("/some_route")
.hx_swap(HXSwap::OuterHTML)
.hx_headers(format!(r#"{{"Authorization": "Bearer {}"}}"#, token))
.render();
insta::assert_snapshot!(res, @r#"<p hx-get="/some_route" hx-swap="outerHTML" hx-headers='{"Authorization": "Bearer asdoiu12309usad"}'></p>"#);
}
#[test]
fn hx_vals_works() {
let res = div().hx_vals(r#"{"myVal": "My Value"}"#).render();
insta::assert_snapshot!(res, @r#"<div hx-vals='{"myVal": "My Value"}'></div>"#);
}
}