Added markdown parser param to disable link shredding for announcements. Added markdown support to deck notes

This commit is contained in:
Christian 'ketura' McCarty
2024-11-30 21:22:40 -06:00
parent 0e0dc5c148
commit 8b4bf99e54
6 changed files with 51 additions and 21 deletions

View File

@@ -66,7 +66,7 @@ public class ChatRequestHandler extends LotroServerRequestHandler implements Uri
final boolean admin = resourceOwner.hasType(Player.Type.ADMIN);
final boolean leagueAdmin = resourceOwner.hasType(Player.Type.LEAGUE_ADMIN);
if (message != null && !message.trim().isEmpty()) {
String newMsg = _markdownParser.renderMarkdown(message);
String newMsg = _markdownParser.renderMarkdown(message, true);
chatRoom.sendMessage(resourceOwner.getName(), newMsg, admin);
responseWriter.writeXmlResponse(null);
} else {

View File

@@ -2,6 +2,7 @@ package com.gempukku.lotro.async.handler;
import com.gempukku.lotro.async.HttpProcessingException;
import com.gempukku.lotro.async.ResponseWriter;
import com.gempukku.lotro.chat.MarkdownParser;
import com.gempukku.lotro.common.JSONDefs;
import com.gempukku.lotro.common.Side;
import com.gempukku.lotro.db.DeckDAO;
@@ -39,6 +40,7 @@ public class DeckRequestHandler extends LotroServerRequestHandler implements Uri
private final LotroFormatLibrary _formatLibrary;
private final SoloDraftDefinitions _draftLibrary;
private final LotroServer _lotroServer;
private final MarkdownParser _markdownParser;
private static final Logger _log = LogManager.getLogger(DeckRequestHandler.class);
@@ -50,6 +52,7 @@ public class DeckRequestHandler extends LotroServerRequestHandler implements Uri
_formatLibrary = extractObject(context, LotroFormatLibrary.class);
_lotroServer = extractObject(context, LotroServer.class);
_draftLibrary = extractObject(context, SoloDraftDefinitions.class);
_markdownParser = extractObject(context, MarkdownParser.class);
}
@Override
@@ -395,7 +398,7 @@ public class DeckRequestHandler extends LotroServerRequestHandler implements Uri
for (CardCollection.Item item : _sortAndFilterCards.process("side:SHADOW sort:cardType,culture,name", deckCards.getAll(), _library, _formatLibrary))
result.append(item.getCount() + "x " + generateCardTooltip(item) + "<br/>");
result.append("<h3>Notes</h3><br>" + deck.getNotes().replace("\n", "<br/>"));
result.append("<h3>Notes</h3><br>" + _markdownParser.renderMarkdown(deck.getNotes(), true));
result.append("</body></html>");

View File

@@ -114,7 +114,8 @@ public class ServerBuilder {
extract(objectMap, DeckDAO.class),
extract(objectMap, LotroCardBlueprintLibrary.class),
extract(objectMap, ChatServer.class),
extract(objectMap, GameRecorder.class)));
extract(objectMap, GameRecorder.class),
extract(objectMap, MarkdownParser.class)));
objectMap.put(HallServer.class,
new HallServer(

View File

@@ -20,24 +20,33 @@ public class MarkdownParser {
private final Parser _markdownParser;
private final HtmlRenderer _markdownRenderer;
private final HtmlRenderer _noHiddenLinksRenderer;
private static Pattern QuoteExtender = Pattern.compile("^([ \t]*>[ \t]*.+)(?=\n[ \t]*[^>])", Pattern.MULTILINE);
public MarkdownParser() {
List<Extension> adminExt = Arrays.asList(StrikethroughExtension.create(), AutolinkExtension.create());
List<Extension> extensions = Arrays.asList(StrikethroughExtension.create(), AutolinkExtension.create());
_markdownParser = Parser.builder()
.extensions(adminExt)
.extensions(extensions)
.build();
_markdownRenderer = HtmlRenderer.builder()
.nodeRendererFactory(htmlContext -> new LinkShredder(htmlContext))
.extensions(adminExt)
.extensions(extensions)
.escapeHtml(true)
.sanitizeUrls(true)
.softbreak("<br />")
.build();
_noHiddenLinksRenderer = HtmlRenderer.builder()
.extensions(extensions)
.escapeHtml(true)
.sanitizeUrls(true)
.softbreak("<br />")
.build();
}
public String renderMarkdown(String markdown) {
public String renderMarkdown(String markdown, boolean shredLinks) {
String newMsg = markdown.trim().replaceAll("\n\n\n+", "\n\n\n");
newMsg = QuoteExtender.matcher(newMsg).replaceAll("$1\n");
//Escaping underscores so that URLs with lots of underscores (i.e. wiki links) aren't mangled
@@ -45,13 +54,23 @@ public class MarkdownParser {
newMsg = newMsg.replace("_", "\\_");
//Need to preserve any commands being made
if(!newMsg.startsWith("/")) {
newMsg = _markdownRenderer.render(_markdownParser.parse(newMsg));
// Prevent quotes with newlines from displaying side-by-side
newMsg = newMsg.replaceAll("</blockquote>[\n \t]*<blockquote>", "</blockquote><br /><blockquote>");
//Make all links open in a new tab
newMsg = newMsg.replaceAll("<(a href=\".*?\")>", "<$1 target=\"_blank\">");
if(newMsg.startsWith("/"))
return newMsg;
if(shredLinks) {
newMsg = _noHiddenLinksRenderer.render(_markdownParser.parse(newMsg));
}
else {
newMsg = _markdownRenderer.render(_markdownParser.parse(newMsg));
}
// Prevent quotes with newlines from displaying side-by-side
newMsg = newMsg.replaceAll("</blockquote>[\n \t]*<blockquote>", "</blockquote><br /><blockquote>");
//Make all links open in a new tab
newMsg = newMsg.replaceAll("<(a href=\".*?\")>", "<$1 target=\"_blank\">");
//Finally, make all newlines into html breaks
newMsg = newMsg.replaceAll("\n", "<br/>");
return newMsg;
}

View File

@@ -3,6 +3,7 @@ package com.gempukku.lotro.game;
import com.gempukku.lotro.PrivateInformationException;
import com.gempukku.lotro.SubscriptionConflictException;
import com.gempukku.lotro.SubscriptionExpiredException;
import com.gempukku.lotro.chat.MarkdownParser;
import com.gempukku.lotro.common.*;
import com.gempukku.lotro.communication.GameStateListener;
import com.gempukku.lotro.filters.Filters;
@@ -48,7 +49,7 @@ public class LotroGameMediator {
public LotroGameMediator(String gameId, LotroFormat lotroFormat, LotroGameParticipant[] participants, LotroCardBlueprintLibrary library,
GameTimer gameTimer, boolean allowSpectators, boolean cancellable, boolean showInGameHall,
String tournamentName) {
String tournamentName, MarkdownParser parser) {
_gameId = gameId;
_timeSettings = gameTimer;
_allowSpectators = allowSpectators;
@@ -59,14 +60,16 @@ public class LotroGameMediator {
for (LotroGameParticipant participant : participants) {
String participantId = participant.getPlayerId();
_playerDecks.put(participantId, participant.getDeck());
var deck = participant.getDeck();
deck.setNotes(parser.renderMarkdown(deck.getNotes(), true));
_playerDecks.put(participantId, deck);
_playerClocks.put(participantId, 0);
_playersPlaying.add(participantId);
}
_userFeedback = new DefaultUserFeedback();
_lotroGame = new DefaultLotroGame(lotroFormat, _playerDecks, _userFeedback, library, _timeSettings.toString(), _allowSpectators,
tournamentName);
_lotroGame = new DefaultLotroGame(lotroFormat, _playerDecks, _userFeedback, library, _timeSettings.toString(),
_allowSpectators, tournamentName);
_userFeedback.setGame(_lotroGame);
}

View File

@@ -4,6 +4,7 @@ import com.gempukku.lotro.AbstractServer;
import com.gempukku.lotro.PrivateInformationException;
import com.gempukku.lotro.chat.ChatCommandErrorException;
import com.gempukku.lotro.chat.ChatServer;
import com.gempukku.lotro.chat.MarkdownParser;
import com.gempukku.lotro.db.DeckDAO;
import com.gempukku.lotro.hall.GameSettings;
import com.gempukku.lotro.logic.timing.GameResultListener;
@@ -33,14 +34,17 @@ public class LotroServer extends AbstractServer {
private final ChatServer _chatServer;
private final GameRecorder _gameRecorder;
private final MarkdownParser _markdownParser;
private final ReadWriteLock _lock = new ReentrantReadWriteLock();
public LotroServer(DeckDAO deckDao, LotroCardBlueprintLibrary library, ChatServer chatServer, GameRecorder gameRecorder) {
public LotroServer(DeckDAO deckDao, LotroCardBlueprintLibrary library, ChatServer chatServer,
GameRecorder gameRecorder, MarkdownParser parser) {
_deckDao = deckDao;
_lotroCardBlueprintLibrary = library;
_chatServer = chatServer;
_gameRecorder = gameRecorder;
_markdownParser = parser;
}
protected void cleanup() {
@@ -110,9 +114,9 @@ public class LotroServer extends AbstractServer {
spectate = false;
}
LotroGameMediator lotroGameMediator = new LotroGameMediator(gameId, gameSettings.format(), participants, _lotroCardBlueprintLibrary,
gameSettings.timeSettings(),
spectate, !gameSettings.competitive(), gameSettings.hiddenGame(), tournamentName);
LotroGameMediator lotroGameMediator = new LotroGameMediator(gameId, gameSettings.format(), participants,
_lotroCardBlueprintLibrary, gameSettings.timeSettings(), spectate, !gameSettings.competitive(),
gameSettings.hiddenGame(), tournamentName, _markdownParser);
lotroGameMediator.addGameResultListener(
new GameResultListener() {
@Override