Created
October 4, 2016 07:53
-
-
Save Shusshu/b4c0d5634e69adf9a22fa694cd853f28 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import android.graphics.BlurMaskFilter; | |
import android.graphics.Color; | |
import android.graphics.EmbossMaskFilter; | |
import android.graphics.Typeface; | |
import android.net.Uri; | |
import android.text.Layout; | |
import android.text.style.AbsoluteSizeSpan; | |
import android.text.style.BackgroundColorSpan; | |
import android.text.style.ForegroundColorSpan; | |
import android.text.style.ImageSpan; | |
import android.text.style.QuoteSpan; | |
import android.text.style.RelativeSizeSpan; | |
import android.text.style.StrikethroughSpan; | |
import android.text.style.StyleSpan; | |
import android.text.style.TypefaceSpan; | |
import android.text.style.URLSpan; | |
import android.text.style.UnderlineSpan; | |
import android.text.style.AlignmentSpan; | |
import android.text.style.BulletSpan; | |
import android.text.style.MaskFilterSpan; | |
import android.text.style.SubscriptSpan; | |
import android.text.style.SuperscriptSpan; | |
import android.view.Gravity; | |
import com.binaryfork.spanny.Spanny; | |
import org.primeframework.transformer.domain.Document; | |
import org.primeframework.transformer.domain.Node; | |
import org.primeframework.transformer.domain.TagNode; | |
import org.primeframework.transformer.domain.TextNode; | |
import org.primeframework.transformer.service.TransformException; | |
import org.primeframework.transformer.service.TransformerSpanny; | |
/** | |
* BBCode to Spanny Transformer For a downgraded version of https://github.com/inversoft/prime-transformer (Java 8 to Java 7) | |
[bullet]First point[/bullet][BR] | |
[bullet]Second point[/bullet][BR] | |
[bullet=30]A[/bullet][BR] | |
[bullet=30]B[/bullet][BR] | |
[quote]Quote me if you can I'm writing so much text that I can be quoted for ages. Yes[/quote][BR] | |
[code]public method() static url variable + ; ... ++a - b = c;[/code][BR] | |
[blur]Blur this[/blur][BR] | |
[emboss][b]bold emboss this[/b][/emboss][BR] | |
[b][i]Bold italic[/i][/b][BR] | |
[s]strike[/s][BR] | |
[u]underline[/u][BR] | |
[style relsize=2.2]Bigger text[/style][BR] | |
32[superscript]2[/superscript] + x[BR] | |
[align=center]Align me if you can I'm writing so much text that I can be quoted for ages. Yes[/align][BR] | |
[align=opposite]Align me if you can I'm writing so much text that I can be quoted for ages. Yes[/align][BR] | |
[align=normal]Align me if you can I'm writing so much text that I can be quoted for ages. Yes[/align][BR] | |
[url=https://www.google.be]Google LINK[/url][BR] | |
[phone=+32466666666]0466666666[/phone] | |
*/ | |
public class BBCodeToSpanTransformer implements TransformerSpanny { | |
public static final String TAG_BOLD = "b"; | |
public static final String TAG_LABEL = "l"; | |
public static final String TAG_STRIKE = "s"; | |
public static final String TAG_ITALIC = "i"; | |
public static final String TAG_UNDERLINE = "u"; | |
public static final String TAG_URL = "url"; | |
public static final String TAG_PHONE = "phone"; | |
public static final String TAG_IMG = "img"; | |
public static final String TAG_CODE = "code"; | |
public static final String TAG_QUOTE = "quote"; | |
public static final String TAG_STYLE = "style"; | |
public static final String TAG_COLOR = "color"; | |
public static final String TAG_FONT_FAMILY = "font-family"; | |
public static final String TAG_BLUR = "blur"; | |
public static final String TAG_BULLET = "bullet"; | |
public static final String TAG_EMBOSS = "emboss"; | |
public static final String TAG_SUPERSCRIPT = "superscript"; | |
public static final String TAG_SUBSCRIPT = "subscript"; | |
public static final String TAG_FONT = "font"; | |
public static final String TAG_ALIGN = "align"; | |
public static final String ALIGN_CENTER = "center"; | |
public static final String ALIGN_NORMAL = "normal"; | |
public static final String ALIGN_OPPOSITE = "opposite"; | |
public static final String ATTR_BLUR = "blur"; | |
public static final String ATTR_EMBOSS = "emboss"; | |
public static final String ATTR_SUPERSCRIPT = "superscript"; | |
public static final String ATTR_SUBSCRIPT = "subscript"; | |
public static final String ATTR_COLOR = "color"; | |
public static final String ATTR_SIZE = "size"; | |
public static final String ATTR_ABS_SIZE = "abssize"; | |
public static final String ATTR_REL_SIZE = "relsize"; | |
public static final String ATTR_BG_COLOR = "bgcolor"; | |
public static final String ATTR_FG_COLOR = "fgcolor"; | |
public static final String ATTR_FONT_FAMILY = "font-family"; | |
private Context context; | |
public BBCodeToSpanTransformer(Context context) { | |
this.context = context; | |
} | |
@Override | |
public Spanny transform( | |
Document document, | |
boolean transform) | |
throws TransformException { | |
return recurse(document, transform); | |
} | |
protected Spanny recurse( | |
Node node, | |
boolean transform) | |
throws TransformException { | |
Spanny spanny = new Spanny(); | |
if (node instanceof TextNode) { | |
TextNode textNode = (TextNode) node; | |
String text = textNode.getBody(); | |
spanny.append(text); | |
} else if (node instanceof Document) { | |
Document document = (Document) node; | |
for (Node child : document.children) { | |
spanny.append(recurse(child, transform)); | |
} | |
} else if (node instanceof TagNode) { | |
TagNode tagNode = (TagNode) node; | |
String tagName = tagNode.getName().toLowerCase(); | |
if (transform) { | |
// Transform the children first | |
Spanny childBuild = new Spanny(); | |
for (Node child : tagNode.children) { | |
childBuild.append(recurse(child, transform)); | |
} | |
transformToSpanny(spanny, tagName, tagNode, childBuild); | |
} else { | |
spanny.append(tagNode.getRawString()); | |
} | |
} else { | |
throw new TransformException("Invalid node class [" + node.getClass() + "]"); | |
} | |
return spanny; | |
} | |
protected void transformToSpanny( | |
final Spanny spanny, | |
final String tagName, | |
final TagNode tagNode, | |
CharSequence body) { | |
boolean tagUnknown = false; | |
String attribute = tagNode.attribute; | |
Object span = null; | |
String url; | |
switch (tagName) { | |
case TAG_LABEL: | |
body = "\n" + body + "\n"; | |
span = new StyleSpan(Typeface.BOLD); | |
break; | |
case TAG_BOLD: | |
span = new StyleSpan(Typeface.BOLD); | |
break; | |
case TAG_ITALIC: | |
span = new StyleSpan(Typeface.ITALIC); | |
break; | |
case TAG_UNDERLINE: | |
span = new UnderlineSpan(); | |
break; | |
case TAG_PHONE: | |
url = attribute == null || attribute.isEmpty() ? "tel:" + body : "tel:" + attribute; | |
span = new URLSpan(url); | |
break; | |
case TAG_URL: | |
url = attribute == null || attribute.isEmpty() ? body.toString() : attribute; | |
span = new URLSpan(url); | |
break; | |
case TAG_STRIKE: | |
span = new StrikethroughSpan(); | |
break; | |
case TAG_IMG: | |
url = attribute == null || attribute.isEmpty() ? body.toString() : attribute; | |
if (!canProcess(url)) { | |
return; | |
} | |
span = new ImageSpan(context, Uri.parse(processUrl(url))); | |
break; | |
case TAG_CODE: | |
span = new QuoteSpan(); | |
break; | |
case TAG_QUOTE: | |
span = new QuoteSpan(); | |
break; | |
case TAG_FONT_FAMILY: | |
if (attribute != null && !attribute.isEmpty()) { | |
span = new TypefaceSpan(attribute); | |
} | |
break; | |
case TAG_STYLE: | |
if (!tagNode.attributes.isEmpty()) { | |
Object[] spans = new Object[tagNode.attributes.size()]; | |
int i = 0; | |
for (String attrName : tagNode.attributes.keySet()) { | |
span = createStyleSpan(attrName, tagNode.attributes.get(attrName)); | |
if (span == null) { | |
continue; | |
} | |
spans[i] = span; | |
i++; | |
} | |
spanny.append(body, spans); | |
} else { | |
styleSingleAttributeBehavior(spanny, tagName, tagNode, body); | |
} | |
break; | |
case TAG_COLOR: | |
span = new ForegroundColorSpan(Color.parseColor(attribute)); | |
break; | |
case TAG_BLUR: | |
span = makeBlur(); | |
break; | |
case TAG_BULLET: | |
if (tagNode.attribute != null && !tagNode.attribute.isEmpty()) { | |
try { | |
span = new BulletSpan(Integer.valueOf(tagNode.attribute)); | |
} catch (NumberFormatException ex) { | |
span = new BulletSpan(); | |
} | |
} else { | |
span = new BulletSpan(); | |
} | |
break; | |
case TAG_ALIGN: | |
Layout.Alignment alignment = Layout.Alignment.ALIGN_CENTER; | |
if (tagNode.attribute != null) { | |
switch (tagNode.attribute) { | |
case ALIGN_CENTER: | |
alignment = Layout.Alignment.ALIGN_CENTER; | |
break; | |
case ALIGN_NORMAL: | |
alignment = Layout.Alignment.ALIGN_NORMAL; | |
break; | |
case ALIGN_OPPOSITE: | |
alignment = Layout.Alignment.ALIGN_OPPOSITE; | |
break; | |
default: | |
alignment = Layout.Alignment.ALIGN_CENTER; | |
} | |
} | |
span = new AlignmentSpan.Standard(alignment); | |
break; | |
case TAG_EMBOSS: | |
span = makeEmboss(); | |
break; | |
case TAG_SUPERSCRIPT: | |
span = new SuperscriptSpan(); | |
break; | |
case TAG_SUBSCRIPT: | |
span = new SubscriptSpan(); | |
break; | |
case TAG_FONT: | |
if (tagNode.attribute != null && !tagNode.attribute.isEmpty()) { | |
try { | |
Typeface font = Typeface.createFromAsset(getContext().getAssets(), tagNode.attribute); | |
if (font != null) { | |
span = new CustomTypefaceSpan(font); | |
} | |
} catch (Exception e) { | |
//Do nothing | |
} | |
} | |
break; | |
default: | |
tagUnknown = true; | |
} | |
if (tagNode.attributes.isEmpty() && !tagUnknown) { | |
spanny.append(body, span); | |
} | |
} | |
/** | |
* Intended to be available for a child class to change the default behavior | |
* | |
* @param spanny | |
* @param tagName | |
* @param tagNode | |
* @param body | |
*/ | |
protected void styleSingleAttributeBehavior( | |
final Spanny spanny, | |
final String tagName, | |
final TagNode tagNode, | |
CharSequence body) { | |
} | |
protected Object createStyleSpan( | |
final String attrName, | |
final String attrValue) { | |
switch (attrName) { | |
case ATTR_COLOR: | |
case ATTR_FG_COLOR: | |
return new ForegroundColorSpan(Color.parseColor(attrValue)); | |
case ATTR_BG_COLOR: | |
return new BackgroundColorSpan(Color.parseColor(attrValue)); | |
case ATTR_SIZE: | |
case ATTR_ABS_SIZE: | |
return new AbsoluteSizeSpan(Integer.parseInt(attrValue), true); | |
case ATTR_REL_SIZE: | |
return new RelativeSizeSpan(Float.parseFloat(attrValue)); | |
case ATTR_FONT_FAMILY: | |
return new TypefaceSpan(attrValue); | |
case ATTR_BLUR: | |
return makeBlur(); | |
case ATTR_EMBOSS: | |
return makeEmboss(); | |
case ATTR_SUPERSCRIPT: | |
return new SuperscriptSpan(); | |
case ATTR_SUBSCRIPT: | |
return new SubscriptSpan(); | |
default: | |
return null; | |
} | |
} | |
private Object makeBlur() { | |
return new MaskFilterSpan(new BlurMaskFilter( | |
getContext().getResources().getDisplayMetrics().density * 2, BlurMaskFilter.Blur.NORMAL)); | |
} | |
private Object makeEmboss() { | |
return new MaskFilterSpan(new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f)); | |
} | |
/** | |
* Intended to be available for a child class to change the default behavior | |
* By default this transformer does not support network calls as they need to be done outside the main thread | |
* | |
* @param url | |
* @return | |
*/ | |
protected boolean canProcess(final String url) { | |
return !url.startsWith("http"); | |
} | |
/** | |
* Intended to be available for a child class to change the default behavior | |
* By default this transformer does not support network calls as they need to be done outside the main thread | |
* | |
* @param url | |
* @return | |
*/ | |
protected String processUrl(final String url) { | |
return url; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment