/*********************************************************************** * This file is part of iDempiere ERP Open Source * * http://www.idempiere.org * * * * Copyright (C) Contributors * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301, USA. * **********************************************************************/ package org.adempiere.base.markdown; import java.util.List; import java.util.Map; import org.commonmark.Extension; import org.commonmark.ext.autolink.AutolinkExtension; import org.commonmark.ext.gfm.tables.TablesExtension; import org.commonmark.node.Link; import org.commonmark.node.Node; import org.commonmark.parser.Parser; import org.commonmark.renderer.html.AttributeProvider; import org.commonmark.renderer.html.AttributeProviderContext; import org.commonmark.renderer.html.AttributeProviderFactory; import org.commonmark.renderer.html.HtmlRenderer; import org.commonmark.renderer.html.HtmlRenderer.Builder; import org.osgi.service.component.annotations.Component; @Component(service = IMarkdownRenderer.class, immediate = true) public class MarkdownRendererImpl implements IMarkdownRenderer { public MarkdownRendererImpl() { } @Override public String renderToHtml(String inputText, boolean autoLink) { List extensions = autoLink ? List.of(TablesExtension.create(), AutolinkExtension.create()) : List.of(TablesExtension.create()); Parser parser = Parser.builder().extensions(extensions).build(); Builder builder = HtmlRenderer.builder().extensions(extensions).omitSingleParagraphP(true); if (autoLink) builder = builder.attributeProviderFactory(new AttributeProviderFactory() { public AttributeProvider create(AttributeProviderContext context) { return new LinkAttributeProvider(); } }); HtmlRenderer renderer = builder.build(); if (inputText.indexOf(MARKDOWN_OPENING_TAG) >= 0 && inputText.indexOf(MARKDOWN_CLOSING_TAG) > 0) { StringBuilder sb = new StringBuilder(); int start = inputText.indexOf(MARKDOWN_OPENING_TAG); int end = start >= 0 ? inputText.indexOf(MARKDOWN_CLOSING_TAG, start) : 0; while (start >= 0 && end > start) { sb.append(inputText.substring(0, start)); String md = inputText.substring(start+MARKDOWN_OPENING_TAG.length(), end); if (end+5 < inputText.length()) inputText = inputText.substring(end+MARKDOWN_CLOSING_TAG.length(), inputText.length()); else inputText = ""; Node node = parser.parse(md); sb.append(renderer.render(node)); start = inputText.indexOf(MARKDOWN_OPENING_TAG); end = start >= 0 ? inputText.indexOf(MARKDOWN_CLOSING_TAG, start) : 0; } if (inputText.length() > 0) sb.append(inputText); return sb.toString(); } else { Node node = parser.parse(inputText); return renderer.render(node); } } /** * Add target to link generated by markdown autolink extension */ private class LinkAttributeProvider implements AttributeProvider { @Override public void setAttributes(Node node, String tagName, Map attributes) { if (node instanceof Link) { String href = attributes.get("href"); if (href != null) { if (!href.startsWith("javascript:") && !attributes.containsKey("target")) attributes.put("target", "_blank"); if (!attributes.containsKey("onclick")) attributes.put("onclick", "event.stopPropagation()"); } } } } }