From 97130f95f04bd5cf8363b35994e3c44f11d70f0c Mon Sep 17 00:00:00 2001 From: Matthias Andreas Benkard Date: Mon, 27 Jan 2020 21:03:39 +0100 Subject: Wiki: Render WikiWord links and autolinks on the server side. Change-Id: I46f972bcebf765a3d9fb55b7b35f40deb978dc5d --- build.gradle | 2 + pom.xml | 2 + .../mulk/mulkcms2/benki/wiki/WikiPageRevision.java | 77 +++++++++++++++++++++- .../resources/templates/benki/wiki/wikiPage.html | 5 +- 4 files changed, 83 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index f0b037c..ae57661 100644 --- a/build.gradle +++ b/build.gradle @@ -108,6 +108,8 @@ task compileWeb { processResources { exclude("META-INF/resources/node_modules/**/*") + exclude("META-INF/resources/package.json") + exclude("META-INF/resources/yarn.lock") } quarkusBuild.dependsOn compileWeb diff --git a/pom.xml b/pom.xml index 0f26d3e..3fcdc0d 100644 --- a/pom.xml +++ b/pom.xml @@ -298,6 +298,8 @@ src/main/resources META-INF/resources/node_modules/**/* + META-INF/resources/package.json + META-INF/resources/yarn.lock false diff --git a/src/main/java/eu/mulk/mulkcms2/benki/wiki/WikiPageRevision.java b/src/main/java/eu/mulk/mulkcms2/benki/wiki/WikiPageRevision.java index 5783166..4054312 100644 --- a/src/main/java/eu/mulk/mulkcms2/benki/wiki/WikiPageRevision.java +++ b/src/main/java/eu/mulk/mulkcms2/benki/wiki/WikiPageRevision.java @@ -3,6 +3,9 @@ package eu.mulk.mulkcms2.benki.wiki; import eu.mulk.mulkcms2.benki.users.User; import io.quarkus.hibernate.orm.panache.PanacheEntityBase; import java.time.OffsetDateTime; +import java.util.function.Function; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; @@ -12,6 +15,11 @@ import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.nodes.TextNode; +import org.jsoup.parser.Tag; @Entity @Table(name = "wiki_page_revisions", schema = "benki") @@ -53,9 +61,76 @@ public class WikiPageRevision extends PanacheEntityBase { User author) { this.date = date; this.title = title; - this.content = content; + this.content = unhrefify(unwikilinkify(Jsoup.parse(content))).select("body").html(); this.format = format; this.page = page; this.author = author; } + + public String enrichedContent() { + return wikilinkify(hrefify(Jsoup.parse(content))).select("body").html(); + } + + private static Document tagsoupMapText(Document soup, Function fn) { + for (var subnode : + soup.select(":not(a):not(a *)").stream() + .flatMap(node -> node.childNodes().stream()) + .collect(Collectors.toUnmodifiableList())) { + if (subnode instanceof TextNode) { + var newNode = new Element(Tag.valueOf("span"), ""); + newNode.html(fn.apply(((TextNode) subnode).text())); + subnode.replaceWith(newNode); + newNode.unwrap(); + } + } + return soup; + } + + private static Pattern WIKIWORD_REGEX = + Pattern.compile( + "\\p{javaUpperCase}+\\p{javaLowerCase}+\\p{javaUpperCase}+\\p{javaLowerCase}+\\w+"); + private static Pattern URL_REGEX = + Pattern.compile("\\(?\\bhttps?://[-A-Za-z0-9+&@#/%?=~_()|!:,.;]*[-A-Za-z0-9+&@#/%=~_()|]"); + + private static Document hrefify(Document soup) { + return tagsoupMapText( + soup, + x -> + URL_REGEX + .matcher(x) + .replaceAll( + match -> { + var s = match.group(); + var leftParen = s.startsWith("("); + var rightParen = s.endsWith(")"); + var url = + s.substring(leftParen ? 1 : 0, rightParen ? s.length() - 1 : s.length()); + return String.format( + "%s%s%s", + leftParen ? "(" : "", url, url, rightParen ? ")" : ""); + })); + } + + private static Document unhrefify(Document soup) { + soup.select(".benkiautohref").unwrap(); + return soup; + } + + private static Document wikilinkify(Document soup) { + return tagsoupMapText( + soup, + x -> + WIKIWORD_REGEX + .matcher(x) + .replaceAll( + match -> + String.format( + "%s", + match.group(), match.group()))); + } + + private static Document unwikilinkify(Document soup) { + soup.select(".benkilink").unwrap(); + return soup; + } } diff --git a/src/main/resources/templates/benki/wiki/wikiPage.html b/src/main/resources/templates/benki/wiki/wikiPage.html index f9f5214..901b300 100644 --- a/src/main/resources/templates/benki/wiki/wikiPage.html +++ b/src/main/resources/templates/benki/wiki/wikiPage.html @@ -25,10 +25,11 @@ requestParams.append(name, regions[name]); } - var response = await fetch("/wiki/{page.title}", { + let response = await fetch("/wiki/{page.title}", { method: 'POST', body: requestParams }); + this.busy(false); }); }); @@ -45,7 +46,7 @@
- {#with page}{content.raw}{/} + {#with page}{enrichedContent.raw}{/}
-- cgit v1.2.3