mirror of
https://github.com/HangarMC/Hangar.git
synced 2024-11-27 06:01:08 +08:00
initial markdown support
This commit is contained in:
parent
117448a78a
commit
a3c2236b0d
7
pom.xml
7
pom.xml
@ -116,6 +116,13 @@
|
||||
<artifactId>postgresql</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- markdown -->
|
||||
<dependency>
|
||||
<groupId>com.vladsch.flexmark</groupId>
|
||||
<artifactId>flexmark-all</artifactId>
|
||||
<version>0.62.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- webjars -->
|
||||
<dependency>
|
||||
<groupId>org.webjars</groupId>
|
||||
|
@ -10,6 +10,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import me.minidigger.hangar.config.HangarConfig;
|
||||
import me.minidigger.hangar.service.MarkdownService;
|
||||
import me.minidigger.hangar.service.UserService;
|
||||
import me.minidigger.hangar.util.RouteHelper;
|
||||
import me.minidigger.hangar.util.TemplateHelper;
|
||||
@ -24,6 +25,8 @@ public abstract class HangarController {
|
||||
private TemplateHelper templateHelper;
|
||||
@Autowired
|
||||
private HangarConfig hangarConfig;
|
||||
@Autowired
|
||||
private MarkdownService markdownService;
|
||||
|
||||
protected ModelAndView fillModel(ModelAndView mav) {
|
||||
// helpers
|
||||
@ -34,6 +37,7 @@ public abstract class HangarController {
|
||||
builder.setUseModelCache(true);
|
||||
mav.addObject("@helper", builder.build().getStaticModels());
|
||||
mav.addObject("config", hangarConfig);
|
||||
mav.addObject("markdownService", markdownService);
|
||||
|
||||
// alerts
|
||||
if (mav.getModelMap().getAttribute("alerts") == null) {
|
||||
|
@ -36,11 +36,6 @@ public class ProjectPagesTable {
|
||||
return slug;
|
||||
}
|
||||
|
||||
public String html(ProjectsTable project) {
|
||||
// TODO markdown renderer
|
||||
return contents;
|
||||
}
|
||||
|
||||
public boolean isHome() {
|
||||
return name.equals("Home") && parentId == null;
|
||||
}
|
||||
|
132
src/main/java/me/minidigger/hangar/service/MarkdownService.java
Normal file
132
src/main/java/me/minidigger/hangar/service/MarkdownService.java
Normal file
@ -0,0 +1,132 @@
|
||||
package me.minidigger.hangar.service;
|
||||
|
||||
import com.vladsch.flexmark.ast.MailLink;
|
||||
import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension;
|
||||
import com.vladsch.flexmark.ext.autolink.AutolinkExtension;
|
||||
import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension;
|
||||
import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension;
|
||||
import com.vladsch.flexmark.ext.tables.TablesExtension;
|
||||
import com.vladsch.flexmark.ext.typographic.TypographicExtension;
|
||||
import com.vladsch.flexmark.ext.wikilink.WikiLinkExtension;
|
||||
import com.vladsch.flexmark.html.HtmlRenderer;
|
||||
import com.vladsch.flexmark.html.LinkResolver;
|
||||
import com.vladsch.flexmark.html.renderer.LinkResolverBasicContext;
|
||||
import com.vladsch.flexmark.html.renderer.LinkStatus;
|
||||
import com.vladsch.flexmark.html.renderer.LinkType;
|
||||
import com.vladsch.flexmark.html.renderer.ResolvedLink;
|
||||
import com.vladsch.flexmark.parser.Parser;
|
||||
import com.vladsch.flexmark.util.ast.Node;
|
||||
import com.vladsch.flexmark.util.data.MutableDataSet;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Arrays;
|
||||
|
||||
@Service
|
||||
public class MarkdownService {
|
||||
|
||||
private final Parser markdownParser;
|
||||
private final MutableDataSet options;
|
||||
|
||||
public MarkdownService() {
|
||||
options = new MutableDataSet()
|
||||
.set(HtmlRenderer.SUPPRESS_HTML, true)
|
||||
.set(AnchorLinkExtension.ANCHORLINKS_TEXT_PREFIX, "<i class=\"fas fa-link\"></i>")
|
||||
.set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "headeranchor")
|
||||
.set(AnchorLinkExtension.ANCHORLINKS_WRAP_TEXT, false)
|
||||
// GFM table compatibility
|
||||
.set(TablesExtension.COLUMN_SPANS, false)
|
||||
.set(TablesExtension.APPEND_MISSING_COLUMNS, true)
|
||||
.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true)
|
||||
.set(TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH, true)
|
||||
.set(
|
||||
Parser.EXTENSIONS,
|
||||
Arrays.asList(
|
||||
AutolinkExtension.create(),
|
||||
AnchorLinkExtension.create(),
|
||||
StrikethroughExtension.create(),
|
||||
TaskListExtension.create(),
|
||||
TablesExtension.create(),
|
||||
TypographicExtension.create(),
|
||||
WikiLinkExtension.create()
|
||||
)
|
||||
);
|
||||
|
||||
markdownParser = Parser.builder(options).build();
|
||||
}
|
||||
|
||||
public String render(String input) {
|
||||
return this.render(input, RenderSettings.defaultSettings);
|
||||
}
|
||||
|
||||
public String render(String input, RenderSettings settings) {
|
||||
MutableDataSet options = new MutableDataSet(this.options);
|
||||
|
||||
if (settings.linkEscapeChars != null) {
|
||||
options.set(WikiLinkExtension.LINK_ESCAPE_CHARS, settings.linkEscapeChars);
|
||||
}
|
||||
if (settings.linkPrefix != null) {
|
||||
options.set(WikiLinkExtension.LINK_PREFIX, settings.linkPrefix);
|
||||
}
|
||||
|
||||
HtmlRenderer htmlRenderer = HtmlRenderer
|
||||
.builder(options)
|
||||
// .linkResolverFactory(new ExternalLinkResolver())
|
||||
.build();
|
||||
|
||||
return htmlRenderer.render(markdownParser.parse(input));
|
||||
}
|
||||
|
||||
static class RenderSettings {
|
||||
private String linkEscapeChars;
|
||||
private String linkPrefix;
|
||||
|
||||
public static final RenderSettings defaultSettings = new RenderSettings(null, null);
|
||||
|
||||
public RenderSettings(String linkEscapeChars, String linkPrefix) {
|
||||
this.linkEscapeChars = linkEscapeChars;
|
||||
this.linkPrefix = linkPrefix;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO external links for markdown shit
|
||||
// static class ExternalLinkResolver implements LinkResolver {
|
||||
//
|
||||
// @Override
|
||||
// public @NotNull ResolvedLink resolveLink(@NotNull Node node, @NotNull LinkResolverBasicContext context, @NotNull ResolvedLink link) {
|
||||
// if (link.getLinkType() == LinkType.IMAGE || node instanceof MailLink) {
|
||||
// return link;
|
||||
// } else {
|
||||
// return link.withStatus(LinkStatus.VALID).withUrl(wrapExternal(link.getUrl()));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private String wrapExternal(String urlString) {
|
||||
// try {
|
||||
// URI uri = new URI(urlString);
|
||||
// String host = uri.getHost();
|
||||
// if (uri.getScheme() != null && host == null) {
|
||||
// if (uri.getScheme().equals("mailto")) {
|
||||
// return urlString;
|
||||
// } else {
|
||||
// return controllers.routes.Application.linkOut(urlString).toString
|
||||
// }
|
||||
// } else {
|
||||
// String trustedUrlHosts = this.config.app.trustedUrlHosts;
|
||||
// val checkSubdomain = (trusted: String) =>
|
||||
// trusted(0) == '.' && (host.endsWith(trusted) || host == trusted.substring(1))
|
||||
// if (host == null || trustedUrlHosts.exists(trusted => trusted == host || checkSubdomain(trusted))) { // scalafix:ok
|
||||
// return urlString
|
||||
// } else {
|
||||
// return controllers.routes.Application.linkOut(urlString).toString
|
||||
// }
|
||||
// }
|
||||
// } catch (URISyntaxException ex) {
|
||||
// return controllers.routes.Application.linkOut(urlString).toString
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
@ -38,7 +38,7 @@ Documentation page within Project overview.
|
||||
deletable=!page.isHome()
|
||||
enabled=canEditPages()
|
||||
raw=page.contents
|
||||
cooked=page.html(p.project)
|
||||
cooked=markdownService.render(page.contents)
|
||||
subject="Page"
|
||||
extraFormValue=page.name />
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user