Skip to content

Commit a4de3ba

Browse files
authored
htmx: Initial add of htmx-api, htmx-nima request support and initial example (#435)
* htmx: Initial add of htmx-api, htmx-nima request support and initial example * Bump parent version * Bump parent version * Conditionally build htmx-nima JDK 21+ * Add TemplateRender interface * Add Jscahe TemplateRender for @HTMX * Javadoc, tests pom fix * Bump version * Bump version * Bump htmlx versions to 2.7
1 parent f051caf commit a4de3ba

File tree

41 files changed

+1067
-19
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1067
-19
lines changed

htmx-api/pom.xml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>io.avaje</groupId>
8+
<artifactId>avaje-http-parent</artifactId>
9+
<version>2.7</version>
10+
</parent>
11+
12+
<artifactId>avaje-htmx-api</artifactId>
13+
14+
<properties>
15+
</properties>
16+
17+
<dependencies>
18+
<dependency>
19+
<groupId>io.avaje</groupId>
20+
<artifactId>avaje-lang</artifactId>
21+
<version>1.0</version>
22+
</dependency>
23+
</dependencies>
24+
25+
</project>
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package io.avaje.htmx.api;
2+
3+
import io.avaje.lang.Nullable;
4+
5+
final class DHxRequest implements HtmxRequest {
6+
7+
private final boolean htmxRequest;
8+
9+
private final boolean boosted;
10+
private final String currentUrl;
11+
private final boolean historyRestoreRequest;
12+
private final String promptResponse;
13+
private final String target;
14+
private final String triggerName;
15+
private final String triggerId;
16+
17+
DHxRequest() {
18+
this.htmxRequest = false;
19+
this.boosted = false;
20+
this.currentUrl = null;
21+
this.historyRestoreRequest = false;
22+
this.promptResponse = null;
23+
this.target = null;
24+
this.triggerName = null;
25+
this.triggerId = null;
26+
}
27+
28+
DHxRequest(boolean boosted, String currentUrl, boolean historyRestoreRequest, String promptResponse, String target, String triggerName, String triggerId) {
29+
this.htmxRequest = true;
30+
this.boosted = boosted;
31+
this.currentUrl = currentUrl;
32+
this.historyRestoreRequest = historyRestoreRequest;
33+
this.promptResponse = promptResponse;
34+
this.target = target;
35+
this.triggerName = triggerName;
36+
this.triggerId = triggerId;
37+
}
38+
39+
@Override
40+
public boolean isHtmxRequest() {
41+
return htmxRequest;
42+
}
43+
44+
@Override
45+
public boolean isBoosted() {
46+
return boosted;
47+
}
48+
49+
@Nullable
50+
@Override
51+
public String currentUrl() {
52+
return currentUrl;
53+
}
54+
55+
@Override
56+
public boolean isHistoryRestoreRequest() {
57+
return historyRestoreRequest;
58+
}
59+
60+
@Nullable
61+
@Override
62+
public String promptResponse() {
63+
return promptResponse;
64+
}
65+
66+
@Nullable
67+
@Override
68+
public String target() {
69+
return target;
70+
}
71+
72+
@Nullable
73+
@Override
74+
public String triggerName() {
75+
return triggerName;
76+
}
77+
78+
@Nullable
79+
public String triggerId() {
80+
return triggerId;
81+
}
82+
83+
static final class DBuilder implements Builder {
84+
85+
private boolean boosted;
86+
private String currentUrl;
87+
private boolean historyRestoreRequest;
88+
private String promptResponse;
89+
private String target;
90+
private String triggerName;
91+
private String triggerId;
92+
93+
@Override
94+
public DBuilder boosted(boolean boosted) {
95+
this.boosted = boosted;
96+
return this;
97+
}
98+
99+
@Override
100+
public DBuilder currentUrl(String currentUrl) {
101+
this.currentUrl = currentUrl;
102+
return this;
103+
}
104+
105+
@Override
106+
public DBuilder historyRestoreRequest(boolean historyRestoreRequest) {
107+
this.historyRestoreRequest = historyRestoreRequest;
108+
return this;
109+
}
110+
111+
@Override
112+
public DBuilder promptResponse(String promptResponse) {
113+
this.promptResponse = promptResponse;
114+
return this;
115+
}
116+
117+
@Override
118+
public DBuilder target(String target) {
119+
this.target = target;
120+
return this;
121+
}
122+
123+
@Override
124+
public DBuilder triggerName(String triggerName) {
125+
this.triggerName = triggerName;
126+
return this;
127+
}
128+
129+
@Override
130+
public DBuilder triggerId(String triggerId) {
131+
this.triggerId = triggerId;
132+
return this;
133+
}
134+
135+
@Override
136+
public HtmxRequest build() {
137+
return new DHxRequest(boosted, currentUrl, historyRestoreRequest, promptResponse, target, triggerName, triggerId);
138+
}
139+
}
140+
141+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.avaje.htmx.api;
2+
3+
import java.lang.annotation.Retention;
4+
import java.lang.annotation.Target;
5+
6+
import static java.lang.annotation.ElementType.TYPE;
7+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
8+
9+
/**
10+
* Mark a controller as producing HTML by default and using "Templating"
11+
* meaning that response objects are expected to a "Model View" passed to
12+
* the "Templating" library.
13+
*/
14+
@Target(TYPE)
15+
@Retention(RUNTIME)
16+
public @interface Html {
17+
18+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package io.avaje.htmx.api;
2+
3+
import io.avaje.lang.Nullable;
4+
5+
/**
6+
* This class can be used as a controller method argument to access
7+
* the <a href="https://htmx.org/reference/#request_headers">htmx Request Headers</a>.
8+
*
9+
* <pre>{@code
10+
*
11+
* @HxRequest
12+
* @Get("/users")
13+
* String users(HtmxRequest htmxRequest) {
14+
* if (htmxRequest.isBoosted()) {
15+
* ...
16+
* }
17+
* }
18+
*
19+
* }</pre>
20+
*
21+
* @see <a href="https://htmx.org/reference/#request_headers">Request Headers Reference</a>
22+
*/
23+
public interface HtmxRequest {
24+
25+
/**
26+
* Represents a non-Htmx request.
27+
*/
28+
HtmxRequest EMPTY = new DHxRequest();
29+
30+
/**
31+
* Return a new builder for the HtmxRequest.
32+
*/
33+
static Builder builder() {
34+
return new DHxRequest.DBuilder();
35+
}
36+
37+
/**
38+
* Return true if this is an Htmx request.
39+
*/
40+
boolean isHtmxRequest();
41+
42+
/**
43+
* Indicates that the request is via an element using hx-boost.
44+
*
45+
* @return true if the request was made via HX-Boost, false otherwise
46+
*/
47+
boolean isBoosted();
48+
49+
/**
50+
* Return the current URL of the browser when the htmx request was made.
51+
*/
52+
@Nullable
53+
String currentUrl();
54+
55+
/**
56+
* Indicates if the request is for history restoration after a miss in the local history cache
57+
*
58+
* @return true if this request is for history restoration, false otherwise
59+
*/
60+
boolean isHistoryRestoreRequest();
61+
62+
/**
63+
* Return the user response to an HX-Prompt.
64+
*/
65+
@Nullable
66+
String promptResponse();
67+
68+
/**
69+
* Return the id of the target element if it exists.
70+
*/
71+
@Nullable
72+
String target();
73+
74+
/**
75+
* Return the name of the triggered element if it exists.
76+
*/
77+
@Nullable
78+
String triggerName();
79+
80+
/**
81+
* Return the id of the triggered element if it exists.
82+
*/
83+
@Nullable
84+
String triggerId();
85+
86+
/**
87+
* Builder for {@link HtmxRequest}.
88+
*/
89+
interface Builder {
90+
Builder boosted(boolean boosted);
91+
92+
Builder currentUrl(String currentUrl);
93+
94+
Builder historyRestoreRequest(boolean historyRestoreRequest);
95+
96+
Builder promptResponse(String promptResponse);
97+
98+
Builder target(String target);
99+
100+
Builder triggerName(String triggerName);
101+
102+
Builder triggerId(String triggerId);
103+
104+
HtmxRequest build();
105+
}
106+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package io.avaje.htmx.api;
2+
3+
import java.lang.annotation.Retention;
4+
import java.lang.annotation.Target;
5+
6+
import static java.lang.annotation.ElementType.METHOD;
7+
import static java.lang.annotation.ElementType.TYPE;
8+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
9+
10+
/**
11+
* Mark a controller method as handling Htmx requests and potentially restrict
12+
* the handler to only be used for specific Htmx target or Htmx trigger.
13+
* <p>
14+
* Controller methods with {@code @HxRequest} require the {@code HX-Request}
15+
* HTTP Header to be set for the handler to process the request. Additionally,
16+
* we can specify {@link #target()}, {@link #triggerId()}, or {@link #triggerName()}
17+
* such that the handler is only invoked specifically for requests with those
18+
* matching headers.
19+
*/
20+
@Target({TYPE, METHOD})
21+
@Retention(RUNTIME)
22+
public @interface HxRequest {
23+
24+
/**
25+
* Restricts the mapping to the {@code id} of a specific target element.
26+
*
27+
* @see <a href="https://htmx.org/reference/#request_headers">HX-Target</a>
28+
*/
29+
String target() default "";
30+
31+
/**
32+
* Restricts the mapping to the {@code id} of a specific triggered element.
33+
*
34+
* @see <a href="https://htmx.org/reference/#request_headers">HX-Trigger</a>
35+
*/
36+
String triggerId() default "";
37+
38+
/**
39+
* Restricts the mapping to the {@code name} of a specific triggered element.
40+
*
41+
* @see <a href="https://htmx.org/reference/#request_headers">HX-Trigger-Name</a>
42+
*/
43+
String triggerName() default "";
44+
45+
/**
46+
* Restricts the mapping to the {@code id}, if any, or to the {@code name} of a specific triggered element.
47+
* <p>
48+
* If you want to be explicit use {@link #triggerId()} or {@link #triggerName()}.
49+
*
50+
* @see <a href="https://htmx.org/reference/#request_headers">HX-Trigger</a>
51+
* @see <a href="https://htmx.org/reference/#request_headers">HX-Trigger-Name</a>
52+
*/
53+
String value() default "";
54+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module io.avaje.htmx.api {
2+
3+
exports io.avaje.htmx.api;
4+
5+
requires static io.avaje.lang;
6+
}

0 commit comments

Comments
 (0)