diff --git a/build.gradle b/build.gradle index 8268e510..d73bba4f 100644 --- a/build.gradle +++ b/build.gradle @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation platform('run.halo.tools.platform:plugin:2.11.0-SNAPSHOT') + implementation platform('run.halo.tools.platform:plugin:2.17.0-SNAPSHOT') compileOnly 'run.halo.app:api' testImplementation 'run.halo.app:api' diff --git a/src/main/java/run/halo/injection/AbstractHtmlProcessor.java b/src/main/java/run/halo/injection/AbstractHtmlProcessor.java new file mode 100644 index 00000000..7d5dbe7e --- /dev/null +++ b/src/main/java/run/halo/injection/AbstractHtmlProcessor.java @@ -0,0 +1,19 @@ +package run.halo.injection; + +import java.util.Set; +import org.thymeleaf.context.ITemplateContext; + +public abstract class AbstractHtmlProcessor { + + protected static final String TEMPLATE_ID_VARIABLE = "_templateId"; + + protected boolean isContentTemplate(ITemplateContext context) { + return "post".equals(context.getVariable(TEMPLATE_ID_VARIABLE)) + || "page".equals(context.getVariable(TEMPLATE_ID_VARIABLE)); + } + + // 匹配路径接口 + protected boolean isRequestPathMatchingRoute(String requestRoute, Set pageRules) { + return true; + } +} diff --git a/src/main/java/run/halo/injection/HtmlFooterProcessor.java b/src/main/java/run/halo/injection/HtmlFooterProcessor.java new file mode 100644 index 00000000..66346567 --- /dev/null +++ b/src/main/java/run/halo/injection/HtmlFooterProcessor.java @@ -0,0 +1,41 @@ +package run.halo.injection; + + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.thymeleaf.context.ITemplateContext; +import org.thymeleaf.model.IModel; +import org.thymeleaf.model.IProcessableElementTag; +import org.thymeleaf.processor.element.IElementTagStructureHandler; +import reactor.core.publisher.Mono; +import run.halo.app.theme.dialect.TemplateFooterProcessor; + + + +@Slf4j +@Component +@RequiredArgsConstructor +public class HtmlFooterProcessor extends AbstractHtmlProcessor implements TemplateFooterProcessor { + + private final HtmlService htmlService; + + @Override + public Mono process(ITemplateContext context, IProcessableElementTag tag, + IElementTagStructureHandler structureHandler, IModel model) { + return htmlService.getFooterEnabledInjections() + .doOnNext(htmlInjection -> { + if (htmlInjection != null && isContentTemplate(context)) { + model.add( + context.getModelFactory().createText( + htmlInjection.getSpec().getFragment())); + } + }) + .onErrorResume(e -> { + log.error("HtmlFooterProcessor process failed", e); + return Mono.empty(); + }) + .then(); + } + +} diff --git a/src/main/java/run/halo/injection/HtmlHeadProcessor.java b/src/main/java/run/halo/injection/HtmlHeadProcessor.java new file mode 100644 index 00000000..7fec2a50 --- /dev/null +++ b/src/main/java/run/halo/injection/HtmlHeadProcessor.java @@ -0,0 +1,38 @@ +package run.halo.injection; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.thymeleaf.context.ITemplateContext; +import org.thymeleaf.model.IModel; +import org.thymeleaf.processor.element.IElementModelStructureHandler; +import reactor.core.publisher.Mono; +import run.halo.app.theme.dialect.TemplateHeadProcessor; + + +@Slf4j +@Component +@RequiredArgsConstructor +public class HtmlHeadProcessor extends AbstractHtmlProcessor implements TemplateHeadProcessor { + + private final HtmlService htmlService; + + @Override + public Mono process(ITemplateContext context, IModel model, + IElementModelStructureHandler structureHandler) { + return htmlService.getHeadEnabledInjections() + .doOnNext(htmlInjection -> { + if (htmlInjection != null && isContentTemplate(context)) { + model.add( + context.getModelFactory().createText( + htmlInjection.getSpec().getFragment())); + } + }) + .onErrorResume(e -> { + log.error("HtmlHeadProcessor process failed", e); + return Mono.empty(); + }) + .then(); + } + +} diff --git a/src/main/java/run/halo/injection/HtmlService.java b/src/main/java/run/halo/injection/HtmlService.java new file mode 100644 index 00000000..83dd0312 --- /dev/null +++ b/src/main/java/run/halo/injection/HtmlService.java @@ -0,0 +1,46 @@ +package run.halo.injection; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; +import run.halo.app.extension.ListOptions; +import run.halo.app.extension.ReactiveExtensionClient; +import run.halo.app.extension.index.query.QueryFactory; + +@Service +@RequiredArgsConstructor +public class HtmlService { + private final ReactiveExtensionClient client; + + /** + * 获取所有启用的 HtmlInjection 对象. + */ + public Flux getAllEnabledInjections() { + ListOptions options = ListOptions.builder() + // 在这里添加查询条件,只获取正在启用的代码 + .fieldQuery(QueryFactory.equal("spec.enabled", "true")) + .build(); + return client.listAll(HtmlInjection.class, options, + Sort.by(Sort.Order.asc("metadata.name"))); + } + + /** + * 获取启用的注入点为 HEAD 的 HtmlInjection 对象. + */ + public Flux getHeadEnabledInjections() { + return getAllEnabledInjections() + .filter(htmlInjection -> + htmlInjection.getSpec().getInjectionPoint() == HtmlInjection.InjectionPoint.HEADER); + } + + /** + * 获取启用的注入点为 FOOTER 的 HtmlInjection 对象. + */ + public Flux getFooterEnabledInjections() { + return getAllEnabledInjections() + .filter(htmlInjection -> + htmlInjection.getSpec().getInjectionPoint() == HtmlInjection.InjectionPoint.FOOTER); + } +} + diff --git a/src/main/java/run/halo/injection/InjectionPlugin.java b/src/main/java/run/halo/injection/InjectionPlugin.java index 029b35e6..4eb57b07 100644 --- a/src/main/java/run/halo/injection/InjectionPlugin.java +++ b/src/main/java/run/halo/injection/InjectionPlugin.java @@ -1,8 +1,12 @@ package run.halo.injection; + +import static run.halo.app.extension.index.IndexAttributeFactory.simpleAttribute; + import org.springframework.stereotype.Component; import run.halo.app.extension.Scheme; import run.halo.app.extension.SchemeManager; +import run.halo.app.extension.index.IndexSpec; import run.halo.app.plugin.BasePlugin; import run.halo.app.plugin.PluginContext; @@ -18,7 +22,23 @@ public InjectionPlugin(PluginContext pluginContext, SchemeManager schemeManager) @Override public void start() { - schemeManager.register(HtmlInjection.class); + schemeManager.register(HtmlInjection.class, indexSpecs -> { + // 为 enabled 添加索引方便根据启用状态查询 + indexSpecs.add(new IndexSpec() + .setName("spec.enabled") + .setIndexFunc(simpleAttribute(HtmlInjection.class, htmlInjection -> { + return Boolean.toString(htmlInjection.getSpec().isEnabled()); + })) + ); + // 为 injectionPoint 添加索引 + indexSpecs.add(new IndexSpec() + .setName("spec.injectionPoint") + .setIndexFunc(simpleAttribute(HtmlInjection.class, htmlInjection -> { + HtmlInjection.InjectionPoint injectionPoint = htmlInjection.getSpec().getInjectionPoint(); + return injectionPoint != null ? injectionPoint.name() : ""; + })) + ); + }); } @Override