Skip to content

Commit

Permalink
Addressed #27 adding support for maps the be serialized as json
Browse files Browse the repository at this point in the history
  • Loading branch information
checketts committed Oct 26, 2022
1 parent dc45d51 commit a468cb2
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 34 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package io.github.wimdeblauwe.hsbt.thymeleaf;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.thymeleaf.context.ITemplateContext;
import org.thymeleaf.engine.AttributeDefinition;
import org.thymeleaf.engine.AttributeDefinitions;
import org.thymeleaf.engine.AttributeName;
import org.thymeleaf.engine.IAttributeDefinitionsAware;
import org.thymeleaf.exceptions.TemplateProcessingException;
import org.thymeleaf.model.IProcessableElementTag;
import org.thymeleaf.processor.element.IElementTagStructureHandler;
import org.thymeleaf.spring5.requestdata.RequestDataValueProcessorUtils;
Expand All @@ -14,22 +17,25 @@
import org.thymeleaf.util.Validate;
import org.unbescape.html.HtmlEscape;

import java.util.LinkedHashMap;

public class HtmxAttributeProcessor extends AbstractStandardExpressionAttributeTagProcessor
implements IAttributeDefinitionsAware {


public static final int ATTR_PRECEDENCE = 1000;
private final String attrName;
private final ObjectMapper mapper;

private static final TemplateMode TEMPLATE_MODE = TemplateMode.HTML;

private AttributeDefinition targetAttributeDefinition;


public HtmxAttributeProcessor(final String dialectPrefix,
String attrName) {
String attrName, ObjectMapper mapper) {
super(TEMPLATE_MODE, dialectPrefix, attrName, ATTR_PRECEDENCE, false, true);
this.attrName = attrName;
this.mapper = mapper;
}


Expand All @@ -52,7 +58,18 @@ protected final void doProcess(
if (expressionResult == null) {
structureHandler.removeAttribute(attributeName);
} else {
String newAttributeValue = HtmlEscape.escapeHtml4Xml(expressionResult.toString());
String expressionResultString;
if (expressionResult instanceof LinkedHashMap) {
try {
expressionResultString = this.mapper.writeValueAsString(expressionResult);
} catch (JsonProcessingException e) {
throw new TemplateProcessingException("Exception writing map", tag.getTemplateName() ,tag.getLine(), tag.getLine(), e);
}
} else {
expressionResultString = expressionResult.toString();
}

String newAttributeValue = HtmlEscape.escapeHtml4Xml(expressionResultString);

// Let RequestDataValueProcessor modify the attribute value if needed
newAttributeValue = RequestDataValueProcessorUtils.processUrl(context, newAttributeValue);
Expand Down
62 changes: 33 additions & 29 deletions src/main/java/io/github/wimdeblauwe/hsbt/thymeleaf/HtmxDialect.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.wimdeblauwe.hsbt.thymeleaf;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.thymeleaf.dialect.AbstractProcessorDialect;
import org.thymeleaf.processor.IProcessor;

Expand All @@ -8,42 +9,45 @@

public class HtmxDialect extends AbstractProcessorDialect {

public HtmxDialect() {
private final ObjectMapper mapper;

public HtmxDialect(ObjectMapper mapper) {
super("Htmx", "hx", 1000);
this.mapper = mapper;
}

@Override
public Set<IProcessor> getProcessors(String dialectPrefix) {
Set<IProcessor> htmxProcessors = new HashSet<>();

htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "boost"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "confirm"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "delete"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "disable"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "disinherit"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "encoding"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "ext"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "get"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "headers"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "history-elt"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "include"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "indicator"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "params"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "patch"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "post"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "preserve"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "prompt"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "put"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "push-url"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "request"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "select"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "swap"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "swap-oob"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "sync"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "target"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "trigger"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "vals"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "vars"));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "boost", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "confirm", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "delete", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "disable", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "disinherit", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "encoding", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "ext", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "get", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "headers", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "history-elt", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "include", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "indicator", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "params", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "patch", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "post", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "preserve", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "prompt", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "put", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "push-url", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "request", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "select", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "swap", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "swap-oob", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "sync", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "target", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "trigger", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "vals", mapper));
htmxProcessors.add(new HtmxAttributeProcessor(dialectPrefix, "vars", mapper));

return htmxProcessors;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.wimdeblauwe.hsbt.thymeleaf;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand All @@ -8,7 +9,7 @@
@ConditionalOnWebApplication
public class HtmxThymeleafConfiguration {
@Bean
public HtmxDialect htmxDialect() {
return new HtmxDialect();
public HtmxDialect htmxDialect(ObjectMapper mapper) {
return new HtmxDialect(mapper);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,14 @@ void testWithThEach() throws Exception {
.containsPattern("hx-target-div-with-th-each.*hx-target=\"2\"")
.containsPattern("hx-target-div-with-th-each.*hx-target=\"3\"");
}

@Test
void testWithHxVals() throws Exception {
String html = mockMvc.perform(get("/htmx-dialect"))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString();
//noinspection RegExpSimplifiable
assertThat(html)
.containsPattern("hx-vals=\"[{][&]quot;trueVariable&quot;:true}\"");
}
}
1 change: 1 addition & 0 deletions src/test/resources/templates/htmx-dialect-test.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<div id="hx-target-div" hx:target="${trueVariable}?'#some-div':'#some-other-div'"></div>
<div id="hx-trigger-div" hx:trigger="${trueVariable}?'reveal':''"></div>
<div id="hx-swap-div" hx:swap="${trueVariable}?'outerHTML':''"></div>
<div id="hx-vals-div" hx:vals="${ {trueVariable: trueVariable} }"></div>
<div id="hx-swap-div-with-empty-string" hx:swap="${falseVariable}?'afterend':''"></div>
<div id="hx-swap-div-with-null" hx:swap="${falseVariable}?'afterend':null"></div>
<div id="hx-swap-div-with-th-with" th:with="sum = ${1+1}" hx:swap="${sum.equals(2)}?'afterend':null"></div>
Expand Down

0 comments on commit a468cb2

Please sign in to comment.