mirror of https://github.com/halo-dev/halo
feat: add theme link expression dialect (#2438)
#### What type of PR is this? /kind feature /milestone 2.0 /area core #### What this PR does / why we need it: 允许主题模板在 HTML 或 JavaScript 片段中使用表达式对象获得链接: - `${#theme.assets('/js/main.js'))}` - `${#theme.route('/categories')}` #### Which issue(s) this PR fixes: Fixes #2435 #### Special notes for your reviewer: /cc @halo-dev/sig-halo #### Does this PR introduce a user-facing change? ```release-note None ```pull/2460/head
parent
d40626b07b
commit
f0892b2f4d
|
@ -14,6 +14,7 @@ import org.springframework.web.reactive.function.server.ServerResponse;
|
|||
import org.thymeleaf.extras.java8time.dialect.Java8TimeDialect;
|
||||
import run.halo.app.infra.properties.HaloProperties;
|
||||
import run.halo.app.infra.utils.FilePathUtils;
|
||||
import run.halo.app.theme.dialect.LinkExpressionObjectDialect;
|
||||
import run.halo.app.theme.dialect.ThemeJava8TimeDialect;
|
||||
|
||||
/**
|
||||
|
@ -52,4 +53,9 @@ public class ThemeConfiguration {
|
|||
Java8TimeDialect java8TimeDialect() {
|
||||
return new ThemeJava8TimeDialect();
|
||||
}
|
||||
|
||||
@Bean
|
||||
LinkExpressionObjectDialect linkExpressionObjectDialect() {
|
||||
return new LinkExpressionObjectDialect();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ import run.halo.app.infra.utils.PathUtils;
|
|||
* @since 2.0.0
|
||||
*/
|
||||
public class ThemeLinkBuilder extends StandardLinkBuilder {
|
||||
private static final String THEME_ASSETS_PREFIX = "/assets";
|
||||
private static final String THEME_PREVIEW_PREFIX = "/themes";
|
||||
public static final String THEME_ASSETS_PREFIX = "/assets";
|
||||
public static final String THEME_PREVIEW_PREFIX = "/themes";
|
||||
|
||||
private final ThemeContext theme;
|
||||
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
package run.halo.app.theme.dialect;
|
||||
|
||||
import java.util.Set;
|
||||
import org.thymeleaf.context.IExpressionContext;
|
||||
import org.thymeleaf.exceptions.TemplateProcessingException;
|
||||
import org.thymeleaf.expression.IExpressionObjectFactory;
|
||||
import org.thymeleaf.linkbuilder.ILinkBuilder;
|
||||
import org.thymeleaf.util.Validate;
|
||||
import run.halo.app.theme.ThemeLinkBuilder;
|
||||
|
||||
/**
|
||||
* A default implementation of {@link IExpressionObjectFactory}.
|
||||
*
|
||||
* @author guqing
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class DefaultLinkExpressionFactory implements IExpressionObjectFactory {
|
||||
private static final String THEME_EVALUATION_VARIABLE_NAME = "theme";
|
||||
|
||||
@Override
|
||||
public Set<String> getAllExpressionObjectNames() {
|
||||
return Set.of(THEME_EVALUATION_VARIABLE_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object buildObject(IExpressionContext context, String expressionObjectName) {
|
||||
if (THEME_EVALUATION_VARIABLE_NAME.equals(expressionObjectName)) {
|
||||
return new ThemeLinkExpressObject(context);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCacheable(String expressionObjectName) {
|
||||
return THEME_EVALUATION_VARIABLE_NAME.equals(expressionObjectName);
|
||||
}
|
||||
|
||||
public static class ThemeLinkExpressObject {
|
||||
private final ILinkBuilder linkBuilder;
|
||||
private final IExpressionContext context;
|
||||
|
||||
/**
|
||||
* Construct an expression object that provides a set of methods to handle link in
|
||||
* Javascript or HTML through {@link IExpressionContext}.
|
||||
*
|
||||
* @param context expression context
|
||||
*/
|
||||
public ThemeLinkExpressObject(IExpressionContext context) {
|
||||
Validate.notNull(context, "Context cannot be null");
|
||||
this.context = context;
|
||||
Set<ILinkBuilder> linkBuilders = context.getConfiguration().getLinkBuilders();
|
||||
linkBuilder = linkBuilders.stream()
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new TemplateProcessingException("Link builder not found"));
|
||||
}
|
||||
|
||||
public String assets(String path) {
|
||||
String assetsPath = ThemeLinkBuilder.THEME_ASSETS_PREFIX + path;
|
||||
return linkBuilder.buildLink(context, assetsPath, null);
|
||||
}
|
||||
|
||||
public String route(String path) {
|
||||
return linkBuilder.buildLink(context, path, null);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package run.halo.app.theme.dialect;
|
||||
|
||||
import org.thymeleaf.dialect.AbstractDialect;
|
||||
import org.thymeleaf.dialect.IExpressionObjectDialect;
|
||||
import org.thymeleaf.expression.IExpressionObjectFactory;
|
||||
|
||||
/**
|
||||
* An expression object dialect for theme link.
|
||||
*
|
||||
* @author guqing
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class LinkExpressionObjectDialect extends AbstractDialect implements
|
||||
IExpressionObjectDialect {
|
||||
|
||||
private static final IExpressionObjectFactory LINK_EXPRESSION_OBJECTS_FACTORY =
|
||||
new DefaultLinkExpressionFactory();
|
||||
|
||||
public LinkExpressionObjectDialect() {
|
||||
super("themeLink");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IExpressionObjectFactory getExpressionObjectFactory() {
|
||||
return LINK_EXPRESSION_OBJECTS_FACTORY;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package run.halo.app.theme.dialect;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link LinkExpressionObjectDialect}.
|
||||
*
|
||||
* @author guqing
|
||||
* @since 2.0.0
|
||||
*/
|
||||
class LinkExpressionObjectDialectTest {
|
||||
|
||||
private final LinkExpressionObjectDialect linkExpressionObjectDialect =
|
||||
new LinkExpressionObjectDialect();
|
||||
|
||||
@Test
|
||||
void getExpressionObjectFactory() {
|
||||
assertThat(linkExpressionObjectDialect.getName())
|
||||
.isEqualTo("themeLink");
|
||||
assertThat(linkExpressionObjectDialect.getExpressionObjectFactory())
|
||||
.isInstanceOf(DefaultLinkExpressionFactory.class);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue