use http::HeaderValue;
use http::response::Parts;
use topcoat_core::{context::Cx, error::Result};
use topcoat_router::IntoResponseParts;
use crate::SwapOption;
use crate::header;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HxPushUrl(pub String);
impl HxPushUrl {
#[must_use]
pub fn prevent() -> Self {
Self("false".to_owned())
}
}
impl<T: Into<String>> From<T> for HxPushUrl {
fn from(url: T) -> Self {
Self(url.into())
}
}
impl IntoResponseParts for HxPushUrl {
fn into_response_parts(self, _cx: &Cx, parts: &mut Parts) -> Result<()> {
parts
.headers
.insert(header::HX_PUSH_URL, HeaderValue::from_str(&self.0)?);
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HxReplaceUrl(pub String);
impl HxReplaceUrl {
#[must_use]
pub fn prevent() -> Self {
Self("false".to_owned())
}
}
impl<T: Into<String>> From<T> for HxReplaceUrl {
fn from(url: T) -> Self {
Self(url.into())
}
}
impl IntoResponseParts for HxReplaceUrl {
fn into_response_parts(self, _cx: &Cx, parts: &mut Parts) -> Result<()> {
parts
.headers
.insert(header::HX_REPLACE_URL, HeaderValue::from_str(&self.0)?);
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HxRedirect(pub String);
impl<T: Into<String>> From<T> for HxRedirect {
fn from(url: T) -> Self {
Self(url.into())
}
}
impl IntoResponseParts for HxRedirect {
fn into_response_parts(self, _cx: &Cx, parts: &mut Parts) -> Result<()> {
parts
.headers
.insert(header::HX_REDIRECT, HeaderValue::from_str(&self.0)?);
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct HxRefresh(pub bool);
impl From<bool> for HxRefresh {
fn from(refresh: bool) -> Self {
Self(refresh)
}
}
impl IntoResponseParts for HxRefresh {
fn into_response_parts(self, _cx: &Cx, parts: &mut Parts) -> Result<()> {
let value = if self.0 { "true" } else { "false" };
parts
.headers
.insert(header::HX_REFRESH, HeaderValue::from_static(value));
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct HxReswap(pub SwapOption);
impl From<SwapOption> for HxReswap {
fn from(option: SwapOption) -> Self {
Self(option)
}
}
impl IntoResponseParts for HxReswap {
fn into_response_parts(self, _cx: &Cx, parts: &mut Parts) -> Result<()> {
parts.headers.insert(header::HX_RESWAP, self.0.into());
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HxRetarget(pub String);
impl<T: Into<String>> From<T> for HxRetarget {
fn from(selector: T) -> Self {
Self(selector.into())
}
}
impl IntoResponseParts for HxRetarget {
fn into_response_parts(self, _cx: &Cx, parts: &mut Parts) -> Result<()> {
parts
.headers
.insert(header::HX_RETARGET, HeaderValue::from_str(&self.0)?);
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HxReselect(pub String);
impl<T: Into<String>> From<T> for HxReselect {
fn from(selector: T) -> Self {
Self(selector.into())
}
}
impl IntoResponseParts for HxReselect {
fn into_response_parts(self, _cx: &Cx, parts: &mut Parts) -> Result<()> {
parts
.headers
.insert(header::HX_RESELECT, HeaderValue::from_str(&self.0)?);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
fn parts() -> Parts {
http::Response::new(()).into_parts().0
}
fn header_value(parts: &Parts, name: &http::HeaderName) -> String {
parts
.headers
.get(name)
.unwrap()
.to_str()
.unwrap()
.to_owned()
}
#[test]
fn push_url_sets_header() {
let mut parts = parts();
HxPushUrl::from("/new")
.into_response_parts(&Cx::default(), &mut parts)
.unwrap();
assert_eq!(header_value(&parts, &header::HX_PUSH_URL), "/new");
}
#[test]
fn push_url_prevent_is_false() {
let mut parts = parts();
HxPushUrl::prevent()
.into_response_parts(&Cx::default(), &mut parts)
.unwrap();
assert_eq!(header_value(&parts, &header::HX_PUSH_URL), "false");
}
#[test]
fn refresh_serializes_bool() {
let mut parts = parts();
HxRefresh(true)
.into_response_parts(&Cx::default(), &mut parts)
.unwrap();
assert_eq!(header_value(&parts, &header::HX_REFRESH), "true");
}
#[test]
fn reswap_uses_swap_option_string() {
let mut parts = parts();
HxReswap(SwapOption::BeforeEnd)
.into_response_parts(&Cx::default(), &mut parts)
.unwrap();
assert_eq!(header_value(&parts, &header::HX_RESWAP), "beforeend");
}
#[test]
fn retarget_and_reselect_carry_selectors() {
let mut parts = parts();
HxRetarget::from("#main")
.into_response_parts(&Cx::default(), &mut parts)
.unwrap();
HxReselect::from(".item")
.into_response_parts(&Cx::default(), &mut parts)
.unwrap();
assert_eq!(header_value(&parts, &header::HX_RETARGET), "#main");
assert_eq!(header_value(&parts, &header::HX_RESELECT), ".item");
}
}