initial commit
This commit is contained in:
commit
43771ff9d6
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
/.settings
|
||||
/bin
|
||||
/.classpath
|
||||
/TEST
|
||||
/target/
|
||||
/files/
|
23
.project
Normal file
23
.project
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>MdBlog</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
64
pom.xml
Normal file
64
pom.xml
Normal file
@ -0,0 +1,64 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>MDTest</groupId>
|
||||
<artifactId>MDTest</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<build>
|
||||
<sourceDirectory>src/main/java</sourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<release>17</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<commonmark.version>0.21.0</commonmark.version>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>Graphite-Official</id>
|
||||
<url>https://maven.graphite-official.com/releases</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>me.mrletsplay</groupId>
|
||||
<artifactId>SimpleHTTPServer</artifactId>
|
||||
<version>2.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.commonmark</groupId>
|
||||
<artifactId>commonmark</artifactId>
|
||||
<version>${commonmark.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.commonmark</groupId>
|
||||
<artifactId>commonmark-ext-gfm-tables</artifactId>
|
||||
<version>${commonmark.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.commonmark</groupId>
|
||||
<artifactId>commonmark-ext-gfm-strikethrough</artifactId>
|
||||
<version>${commonmark.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.commonmark</groupId>
|
||||
<artifactId>commonmark-ext-ins</artifactId>
|
||||
<version>${commonmark.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.commonmark</groupId>
|
||||
<artifactId>commonmark-ext-task-list-items</artifactId>
|
||||
<version>${commonmark.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
137
src/main/java/me/mrletsplay/mdblog/MdBlog.java
Normal file
137
src/main/java/me/mrletsplay/mdblog/MdBlog.java
Normal file
@ -0,0 +1,137 @@
|
||||
package me.mrletsplay.mdblog;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardWatchEventKinds;
|
||||
import java.nio.file.WatchKey;
|
||||
import java.nio.file.WatchService;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import me.mrletsplay.mdblog.blog.Post;
|
||||
import me.mrletsplay.simplehttpserver.http.HttpRequestMethod;
|
||||
import me.mrletsplay.simplehttpserver.http.document.FileDocument;
|
||||
import me.mrletsplay.simplehttpserver.http.request.HttpRequestContext;
|
||||
import me.mrletsplay.simplehttpserver.http.server.HttpServer;
|
||||
|
||||
public class MdBlog {
|
||||
|
||||
private static final Path
|
||||
FILES_PATH = Path.of("files"),
|
||||
POSTS_PATH = FILES_PATH.resolve("posts");
|
||||
|
||||
private static HttpServer server;
|
||||
private static WatchService watchService;
|
||||
private static List<WatchKey> watchedDirectories;
|
||||
private static Map<String, Post> posts;
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
server = new HttpServer(HttpServer.newConfigurationBuilder()
|
||||
.hostBindAll()
|
||||
.port(3706)
|
||||
.create());
|
||||
|
||||
server.getDocumentProvider().registerPattern(HttpRequestMethod.GET, "/posts/{path...}", () -> {
|
||||
HttpRequestContext ctx = HttpRequestContext.getCurrentContext();
|
||||
String path = ctx.getPathParameters().get("path");
|
||||
Post post = posts.get(path);
|
||||
if(post != null) {
|
||||
post.getContent().createContent();
|
||||
return;
|
||||
}
|
||||
|
||||
Path resolved = POSTS_PATH.resolve(path).normalize();
|
||||
if(!resolved.startsWith(POSTS_PATH) || resolved.getFileName().toString().endsWith(".md")) {
|
||||
server.getDocumentProvider().getNotFoundDocument().createContent();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!Files.isRegularFile(resolved)) {
|
||||
server.getDocumentProvider().getNotFoundDocument().createContent();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
new FileDocument(resolved).createContent();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
extractAndRegister("style/base.css");
|
||||
extractAndRegister("style/post.css");
|
||||
|
||||
server.start();
|
||||
|
||||
Files.createDirectories(FILES_PATH);
|
||||
Files.createDirectories(POSTS_PATH);
|
||||
|
||||
watchedDirectories = new ArrayList<>();
|
||||
watchService = POSTS_PATH.getFileSystem().newWatchService();
|
||||
posts = new HashMap<>();
|
||||
updateBlogs();
|
||||
watchFolders();
|
||||
|
||||
while(true) {
|
||||
try {
|
||||
WatchKey key = watchService.take();
|
||||
key.pollEvents();
|
||||
updateBlogs();
|
||||
watchFolders();
|
||||
if(!key.reset()) {
|
||||
key.cancel();
|
||||
watchedDirectories.remove(key);
|
||||
continue;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void extractAndRegister(String path) throws IOException {
|
||||
Path filePath = FILES_PATH.resolve(path);
|
||||
if(!Files.exists(filePath)) {
|
||||
Files.createDirectories(filePath.getParent());
|
||||
Files.write(filePath, MdBlog.class.getResourceAsStream("/" + path).readAllBytes());
|
||||
}
|
||||
|
||||
server.getDocumentProvider().register(HttpRequestMethod.GET, "/" + path, new FileDocument(filePath));
|
||||
}
|
||||
|
||||
private static void updateBlogs() throws IOException {
|
||||
Iterator<Post> it = posts.values().iterator();
|
||||
while(it.hasNext()) {
|
||||
Post p = it.next();
|
||||
if(!p.update()) it.remove();
|
||||
}
|
||||
|
||||
Files.walk(POSTS_PATH)
|
||||
.filter(Files::isRegularFile)
|
||||
.filter(f -> f.getFileName().toString().endsWith(".md"))
|
||||
.filter(f -> posts.values().stream().noneMatch(p -> p.getFilePath().equals(f)))
|
||||
.forEach(f -> {
|
||||
try {
|
||||
String path = POSTS_PATH.relativize(f).toString();
|
||||
path = path.substring(0, path.length() - ".md".length());
|
||||
posts.put(path, new Post(f));
|
||||
} catch (IOException e) {}
|
||||
});
|
||||
}
|
||||
|
||||
private static void watchFolders() throws IOException {
|
||||
Files.walk(POSTS_PATH)
|
||||
.filter(Files::isDirectory)
|
||||
.filter(d -> watchedDirectories.stream().noneMatch(w -> w.watchable().equals(d)))
|
||||
.forEach(d -> {
|
||||
try {
|
||||
System.out.println("Watching " + d);
|
||||
watchedDirectories.add(d.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.OVERFLOW));
|
||||
} catch (IOException e) {}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
84
src/main/java/me/mrletsplay/mdblog/blog/Post.java
Normal file
84
src/main/java/me/mrletsplay/mdblog/blog/Post.java
Normal file
@ -0,0 +1,84 @@
|
||||
package me.mrletsplay.mdblog.blog;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import me.mrletsplay.mdblog.markdown.MdParser;
|
||||
import me.mrletsplay.mdblog.markdown.MdRenderer;
|
||||
import me.mrletsplay.mrcore.misc.ByteUtils;
|
||||
import me.mrletsplay.simplehttpserver.dom.html.HtmlDocument;
|
||||
|
||||
public class Post {
|
||||
|
||||
private static final MessageDigest MD_5;
|
||||
private static final MdRenderer RENDERER = new MdRenderer();
|
||||
|
||||
static {
|
||||
try {
|
||||
MD_5 = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Path filePath;
|
||||
private String checksum;
|
||||
private PostMetadata metadata;
|
||||
private HtmlDocument content;
|
||||
|
||||
public Post(Path filePath) throws IOException {
|
||||
this.filePath = filePath;
|
||||
this.checksum = checksum(filePath);
|
||||
load();
|
||||
}
|
||||
|
||||
public Path getFilePath() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public PostMetadata getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public HtmlDocument getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
private void load() throws IOException {
|
||||
String postData = Files.readString(filePath);
|
||||
String[] spl = postData.split("\n---\n", 2);
|
||||
if(spl.length != 2) throw new IOException("Invalid post file");
|
||||
|
||||
this.metadata = PostMetadata.load(spl[0]);
|
||||
|
||||
HtmlDocument document = new HtmlDocument();
|
||||
document.getBodyNode().appendChild(RENDERER.render(MdParser.parse(spl[1])));
|
||||
document.setTitle(metadata.title());
|
||||
document.setDescription(metadata.author());
|
||||
document.addStyleSheet("/style/base.css");
|
||||
document.addStyleSheet("/style/post.css");
|
||||
this.content = document;
|
||||
}
|
||||
|
||||
public boolean update() {
|
||||
if(!Files.exists(filePath)) return false;
|
||||
|
||||
try {
|
||||
String newChecksum = checksum(filePath);
|
||||
if(checksum.equals(newChecksum)) return true;
|
||||
this.checksum = newChecksum;
|
||||
load();
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static String checksum(Path filePath) throws IOException {
|
||||
return ByteUtils.bytesToHex(MD_5.digest(Files.readAllBytes(filePath)));
|
||||
}
|
||||
|
||||
}
|
43
src/main/java/me/mrletsplay/mdblog/blog/PostMetadata.java
Normal file
43
src/main/java/me/mrletsplay/mdblog/blog/PostMetadata.java
Normal file
@ -0,0 +1,43 @@
|
||||
package me.mrletsplay.mdblog.blog;
|
||||
|
||||
import java.time.DateTimeException;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public record PostMetadata(Instant date, String title, String author, Set<String> tags) {
|
||||
|
||||
public static PostMetadata load(String metadataString) {
|
||||
Instant date = Instant.EPOCH;
|
||||
String title = "Untitled Post";
|
||||
String author = "Unknown Author";
|
||||
Set<String> tags = Collections.emptySet();
|
||||
for(String line : metadataString.split("\n")) {
|
||||
if(line.isEmpty()) continue;
|
||||
String[] spl = line.split(":", 2);
|
||||
if(spl.length != 2) {
|
||||
System.err.println("Invalid metadata line: " + line);
|
||||
continue;
|
||||
}
|
||||
|
||||
String key = spl[0].toLowerCase().trim();
|
||||
String value = spl[1].trim();
|
||||
|
||||
switch(key) {
|
||||
case "date" -> {
|
||||
try {
|
||||
date = Instant.parse(value);
|
||||
}catch(DateTimeException e) {}
|
||||
}
|
||||
case "title" -> title = value;
|
||||
case "author" -> author = value;
|
||||
case "tags" -> tags = Arrays.stream(value.split(",")).map(String::trim).collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
}
|
||||
|
||||
return new PostMetadata(date, title, author, tags);
|
||||
}
|
||||
|
||||
}
|
23
src/main/java/me/mrletsplay/mdblog/markdown/MdException.java
Normal file
23
src/main/java/me/mrletsplay/mdblog/markdown/MdException.java
Normal file
@ -0,0 +1,23 @@
|
||||
package me.mrletsplay.mdblog.markdown;
|
||||
|
||||
public class MdException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 2453345940664448784L;
|
||||
|
||||
public MdException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public MdException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public MdException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public MdException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
22
src/main/java/me/mrletsplay/mdblog/markdown/MdParser.java
Normal file
22
src/main/java/me/mrletsplay/mdblog/markdown/MdParser.java
Normal file
@ -0,0 +1,22 @@
|
||||
package me.mrletsplay.mdblog.markdown;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension;
|
||||
import org.commonmark.ext.gfm.tables.TablesExtension;
|
||||
import org.commonmark.ext.ins.InsExtension;
|
||||
import org.commonmark.ext.task.list.items.TaskListItemsExtension;
|
||||
import org.commonmark.node.Node;
|
||||
import org.commonmark.parser.Parser;
|
||||
|
||||
public class MdParser {
|
||||
|
||||
private static Parser parser = new Parser.Builder()
|
||||
.extensions(Arrays.asList(TablesExtension.create(), StrikethroughExtension.create(), InsExtension.create(), TaskListItemsExtension.create()))
|
||||
.build();
|
||||
|
||||
public static Node parse(String text) {
|
||||
Node n = parser.parse(text);
|
||||
return n;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package me.mrletsplay.mdblog.markdown;
|
||||
|
||||
public class MdRenderContext {
|
||||
|
||||
private MdRenderer renderer;
|
||||
|
||||
public MdRenderContext(MdRenderer renderer) {
|
||||
this.renderer = renderer;
|
||||
}
|
||||
|
||||
public MdRenderer getRenderer() {
|
||||
return renderer;
|
||||
}
|
||||
|
||||
}
|
208
src/main/java/me/mrletsplay/mdblog/markdown/MdRenderer.java
Normal file
208
src/main/java/me/mrletsplay/mdblog/markdown/MdRenderer.java
Normal file
@ -0,0 +1,208 @@
|
||||
package me.mrletsplay.mdblog.markdown;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.commonmark.ext.gfm.strikethrough.Strikethrough;
|
||||
import org.commonmark.ext.gfm.tables.TableBlock;
|
||||
import org.commonmark.ext.gfm.tables.TableBody;
|
||||
import org.commonmark.ext.gfm.tables.TableCell;
|
||||
import org.commonmark.ext.gfm.tables.TableHead;
|
||||
import org.commonmark.ext.gfm.tables.TableRow;
|
||||
import org.commonmark.ext.ins.Ins;
|
||||
import org.commonmark.ext.task.list.items.TaskListItemMarker;
|
||||
import org.commonmark.node.BlockQuote;
|
||||
import org.commonmark.node.BulletList;
|
||||
import org.commonmark.node.Code;
|
||||
import org.commonmark.node.Document;
|
||||
import org.commonmark.node.Emphasis;
|
||||
import org.commonmark.node.FencedCodeBlock;
|
||||
import org.commonmark.node.HardLineBreak;
|
||||
import org.commonmark.node.Heading;
|
||||
import org.commonmark.node.HtmlBlock;
|
||||
import org.commonmark.node.HtmlInline;
|
||||
import org.commonmark.node.Image;
|
||||
import org.commonmark.node.IndentedCodeBlock;
|
||||
import org.commonmark.node.Link;
|
||||
import org.commonmark.node.LinkReferenceDefinition;
|
||||
import org.commonmark.node.ListItem;
|
||||
import org.commonmark.node.Node;
|
||||
import org.commonmark.node.OrderedList;
|
||||
import org.commonmark.node.Paragraph;
|
||||
import org.commonmark.node.SoftLineBreak;
|
||||
import org.commonmark.node.StrongEmphasis;
|
||||
import org.commonmark.node.Text;
|
||||
import org.commonmark.node.ThematicBreak;
|
||||
|
||||
import me.mrletsplay.simplehttpserver.dom.html.HtmlElement;
|
||||
|
||||
public class MdRenderer {
|
||||
|
||||
public HtmlElement render(Node node) {
|
||||
MdRenderContext ctx = new MdRenderContext(this);
|
||||
|
||||
HtmlElement element = renderSingleNode(ctx, node);
|
||||
if(element == null) return null;
|
||||
Node ch = node.getFirstChild();
|
||||
if(ch == null) return element;
|
||||
do {
|
||||
HtmlElement chEl = render(ch);
|
||||
if(chEl == null) continue;
|
||||
element.appendChild(chEl);
|
||||
}while((ch = ch.getNext()) != null);
|
||||
return element;
|
||||
}
|
||||
|
||||
private HtmlElement renderSingleNode(MdRenderContext ctx, Node node) {
|
||||
try {
|
||||
Method m = MdRenderer.class.getDeclaredMethod("render", MdRenderContext.class, node.getClass());
|
||||
return (HtmlElement) m.invoke(this, ctx, node);
|
||||
}catch(NoSuchMethodException e) {
|
||||
System.err.println("Warning: No render() method defined for " + node.getClass().getName());
|
||||
return null;
|
||||
} catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, Document node) {
|
||||
HtmlElement el = new HtmlElement("div");
|
||||
el.setAttribute("md-document");
|
||||
return el;
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, Heading node) {
|
||||
return new HtmlElement("h" + Math.min(6, node.getLevel()));
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, Paragraph node) {
|
||||
return new HtmlElement("p");
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, BlockQuote node) {
|
||||
return new HtmlElement("blockquote");
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, BulletList node) {
|
||||
return new HtmlElement("ul");
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, FencedCodeBlock node) {
|
||||
HtmlElement el = new HtmlElement("pre");
|
||||
HtmlElement code = new HtmlElement("code");
|
||||
code.setText(node.getLiteral());
|
||||
el.appendChild(code);
|
||||
return el;
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, HtmlBlock node) {
|
||||
return new RawHtmlElement(node.getLiteral());
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, ThematicBreak node) {
|
||||
HtmlElement el = new HtmlElement("hr");
|
||||
el.setSelfClosing(true);
|
||||
return el;
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, IndentedCodeBlock node) {
|
||||
HtmlElement el = new HtmlElement("pre");
|
||||
HtmlElement code = new HtmlElement("code");
|
||||
code.setText(node.getLiteral());
|
||||
el.appendChild(code);
|
||||
return el;
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, Link node) {
|
||||
HtmlElement el = new HtmlElement("a");
|
||||
el.setAttribute("href", node.getDestination());
|
||||
el.setAttribute("title", node.getTitle());
|
||||
return el;
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, ListItem node) {
|
||||
return new HtmlElement("li");
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, OrderedList node) {
|
||||
HtmlElement el = new HtmlElement("ol");
|
||||
el.setAttribute("start", String.valueOf(node.getStartNumber()));
|
||||
return el;
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, Image node) {
|
||||
return HtmlElement.img(node.getDestination(), node.getTitle());
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, Emphasis node) {
|
||||
return new HtmlElement("em");
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, StrongEmphasis node) {
|
||||
return new HtmlElement("strong");
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, Text node) {
|
||||
HtmlElement el = new HtmlElement("span");
|
||||
el.setText(node.getLiteral());
|
||||
return el;
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, Code node) {
|
||||
HtmlElement el = new HtmlElement("code");
|
||||
el.setText(node.getLiteral());
|
||||
return el;
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, HtmlInline node) {
|
||||
return new RawHtmlElement(node.getLiteral());
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, SoftLineBreak node) {
|
||||
return new RawHtmlElement(" ");
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, HardLineBreak node) {
|
||||
return HtmlElement.br();
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, LinkReferenceDefinition node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, Strikethrough node) {
|
||||
return new HtmlElement("del");
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, TableBlock node) {
|
||||
return new HtmlElement("table");
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, TableHead node) {
|
||||
return new HtmlElement("thead");
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, TableBody node) {
|
||||
return new HtmlElement("tbody");
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, TableRow node) {
|
||||
return new HtmlElement("tr");
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, TableCell node) {
|
||||
return new HtmlElement("td");
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, Ins node) {
|
||||
return new HtmlElement("ins");
|
||||
}
|
||||
|
||||
public HtmlElement render(MdRenderContext ctx, TaskListItemMarker node) {
|
||||
HtmlElement el = new HtmlElement("input");
|
||||
el.setAttribute("type", "checkbox");
|
||||
el.setAttribute("disabled");
|
||||
if(node.isChecked()) el.setAttribute("checked");
|
||||
return el;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package me.mrletsplay.mdblog.markdown;
|
||||
|
||||
import me.mrletsplay.simplehttpserver.dom.html.HtmlElement;
|
||||
|
||||
public class RawHtmlElement extends HtmlElement {
|
||||
|
||||
private String raw;
|
||||
|
||||
public RawHtmlElement(String raw) {
|
||||
super("raw");
|
||||
this.raw = raw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return raw;
|
||||
}
|
||||
|
||||
}
|
7
src/main/resources/style/base.css
Normal file
7
src/main/resources/style/base.css
Normal file
@ -0,0 +1,7 @@
|
||||
body {
|
||||
filter: invert();
|
||||
}
|
||||
|
||||
h1 {
|
||||
background-color: red;
|
||||
}
|
3
src/main/resources/style/post.css
Normal file
3
src/main/resources/style/post.css
Normal file
@ -0,0 +1,3 @@
|
||||
h2 {
|
||||
background-color: orange;
|
||||
}
|
Loading…
Reference in New Issue
Block a user