Skip to content

Commit 8cd2982

Browse files
Merge pull request #1 from Polidea/parser_optimization
Parser optimization
2 parents 8a8782c + 2f31041 commit 8cd2982

File tree

5 files changed

+371
-322
lines changed

5 files changed

+371
-322
lines changed

app/src/main/java/br/tiagohm/markdownview/app/MainActivity.java

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,26 @@ protected void onCreate(Bundle savedInstanceState) {
1919
setContentView(R.layout.activity_main);
2020

2121
mMarkdownView = (MarkdownView) findViewById(R.id.mark_view);
22-
mMarkdownView.addStyleSheet(mStyle);
23-
//http://stackoverflow.com/questions/6370690/media-queries-how-to-target-desktop-tablet-and-mobile
24-
mStyle.addMedia("screen and (min-width: 320px)");
25-
mStyle.addRule("h1", "color: green");
26-
mStyle.endMedia();
27-
mStyle.addMedia("screen and (min-width: 481px)");
28-
mStyle.addRule("h1", "color: red");
29-
mStyle.endMedia();
30-
mStyle.addMedia("screen and (min-width: 641px)");
31-
mStyle.addRule("h1", "color: blue");
32-
mStyle.endMedia();
33-
mStyle.addMedia("screen and (min-width: 961px)");
34-
mStyle.addRule("h1", "color: yellow");
35-
mStyle.endMedia();
36-
mStyle.addMedia("screen and (min-width: 1025px)");
37-
mStyle.addRule("h1", "color: gray");
38-
mStyle.endMedia();
39-
mStyle.addMedia("screen and (min-width: 1281px)");
40-
mStyle.addRule("h1", "color: orange");
41-
mStyle.endMedia();
22+
// mMarkdownView.addStyleSheet(mStyle);
23+
// //http://stackoverflow.com/questions/6370690/media-queries-how-to-target-desktop-tablet-and-mobile
24+
// mStyle.addMedia("screen and (min-width: 320px)");
25+
// mStyle.addRule("h1", "color: green");
26+
// mStyle.endMedia();
27+
// mStyle.addMedia("screen and (min-width: 481px)");
28+
// mStyle.addRule("h1", "color: red");
29+
// mStyle.endMedia();
30+
// mStyle.addMedia("screen and (min-width: 641px)");
31+
// mStyle.addRule("h1", "color: blue");
32+
// mStyle.endMedia();
33+
// mStyle.addMedia("screen and (min-width: 961px)");
34+
// mStyle.addRule("h1", "color: yellow");
35+
// mStyle.endMedia();
36+
// mStyle.addMedia("screen and (min-width: 1025px)");
37+
// mStyle.addRule("h1", "color: gray");
38+
// mStyle.endMedia();
39+
// mStyle.addMedia("screen and (min-width: 1281px)");
40+
// mStyle.addRule("h1", "color: orange");
41+
// mStyle.endMedia();
4242
mMarkdownView.loadMarkdownFromAsset("markdown1.md");
4343
}
4444

gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
33
distributionPath=wrapper/dists
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists
6-
distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
6+
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-all.zip
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
package br.tiagohm.markdownview;
2+
3+
4+
import android.content.Context;
5+
import android.text.TextUtils;
6+
import android.util.Log;
7+
8+
import com.vladsch.flexmark.Extension;
9+
import com.vladsch.flexmark.ast.AutoLink;
10+
import com.vladsch.flexmark.ast.FencedCodeBlock;
11+
import com.vladsch.flexmark.ast.Heading;
12+
import com.vladsch.flexmark.ast.Image;
13+
import com.vladsch.flexmark.ast.Link;
14+
import com.vladsch.flexmark.ast.Node;
15+
import com.vladsch.flexmark.ext.abbreviation.Abbreviation;
16+
import com.vladsch.flexmark.ext.abbreviation.AbbreviationExtension;
17+
import com.vladsch.flexmark.ext.autolink.AutolinkExtension;
18+
import com.vladsch.flexmark.ext.footnotes.FootnoteExtension;
19+
import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughSubscriptExtension;
20+
import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension;
21+
import com.vladsch.flexmark.ext.tables.TablesExtension;
22+
import com.vladsch.flexmark.html.AttributeProvider;
23+
import com.vladsch.flexmark.html.HtmlRenderer;
24+
import com.vladsch.flexmark.html.IndependentAttributeProviderFactory;
25+
import com.vladsch.flexmark.html.renderer.AttributablePart;
26+
import com.vladsch.flexmark.html.renderer.NodeRendererContext;
27+
import com.vladsch.flexmark.parser.Parser;
28+
import com.vladsch.flexmark.superscript.SuperscriptExtension;
29+
import com.vladsch.flexmark.util.html.Attributes;
30+
import com.vladsch.flexmark.util.options.DataHolder;
31+
import com.vladsch.flexmark.util.options.DataKey;
32+
import com.vladsch.flexmark.util.options.MutableDataHolder;
33+
import com.vladsch.flexmark.util.options.MutableDataSet;
34+
35+
import java.util.Arrays;
36+
import java.util.HashSet;
37+
import java.util.LinkedHashSet;
38+
import java.util.LinkedList;
39+
import java.util.List;
40+
41+
import br.tiagohm.markdownview.css.ExternalStyleSheet;
42+
import br.tiagohm.markdownview.css.StyleSheet;
43+
import br.tiagohm.markdownview.ext.button.ButtonExtension;
44+
import br.tiagohm.markdownview.ext.emoji.EmojiExtension;
45+
import br.tiagohm.markdownview.ext.kbd.Keystroke;
46+
import br.tiagohm.markdownview.ext.kbd.KeystrokeExtension;
47+
import br.tiagohm.markdownview.ext.label.LabelExtension;
48+
import br.tiagohm.markdownview.ext.localization.LocalizationExtension;
49+
import br.tiagohm.markdownview.ext.mark.Mark;
50+
import br.tiagohm.markdownview.ext.mark.MarkExtension;
51+
import br.tiagohm.markdownview.ext.mathjax.MathJax;
52+
import br.tiagohm.markdownview.ext.mathjax.MathJaxExtension;
53+
import br.tiagohm.markdownview.ext.twitter.TwitterExtension;
54+
import br.tiagohm.markdownview.ext.video.VideoLinkExtension;
55+
import br.tiagohm.markdownview.js.ExternalScript;
56+
import br.tiagohm.markdownview.js.JavaScript;
57+
58+
public class MarkdownParser {
59+
60+
public final static JavaScript JQUERY_3 = new ExternalScript("file:///android_asset/js/jquery-3.1.1.min.js", false, false);
61+
public final static JavaScript HIGHLIGHTJS = new ExternalScript("file:///android_asset/js/highlight.js", false, true);
62+
public final static JavaScript MATHJAX = new ExternalScript("https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_CHTML", false, true);
63+
public final static JavaScript HIGHLIGHT_INIT = new ExternalScript("file:///android_asset/js/highlight-init.js", false, true);
64+
public final static JavaScript MATHJAX_CONFIG = new ExternalScript("file:///android_asset/js/mathjax-config.js", false, true);
65+
public final static JavaScript TOOLTIPSTER_JS = new ExternalScript("file:///android_asset/js/tooltipster.bundle.min.js", false, true);
66+
public final static JavaScript TOOLTIPSTER_INIT = new ExternalScript("file:///android_asset/js/tooltipster-init.js", false, true);
67+
68+
public final static StyleSheet TOOLTIPSTER_CSS = new ExternalStyleSheet("file:///android_asset/css/tooltipster.bundle.min.css");
69+
70+
private List<Extension> EXTENSIONS = Arrays.asList(TablesExtension.create(),
71+
TaskListExtension.create(),
72+
AbbreviationExtension.create(),
73+
AutolinkExtension.create(),
74+
MarkExtension.create(),
75+
StrikethroughSubscriptExtension.create(),
76+
SuperscriptExtension.create(),
77+
KeystrokeExtension.create(),
78+
MathJaxExtension.create(),
79+
FootnoteExtension.create(),
80+
EmojiExtension.create(),
81+
VideoLinkExtension.create(),
82+
TwitterExtension.create(),
83+
LabelExtension.create(),
84+
ButtonExtension.create(),
85+
LocalizationExtension.create());
86+
87+
private final DataHolder OPTIONS = new MutableDataSet()
88+
.set(FootnoteExtension.FOOTNOTE_REF_PREFIX, "[")
89+
.set(FootnoteExtension.FOOTNOTE_REF_SUFFIX, "]")
90+
.set(HtmlRenderer.FENCED_CODE_LANGUAGE_CLASS_PREFIX, "")
91+
.set(HtmlRenderer.FENCED_CODE_NO_LANGUAGE_CLASS, "nohighlight")
92+
//.set(FootnoteExtension.FOOTNOTE_BACK_REF_STRING, "&#8593")
93+
;
94+
95+
private final List<StyleSheet> mStyleSheets = new LinkedList<>();
96+
private final HashSet<JavaScript> mScripts = new LinkedHashSet<>();
97+
private boolean mEscapeHtml = true;
98+
99+
public String parseBuildAndRender(String text) {
100+
setEscapeHtml(false);
101+
Parser parser = Parser.builder(OPTIONS)
102+
.extensions(EXTENSIONS)
103+
.build();
104+
105+
HtmlRenderer renderer = HtmlRenderer.builder(OPTIONS)
106+
.escapeHtml(mEscapeHtml)
107+
.attributeProviderFactory(new IndependentAttributeProviderFactory() {
108+
@Override
109+
public AttributeProvider create(NodeRendererContext context) {
110+
return new CustomAttributeProvider();
111+
}
112+
})
113+
.nodeRendererFactory(new NodeRendererFactoryImpl())
114+
.extensions(EXTENSIONS)
115+
.build();
116+
117+
return renderer.render(parser.parse(text));
118+
}
119+
120+
public MarkdownParser basicsOnly() {
121+
EXTENSIONS = Arrays.asList();
122+
setEscapeHtml(false);
123+
mScripts.clear();
124+
mStyleSheets.clear();
125+
return this;
126+
}
127+
128+
129+
public String buildHtml(String text) {
130+
setEscapeHtml(false);
131+
long start = System.currentTimeMillis();
132+
String html = parseBuildAndRender(text);
133+
134+
StringBuilder sb = new StringBuilder();
135+
sb.append("<html>\n");
136+
sb.append("<head>\n");
137+
138+
for (StyleSheet s : mStyleSheets) {
139+
sb.append(s.toHTML());
140+
}
141+
142+
for (JavaScript js : mScripts) {
143+
sb.append(js.toHTML());
144+
}
145+
146+
sb.append("</head>\n");
147+
sb.append("<body>\n");
148+
sb.append("<div class=\"container\">\n");
149+
sb.append(html);
150+
sb.append("</div>\n");
151+
sb.append("</body>\n");
152+
sb.append("</html>");
153+
154+
html = sb.toString();
155+
long duration = System.currentTimeMillis() - start;
156+
Log.i("MarkdownParser", "----> Markdown Parsing time: " + duration);
157+
return html;
158+
}
159+
160+
public MarkdownParser setEscapeHtml(boolean flag) {
161+
mEscapeHtml = flag;
162+
return this;
163+
}
164+
165+
public MarkdownParser setEmojiRootPath(String path) {
166+
((MutableDataHolder) OPTIONS).set(EmojiExtension.ROOT_IMAGE_PATH, path);
167+
return this;
168+
}
169+
170+
public MarkdownParser setEmojiImageExtension(String ext) {
171+
((MutableDataHolder) OPTIONS).set(EmojiExtension.IMAGE_EXT, ext);
172+
return this;
173+
}
174+
175+
public MarkdownParser addStyleSheet(StyleSheet s) {
176+
if (s != null && !mStyleSheets.contains(s)) {
177+
mStyleSheets.add(s);
178+
}
179+
180+
return this;
181+
}
182+
183+
public MarkdownParser replaceStyleSheet(StyleSheet oldStyle, StyleSheet newStyle) {
184+
if (oldStyle == newStyle) {
185+
} else if (newStyle == null) {
186+
mStyleSheets.remove(oldStyle);
187+
} else {
188+
final int index = mStyleSheets.indexOf(oldStyle);
189+
190+
if (index >= 0) {
191+
mStyleSheets.set(index, newStyle);
192+
} else {
193+
addStyleSheet(newStyle);
194+
}
195+
}
196+
197+
return this;
198+
}
199+
200+
public MarkdownParser removeStyleSheet(StyleSheet s) {
201+
mStyleSheets.remove(s);
202+
return this;
203+
}
204+
205+
public MarkdownParser addJavascript(JavaScript js) {
206+
mScripts.add(js);
207+
return this;
208+
}
209+
210+
public MarkdownParser removeJavaScript(JavaScript js) {
211+
mScripts.remove(js);
212+
return this;
213+
}
214+
215+
public void addOption(DataKey<Context> key, Context context) {
216+
((MutableDataHolder) OPTIONS).set(key, context);
217+
}
218+
219+
public class CustomAttributeProvider implements AttributeProvider {
220+
@Override
221+
public void setAttributes(final Node node, final AttributablePart part, final Attributes attributes) {
222+
if (node instanceof FencedCodeBlock) {
223+
if (part.getName().equals("NODE")) {
224+
String language = ((FencedCodeBlock) node).getInfo().toString();
225+
if (!TextUtils.isEmpty(language) &&
226+
!language.equals("nohighlight")) {
227+
addJavascript(HIGHLIGHTJS);
228+
addJavascript(HIGHLIGHT_INIT);
229+
230+
attributes.addValue("language", language);
231+
attributes.addValue("onclick", String.format("javascript:android.onCodeTap('%s', this.textContent);",
232+
language));
233+
}
234+
}
235+
} else if (node instanceof MathJax) {
236+
addJavascript(MATHJAX);
237+
addJavascript(MATHJAX_CONFIG);
238+
} else if (node instanceof Abbreviation) {
239+
addJavascript(TOOLTIPSTER_JS);
240+
addStyleSheet(TOOLTIPSTER_CSS);
241+
addJavascript(TOOLTIPSTER_INIT);
242+
attributes.addValue("class", "tooltip");
243+
} else if (node instanceof Heading) {
244+
attributes.addValue("onclick", String.format("javascript:android.onHeadingTap(%d, '%s');",
245+
((Heading) node).getLevel(), ((Heading) node).getText()));
246+
} else if (node instanceof Image) {
247+
attributes.addValue("onclick", String.format("javascript: android.onImageTap(this.src, this.clientWidth, this.clientHeight);"));
248+
} else if (node instanceof Mark) {
249+
attributes.addValue("onclick", String.format("javascript: android.onMarkTap(this.textContent)"));
250+
} else if (node instanceof Keystroke) {
251+
attributes.addValue("onclick", String.format("javascript: android.onKeystrokeTap(this.textContent)"));
252+
} else if (node instanceof Link ||
253+
node instanceof AutoLink) {
254+
attributes.addValue("onclick", String.format("javascript: android.onLinkTap(this.href, this.textContent)"));
255+
}
256+
}
257+
}
258+
259+
}

0 commit comments

Comments
 (0)