Skip to content

Commit

Permalink
Add dedicated annoations for HX-Trigger-After-Settle and HX-Trigger-A…
Browse files Browse the repository at this point in the history
…fter-Swap and support multiple events
  • Loading branch information
xhaggi committed May 1, 2024
1 parent 9e8f235 commit 680123c
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public boolean preHandle(HttpServletRequest request,
setHxRetarget(response, method);
setHxReselect(response, method);
setHxTrigger(response, method);
setHxTriggerAfterSettle(response, method);
setHxTriggerAfterSwap(response, method);
setHxRefresh(response, method);
setVary(request, response);
}
Expand Down Expand Up @@ -108,7 +110,27 @@ private void setHxReselect(HttpServletResponse response, Method method) {
private void setHxTrigger(HttpServletResponse response, Method method) {
HxTrigger methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, HxTrigger.class);
if (methodAnnotation != null) {
response.setHeader(getHeaderName(methodAnnotation.lifecycle()), methodAnnotation.value());
response.setHeader(
getHeaderName(methodAnnotation.lifecycle()),
String.join( ",", methodAnnotation.value()));
}
}

private void setHxTriggerAfterSettle(HttpServletResponse response, Method method) {
HxTriggerAfterSettle methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, HxTriggerAfterSettle.class);
if (methodAnnotation != null) {
response.setHeader(
HtmxResponseHeader.HX_TRIGGER_AFTER_SETTLE.getValue(),
String.join( ",", methodAnnotation.value()));
}
}

private void setHxTriggerAfterSwap(HttpServletResponse response, Method method) {
HxTriggerAfterSwap methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, HxTriggerAfterSwap.class);
if (methodAnnotation != null) {
response.setHeader(
HtmxResponseHeader.HX_TRIGGER_AFTER_SWAP.getValue(),
String.join( ",", methodAnnotation.value()));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@
import java.lang.annotation.Target;

/**
* Annotation to trigger client side actions on the target element within a response to htmx.
* Annotation to trigger client side events as soon as the response is received on the target element.
* <br>
* You can trigger a single event or as many uniquely named events as you would like.
*
* @see <a href="https://htmx.org/headers/hx-trigger/">HX-Trigger Response Headers</a>
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface HxTrigger {
String value();

String[] value();

HxTriggerLifecycle lifecycle() default HxTriggerLifecycle.RECEIVE;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.github.wimdeblauwe.htmx.spring.boot.mvc;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Annotation to trigger client side events after the
* <a href="https://htmx.org/docs/#request-operations">settling step</a>
* on the target element.
* <br>
* You can trigger a single event or as many uniquely named events as you would like.
*
* @see <a href="https://htmx.org/headers/hx-trigger/">HX-Trigger Response Headers</a>
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface HxTriggerAfterSettle {

/**
* The events to trigger after the
* <a href="https://htmx.org/docs/#request-operations">settling step</a>
* on the target element.
*/
String[] value();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.github.wimdeblauwe.htmx.spring.boot.mvc;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Annotation to trigger client side events after the
* <a href="https://htmx.org/docs/#request-operations">swap step</a>
* on the target element.
* <br>
* You can trigger a single event or as many uniquely named events as you would like.
*
* @see <a href="https://htmx.org/headers/hx-trigger/">HX-Trigger Response Headers</a>
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface HxTriggerAfterSwap {

/**
* The events to trigger after the
* <a href="https://htmx.org/docs/#request-operations">swap step</a>
* on the target element.
*/
String[] value();

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
* Represents the HX-Trigger Response Headers.
*
* @see <a href="https://htmx.org/headers/hx-trigger/">HX-Trigger Response Headers</a>
* @deprecated use annotation {@link HxTriggerAfterSettle} or {@link HxTriggerAfterSwap} instead.
*/
@Deprecated
public enum HxTriggerLifecycle {
/**
* Trigger events as soon as the response is received.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ public void testHeaderIsSetOnResponseIfHxTriggerIsPresent() throws Exception {
.andExpect(header().string("HX-Trigger", "eventTriggered"));
}

@Test
public void testHeaderIsSetOnResponseWithMultipleEventsIfHxTriggerIsPresent() throws Exception {
mockMvc.perform(get("/with-trigger-multiple-events"))
.andExpect(status().isOk())
.andExpect(header().string("HX-Trigger", "event1,event2"));
}

@Test
public void testAfterSettleHeaderIsSetOnResponseIfHxTriggerIsPresent() throws Exception {
mockMvc.perform(get("/with-trigger-settle"))
Expand All @@ -40,6 +47,34 @@ public void testAfterSwapHeaderIsSetOnResponseIfHxTriggerIsPresent() throws Exce
.andExpect(header().string("HX-Trigger-After-Swap", "eventTriggered"));
}

@Test
public void testAfterSettleHeaderIsSetOnResponseIfHxTriggerAfterSettleIsPresent() throws Exception {
mockMvc.perform(get("/with-trigger-after-settle"))
.andExpect(status().isOk())
.andExpect(header().string("HX-Trigger-After-Settle", "eventTriggered"));
}

@Test
public void testAfterSettleHeaderIsSetOnResponseWithMultipleEventsIfHxTriggerAfterSettleIsPresent() throws Exception {
mockMvc.perform(get("/with-trigger-after-settle-multiple-events"))
.andExpect(status().isOk())
.andExpect(header().string("HX-Trigger-After-Settle", "event1,event2"));
}

@Test
public void testAfterSwapHeaderIsSetOnResponseIfHxTriggerAfterSwapIsPresent() throws Exception {
mockMvc.perform(get("/with-trigger-after-swap"))
.andExpect(status().isOk())
.andExpect(header().string("HX-Trigger-After-Swap", "eventTriggered"));
}

@Test
public void testAfterSwapHeaderIsSetOnResponseWithMultipleEventsIfHxTriggerAfterSwapIsPresent() throws Exception {
mockMvc.perform(get("/with-trigger-after-swap-multiple-events"))
.andExpect(status().isOk())
.andExpect(header().string("HX-Trigger-After-Swap", "event1,event2"));
}

@Test
public void testHeaderIsNotSetOnResponseIfHxTriggerNotPresent() throws Exception {
mockMvc.perform(get("/without-trigger"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,55 @@ public String methodWithHxTrigger() {
return "";
}

@GetMapping("/with-trigger-multiple-events")
@HxTrigger({ "event1", "event2" })
@ResponseBody
public String methodWithHxTriggerAndMultipleEvents() {
return "";
}

@GetMapping("/with-trigger-settle")
@HxTrigger(value = "eventTriggered", lifecycle = HxTriggerLifecycle.SETTLE)
@ResponseBody
public String methodWithHxTriggerAfterSettle() {
public String methodWithHxTriggerAndLifecycleSettle() {
return "";
}

@GetMapping("/with-trigger-swap")
@HxTrigger(value = "eventTriggered", lifecycle = HxTriggerLifecycle.SWAP)
@ResponseBody
public String methodWithHxTriggerAndLifecycleSwap() {
return "";
}

@GetMapping("/with-trigger-after-settle")
@HxTriggerAfterSettle("eventTriggered")
@ResponseBody
public String methodWithHxTriggerAfterSettle() {
return "";
}

@GetMapping("/with-trigger-after-settle-multiple-events")
@HxTriggerAfterSettle({ "event1", "event2" })
@ResponseBody
public String methodWithHxTriggerAfterSettleAndMultipleEvents() {
return "";
}

@GetMapping("/with-trigger-after-swap")
@HxTriggerAfterSwap("eventTriggered")
@ResponseBody
public String methodWithHxTriggerAfterSwap() {
return "";
}

@GetMapping("/with-trigger-after-swap-multiple-events")
@HxTriggerAfterSwap({ "event1", "event2" })
@ResponseBody
public String methodWithHxTriggerAfterSwapAndMultipleEvents() {
return "";
}

@GetMapping("/updates-sidebar")
@HxUpdatesSidebar
@ResponseBody
Expand Down

0 comments on commit 680123c

Please sign in to comment.