Added markdown parser param to disable link shredding for announcements. Added markdown support to deck notes
This commit is contained in:
@@ -66,7 +66,7 @@ public class ChatRequestHandler extends LotroServerRequestHandler implements Uri
|
|||||||
final boolean admin = resourceOwner.hasType(Player.Type.ADMIN);
|
final boolean admin = resourceOwner.hasType(Player.Type.ADMIN);
|
||||||
final boolean leagueAdmin = resourceOwner.hasType(Player.Type.LEAGUE_ADMIN);
|
final boolean leagueAdmin = resourceOwner.hasType(Player.Type.LEAGUE_ADMIN);
|
||||||
if (message != null && !message.trim().isEmpty()) {
|
if (message != null && !message.trim().isEmpty()) {
|
||||||
String newMsg = _markdownParser.renderMarkdown(message);
|
String newMsg = _markdownParser.renderMarkdown(message, true);
|
||||||
chatRoom.sendMessage(resourceOwner.getName(), newMsg, admin);
|
chatRoom.sendMessage(resourceOwner.getName(), newMsg, admin);
|
||||||
responseWriter.writeXmlResponse(null);
|
responseWriter.writeXmlResponse(null);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.gempukku.lotro.async.handler;
|
|||||||
|
|
||||||
import com.gempukku.lotro.async.HttpProcessingException;
|
import com.gempukku.lotro.async.HttpProcessingException;
|
||||||
import com.gempukku.lotro.async.ResponseWriter;
|
import com.gempukku.lotro.async.ResponseWriter;
|
||||||
|
import com.gempukku.lotro.chat.MarkdownParser;
|
||||||
import com.gempukku.lotro.common.JSONDefs;
|
import com.gempukku.lotro.common.JSONDefs;
|
||||||
import com.gempukku.lotro.common.Side;
|
import com.gempukku.lotro.common.Side;
|
||||||
import com.gempukku.lotro.db.DeckDAO;
|
import com.gempukku.lotro.db.DeckDAO;
|
||||||
@@ -39,6 +40,7 @@ public class DeckRequestHandler extends LotroServerRequestHandler implements Uri
|
|||||||
private final LotroFormatLibrary _formatLibrary;
|
private final LotroFormatLibrary _formatLibrary;
|
||||||
private final SoloDraftDefinitions _draftLibrary;
|
private final SoloDraftDefinitions _draftLibrary;
|
||||||
private final LotroServer _lotroServer;
|
private final LotroServer _lotroServer;
|
||||||
|
private final MarkdownParser _markdownParser;
|
||||||
|
|
||||||
private static final Logger _log = LogManager.getLogger(DeckRequestHandler.class);
|
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);
|
_formatLibrary = extractObject(context, LotroFormatLibrary.class);
|
||||||
_lotroServer = extractObject(context, LotroServer.class);
|
_lotroServer = extractObject(context, LotroServer.class);
|
||||||
_draftLibrary = extractObject(context, SoloDraftDefinitions.class);
|
_draftLibrary = extractObject(context, SoloDraftDefinitions.class);
|
||||||
|
_markdownParser = extractObject(context, MarkdownParser.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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))
|
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(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>");
|
result.append("</body></html>");
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,8 @@ public class ServerBuilder {
|
|||||||
extract(objectMap, DeckDAO.class),
|
extract(objectMap, DeckDAO.class),
|
||||||
extract(objectMap, LotroCardBlueprintLibrary.class),
|
extract(objectMap, LotroCardBlueprintLibrary.class),
|
||||||
extract(objectMap, ChatServer.class),
|
extract(objectMap, ChatServer.class),
|
||||||
extract(objectMap, GameRecorder.class)));
|
extract(objectMap, GameRecorder.class),
|
||||||
|
extract(objectMap, MarkdownParser.class)));
|
||||||
|
|
||||||
objectMap.put(HallServer.class,
|
objectMap.put(HallServer.class,
|
||||||
new HallServer(
|
new HallServer(
|
||||||
|
|||||||
@@ -20,24 +20,33 @@ public class MarkdownParser {
|
|||||||
|
|
||||||
private final Parser _markdownParser;
|
private final Parser _markdownParser;
|
||||||
private final HtmlRenderer _markdownRenderer;
|
private final HtmlRenderer _markdownRenderer;
|
||||||
|
private final HtmlRenderer _noHiddenLinksRenderer;
|
||||||
|
|
||||||
private static Pattern QuoteExtender = Pattern.compile("^([ \t]*>[ \t]*.+)(?=\n[ \t]*[^>])", Pattern.MULTILINE);
|
private static Pattern QuoteExtender = Pattern.compile("^([ \t]*>[ \t]*.+)(?=\n[ \t]*[^>])", Pattern.MULTILINE);
|
||||||
|
|
||||||
public MarkdownParser() {
|
public MarkdownParser() {
|
||||||
List<Extension> adminExt = Arrays.asList(StrikethroughExtension.create(), AutolinkExtension.create());
|
List<Extension> extensions = Arrays.asList(StrikethroughExtension.create(), AutolinkExtension.create());
|
||||||
_markdownParser = Parser.builder()
|
_markdownParser = Parser.builder()
|
||||||
.extensions(adminExt)
|
.extensions(extensions)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
_markdownRenderer = HtmlRenderer.builder()
|
_markdownRenderer = HtmlRenderer.builder()
|
||||||
.nodeRendererFactory(htmlContext -> new LinkShredder(htmlContext))
|
.nodeRendererFactory(htmlContext -> new LinkShredder(htmlContext))
|
||||||
.extensions(adminExt)
|
.extensions(extensions)
|
||||||
|
.escapeHtml(true)
|
||||||
|
.sanitizeUrls(true)
|
||||||
|
.softbreak("<br />")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
_noHiddenLinksRenderer = HtmlRenderer.builder()
|
||||||
|
.extensions(extensions)
|
||||||
.escapeHtml(true)
|
.escapeHtml(true)
|
||||||
.sanitizeUrls(true)
|
.sanitizeUrls(true)
|
||||||
.softbreak("<br />")
|
.softbreak("<br />")
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String renderMarkdown(String markdown) {
|
public String renderMarkdown(String markdown, boolean shredLinks) {
|
||||||
String newMsg = markdown.trim().replaceAll("\n\n\n+", "\n\n\n");
|
String newMsg = markdown.trim().replaceAll("\n\n\n+", "\n\n\n");
|
||||||
newMsg = QuoteExtender.matcher(newMsg).replaceAll("$1\n");
|
newMsg = QuoteExtender.matcher(newMsg).replaceAll("$1\n");
|
||||||
//Escaping underscores so that URLs with lots of underscores (i.e. wiki links) aren't mangled
|
//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("_", "\\_");
|
newMsg = newMsg.replace("_", "\\_");
|
||||||
|
|
||||||
//Need to preserve any commands being made
|
//Need to preserve any commands being made
|
||||||
if(!newMsg.startsWith("/")) {
|
if(newMsg.startsWith("/"))
|
||||||
newMsg = _markdownRenderer.render(_markdownParser.parse(newMsg));
|
return 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
|
if(shredLinks) {
|
||||||
newMsg = newMsg.replaceAll("<(a href=\".*?\")>", "<$1 target=\"_blank\">");
|
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;
|
return newMsg;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.gempukku.lotro.game;
|
|||||||
import com.gempukku.lotro.PrivateInformationException;
|
import com.gempukku.lotro.PrivateInformationException;
|
||||||
import com.gempukku.lotro.SubscriptionConflictException;
|
import com.gempukku.lotro.SubscriptionConflictException;
|
||||||
import com.gempukku.lotro.SubscriptionExpiredException;
|
import com.gempukku.lotro.SubscriptionExpiredException;
|
||||||
|
import com.gempukku.lotro.chat.MarkdownParser;
|
||||||
import com.gempukku.lotro.common.*;
|
import com.gempukku.lotro.common.*;
|
||||||
import com.gempukku.lotro.communication.GameStateListener;
|
import com.gempukku.lotro.communication.GameStateListener;
|
||||||
import com.gempukku.lotro.filters.Filters;
|
import com.gempukku.lotro.filters.Filters;
|
||||||
@@ -48,7 +49,7 @@ public class LotroGameMediator {
|
|||||||
|
|
||||||
public LotroGameMediator(String gameId, LotroFormat lotroFormat, LotroGameParticipant[] participants, LotroCardBlueprintLibrary library,
|
public LotroGameMediator(String gameId, LotroFormat lotroFormat, LotroGameParticipant[] participants, LotroCardBlueprintLibrary library,
|
||||||
GameTimer gameTimer, boolean allowSpectators, boolean cancellable, boolean showInGameHall,
|
GameTimer gameTimer, boolean allowSpectators, boolean cancellable, boolean showInGameHall,
|
||||||
String tournamentName) {
|
String tournamentName, MarkdownParser parser) {
|
||||||
_gameId = gameId;
|
_gameId = gameId;
|
||||||
_timeSettings = gameTimer;
|
_timeSettings = gameTimer;
|
||||||
_allowSpectators = allowSpectators;
|
_allowSpectators = allowSpectators;
|
||||||
@@ -59,14 +60,16 @@ public class LotroGameMediator {
|
|||||||
|
|
||||||
for (LotroGameParticipant participant : participants) {
|
for (LotroGameParticipant participant : participants) {
|
||||||
String participantId = participant.getPlayerId();
|
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);
|
_playerClocks.put(participantId, 0);
|
||||||
_playersPlaying.add(participantId);
|
_playersPlaying.add(participantId);
|
||||||
}
|
}
|
||||||
|
|
||||||
_userFeedback = new DefaultUserFeedback();
|
_userFeedback = new DefaultUserFeedback();
|
||||||
_lotroGame = new DefaultLotroGame(lotroFormat, _playerDecks, _userFeedback, library, _timeSettings.toString(), _allowSpectators,
|
_lotroGame = new DefaultLotroGame(lotroFormat, _playerDecks, _userFeedback, library, _timeSettings.toString(),
|
||||||
tournamentName);
|
_allowSpectators, tournamentName);
|
||||||
_userFeedback.setGame(_lotroGame);
|
_userFeedback.setGame(_lotroGame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.gempukku.lotro.AbstractServer;
|
|||||||
import com.gempukku.lotro.PrivateInformationException;
|
import com.gempukku.lotro.PrivateInformationException;
|
||||||
import com.gempukku.lotro.chat.ChatCommandErrorException;
|
import com.gempukku.lotro.chat.ChatCommandErrorException;
|
||||||
import com.gempukku.lotro.chat.ChatServer;
|
import com.gempukku.lotro.chat.ChatServer;
|
||||||
|
import com.gempukku.lotro.chat.MarkdownParser;
|
||||||
import com.gempukku.lotro.db.DeckDAO;
|
import com.gempukku.lotro.db.DeckDAO;
|
||||||
import com.gempukku.lotro.hall.GameSettings;
|
import com.gempukku.lotro.hall.GameSettings;
|
||||||
import com.gempukku.lotro.logic.timing.GameResultListener;
|
import com.gempukku.lotro.logic.timing.GameResultListener;
|
||||||
@@ -33,14 +34,17 @@ public class LotroServer extends AbstractServer {
|
|||||||
|
|
||||||
private final ChatServer _chatServer;
|
private final ChatServer _chatServer;
|
||||||
private final GameRecorder _gameRecorder;
|
private final GameRecorder _gameRecorder;
|
||||||
|
private final MarkdownParser _markdownParser;
|
||||||
|
|
||||||
private final ReadWriteLock _lock = new ReentrantReadWriteLock();
|
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;
|
_deckDao = deckDao;
|
||||||
_lotroCardBlueprintLibrary = library;
|
_lotroCardBlueprintLibrary = library;
|
||||||
_chatServer = chatServer;
|
_chatServer = chatServer;
|
||||||
_gameRecorder = gameRecorder;
|
_gameRecorder = gameRecorder;
|
||||||
|
_markdownParser = parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void cleanup() {
|
protected void cleanup() {
|
||||||
@@ -110,9 +114,9 @@ public class LotroServer extends AbstractServer {
|
|||||||
spectate = false;
|
spectate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LotroGameMediator lotroGameMediator = new LotroGameMediator(gameId, gameSettings.format(), participants, _lotroCardBlueprintLibrary,
|
LotroGameMediator lotroGameMediator = new LotroGameMediator(gameId, gameSettings.format(), participants,
|
||||||
gameSettings.timeSettings(),
|
_lotroCardBlueprintLibrary, gameSettings.timeSettings(), spectate, !gameSettings.competitive(),
|
||||||
spectate, !gameSettings.competitive(), gameSettings.hiddenGame(), tournamentName);
|
gameSettings.hiddenGame(), tournamentName, _markdownParser);
|
||||||
lotroGameMediator.addGameResultListener(
|
lotroGameMediator.addGameResultListener(
|
||||||
new GameResultListener() {
|
new GameResultListener() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user