Skip to content

Commit

Permalink
Remove unnecessary whitespace from HTML output
Browse files Browse the repository at this point in the history
  • Loading branch information
perdian committed Feb 6, 2024
1 parent 38e60e1 commit e9571df
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package de.perdian.flightlog.support.thymeleaf;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.thymeleaf.dialect.IPostProcessorDialect;
import org.thymeleaf.engine.AbstractTemplateHandler;
import org.thymeleaf.model.ICloseElementTag;
import org.thymeleaf.model.IOpenElementTag;
import org.thymeleaf.model.IText;
import org.thymeleaf.postprocessor.IPostProcessor;
import org.thymeleaf.postprocessor.PostProcessor;
import org.thymeleaf.templatemode.TemplateMode;

import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

@Component
public class FlightlogThymeleafDialect implements IPostProcessorDialect {

@Override
public int getDialectPostProcessorPrecedence() {
return 0;
}

@Override
public String getName() {
return "flightlog";
}

@Override
public Set<IPostProcessor> getPostProcessors() {
return Set.of(
new PostProcessor(TemplateMode.HTML, RemoveWhitespacesTemplateHandler.class, 0)
);
}

public static class RemoveWhitespacesTemplateHandler extends AbstractTemplateHandler {

private List<ElementInfo> elementStack = new LinkedList<>();
private List<String> ignoreElementNames = List.of("html", "head", "body", "span", "pre");
private List<String> trimElementNames = List.of("a", "button");

@Override
public void handleOpenElement(IOpenElementTag openElementTag) {
ElementInfo newElementInfo = new ElementInfo(openElementTag.getElementDefinition().getElementName().getElementName().toLowerCase());
ElementInfo currentElementInfo = this.getElementStack().isEmpty() ? null : this.getElementStack().getLast();
if (currentElementInfo != null) {
currentElementInfo.addChild(newElementInfo);
}
this.getElementStack().addLast(newElementInfo);
super.handleOpenElement(openElementTag);
}

@Override
public void handleCloseElement(ICloseElementTag closeElementTag) {
if (!this.getElementStack().isEmpty()) {
this.getElementStack().removeLast();
}
super.handleCloseElement(closeElementTag);
}

@Override
public void handleText(IText text) {
ElementInfo currentElementInfo = this.getElementStack().isEmpty() ? null : this.getElementStack().getLast();
if (currentElementInfo == null || this.getIgnoreElementNames().contains(currentElementInfo.getElementName())) {
super.handleText(text);
} else {
String currentTextValue = text.getText();
if (StringUtils.isBlank(currentTextValue)) {
// Ignore
} else {
String reducedTextValue = this.reduceString(currentTextValue, currentElementInfo);
if (!Objects.equals(currentTextValue, reducedTextValue)) {
super.handleText(this.getContext().getModelFactory().createText(reducedTextValue));
} else {
super.handleText(text);
}
}
}
}

private String reduceString(String inputString, ElementInfo elementInfo) {
if (this.getTrimElementNames().contains(elementInfo.getElementName())) {
if (!elementInfo.getChildren().isEmpty()) {
return inputString;
} else {
return inputString.strip();
}
} else {
return inputString;
}
}

List<ElementInfo> getElementStack() {
return this.elementStack;
}
void setElementStack(List<ElementInfo> elementStack) {
this.elementStack = elementStack;
}

List<String> getIgnoreElementNames() {
return this.ignoreElementNames;
}
void setIgnoreElementNames(List<String> ignoreElementNames) {
this.ignoreElementNames = ignoreElementNames;
}

List<String> getTrimElementNames() {
return this.trimElementNames;
}
void setTrimElementNames(List<String> trimElementNames) {
this.trimElementNames = trimElementNames;
}

static class ElementInfo {

private String elementName = null;
private boolean nonWhitespaceTextAdded = false;
private List<ElementInfo> children = new LinkedList<>();

private ElementInfo(String elementName) {
this.setElementName(elementName);
}

@Override
public String toString() {
return this.getElementName();
}

String getElementName() {
return this.elementName;
}
private void setElementName(String elementName) {
this.elementName = elementName;
}

boolean isNonWhitespaceTextAdded() {
return this.nonWhitespaceTextAdded;
}
void setNonWhitespaceTextAdded(boolean nonWhitespaceTextAdded) {
this.nonWhitespaceTextAdded = nonWhitespaceTextAdded;
}

void addChild(ElementInfo child) {
this.getChildren().add(child);
}
List<ElementInfo> getChildren() {
return this.children;
}
void setChildren(List<ElementInfo> children) {
this.children = children;
}

}

}

}
24 changes: 18 additions & 6 deletions src/main/resources/templates/flights/include/list-flights.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
</div>
<div>
<strong><span th:text="${flight.departureContact.airport.code}">XXX</span></strong>
<i class="flag" th:classappend="${#strings.toLowerCase(flight.departureContact.airport.countryCode)}"></i>
<span>
<i class="flag" th:classappend="${#strings.toLowerCase(flight.departureContact.airport.countryCode)}"></i>
</span>
</div>
<div class="smalltext" th:text="${flight.departureContact.airport.name}">Airport name</div>
</div>
Expand All @@ -43,7 +45,9 @@
</div>
<div>
<strong><span th:text="${flight.arrivalContact.airport.code}">XXX</span></strong>
<i class="flag" th:classappend="${#strings.toLowerCase(flight.arrivalContact.airport.countryCode)}"></i>
<span>
<i class="flag" th:classappend="${#strings.toLowerCase(flight.arrivalContact.airport.countryCode)}"></i>
</span>
</div>
<div class="smalltext" th:text="${flight.arrivalContact.airport.name}">Airport name</div>
</div>
Expand Down Expand Up @@ -116,9 +120,13 @@
<span th:text="${#temporals.format(flight.departureContact.timeLocal, 'HH:mm')}"></span>
&nbsp;
<strong><span th:text="${flight.departureContact.airport.code}">XXX</span></strong>
<i class="mobile hidden flag" th:classappend="${#strings.toLowerCase(flight.departureContact.airport.countryCode)}"></i>
<span class="mobile hidden">
<i class="flag" th:classappend="${#strings.toLowerCase(flight.departureContact.airport.countryCode)}"></i>
</span>
<div class="smalltext">
<i class="mobile only flag" th:classappend="${#strings.toLowerCase(flight.departureContact.airport.countryCode)}"></i>
<span class="mobile only">
<i class="flag" th:classappend="${#strings.toLowerCase(flight.departureContact.airport.countryCode)}"></i>
</span>
<span th:text="${flight.departureContact.airport.name}"></span>
</div>
</div>
Expand All @@ -130,9 +138,13 @@
</span>
&nbsp;
<strong><span th:text="${flight.arrivalContact.airport.code}">XXX</span></strong>
<i class="mobile hidden flag" th:classappend="${#strings.toLowerCase(flight.arrivalContact.airport.countryCode)}"></i>
<span class="mobile hidden">
<i class="flag" th:classappend="${#strings.toLowerCase(flight.arrivalContact.airport.countryCode)}"></i>
</span>
<div class="smalltext">
<i class="mobile only flag" th:classappend="${#strings.toLowerCase(flight.arrivalContact.airport.countryCode)}"></i>
<span class="mobile only">
<i class="flag" th:classappend="${#strings.toLowerCase(flight.arrivalContact.airport.countryCode)}"></i>
</span>
<span th:text="${flight.arrivalContact.airport.name}"></span>
<span th:if="${flight.arrivalContact.dateOffset}" class="mobile only">
(<span th:text="${flight.arrivalContact.dateOffset}">+0</span>)
Expand Down
4 changes: 3 additions & 1 deletion src/main/resources/templates/overview/statistics.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ <h3 th:text="${#strings.isEmpty(group.title.key) ? group.title.value : #messages
<td width="15" class="right aligned" th:text="${groupItemStatus.index + 1}" th:if="${includeIndex}">X</td>
<td>
<div>
<i th:if="${not #strings.isEmpty(groupItem.iconCode)}" class="flag" th:classappend="${groupItem.iconCode}"></i>
<span th:if="${not #strings.isEmpty(groupItem.iconCode)}">
<i class="flag" th:classappend="${groupItem.iconCode}"></i>
</span>
<span th:classappend="${titleCssClass}" th:text="${#strings.isEmpty(groupItem.title.key) ? groupItem.title.value : #messages.msg(groupItem.title.key)}">Title</span>
</div>
<div class="smalltext" th:if="${descriptionPosition == 'inline' && not #strings.isEmpty(groupItem.description)}" th:text="${#strings.isEmpty(groupItem.description.key) ? groupItem.description.value : #messages.msg(groupItem.description.key)}">Description</div>
Expand Down

0 comments on commit e9571df

Please sign in to comment.