package org.commcare.utils; import android.content.Context; import android.os.Build; import android.text.Html; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.style.UnderlineSpan; import net.nightwhistler.htmlspanner.HtmlSpanner; import net.nightwhistler.htmlspanner.SpanStack; import net.nightwhistler.htmlspanner.TagNodeHandler; import org.commcare.CommCareApplication; import org.commcare.preferences.DeveloperPreferences; import org.htmlcleaner.TagNode; import org.javarosa.core.services.locale.Localization; import in.uncod.android.bypass.Bypass; public class MarkupUtil { public static class UnderlineHandler extends TagNodeHandler { @Override public void handleTagNode(TagNode node, SpannableStringBuilder builder, int start, int end, SpanStack spanStack) { spanStack.pushSpan(new UnderlineSpan(), start, end); } } private static final HtmlSpanner htmlspanner = new HtmlSpanner() { { this.registerHandler("u", new UnderlineHandler()); } }; public static Spannable styleSpannable(Context c, String message) { if (DeveloperPreferences.isMarkdownEnabled()) { returnMarkdown(c, message); } if (DeveloperPreferences.isCssEnabled()) { returnCSS(message); } return new SpannableString(message); } public static Spannable localizeStyleSpannable(Context c, String localizationKey) { return styleSpannable(c, Localization.get(localizationKey)); } public static Spannable localizeStyleSpannable(Context c, String localizationKey, String localizationArg) { return styleSpannable(c, Localization.get(localizationKey, localizationArg)); } public static Spannable localizeStyleSpannable(Context c, String localizationKey, String[] localizationArgs) { return styleSpannable(c, Localization.get(localizationKey, localizationArgs)); } public static Spannable returnMarkdown(Context c, String message) { return new SpannableString(generateMarkdown(c, message)); } public static Spannable returnCSS(String message) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) { return new SpannableString(Html.fromHtml(message)); } else { return htmlspanner.fromHtml(MarkupUtil.getStyleString() + message); } } private static CharSequence generateMarkdown(Context c, String message) { Bypass bypass = new Bypass(c); return trimTrailingWhitespace(bypass.markdownToSpannable(convertCharacterEncodings(message))); } /** * Trims trailing whitespace. Removes any of these characters: * 0009, HORIZONTAL TABULATION * 000A, LINE FEED * 000B, VERTICAL TABULATION * 000C, FORM FEED * 000D, CARRIAGE RETURN * 001C, FILE SEPARATOR * 001D, GROUP SEPARATOR * 001E, RECORD SEPARATOR * 001F, UNIT SEPARATOR * * @return "" if source is null, otherwise string with all trailing whitespace removed * soruce: http://stackoverflow.com/questions/9589381/remove-extra-line-breaks-after-html-fromhtml */ private static CharSequence trimTrailingWhitespace(CharSequence source) { if (source == null) { return ""; } int i = source.length(); // loop back to the first non-whitespace character while (--i >= 0 && Character.isWhitespace(source.charAt(i))) { } return source.subSequence(0, i + 1); } private static String convertCharacterEncodings(String input) { return convertNewlines(convertPoundSigns(input)); } private static String convertNewlines(String input) { return input.replace("\\n", System.getProperty("line.separator")); } private static String convertPoundSigns(String input) { return input.replace("\\#", "#"); } /* * CSS style classes used by GridEntityView which has its own pattern (probably silly) */ public static Spannable getSpannable(String message) { if (!DeveloperPreferences.isCssEnabled()) { return Spannable.Factory.getInstance().newSpannable(MarkupUtil.stripHtml(message)); } return htmlspanner.fromHtml(message); } public static Spannable getCustomSpannable(String style, String message) { if (!DeveloperPreferences.isCssEnabled()) { return Spannable.Factory.getInstance().newSpannable(MarkupUtil.stripHtml(message)); } String mStyles = "<style> " + style + " </style>"; return htmlspanner.fromHtml(mStyles + message); } private static String getStyleString() { if (CommCareApplication.instance() != null && CommCareApplication.instance().getCurrentApp() != null) { return CommCareApplication.instance().getCurrentApp().getStylizer().getStyleString(); } else { // fail silently? return ""; } } public static String formatKeyVal(String key, String val) { return "<style> #" + key + " " + val + " </style>"; } private static String stripHtml(String html) { return Html.fromHtml(html).toString(); } }