Skip to content

Commit

Permalink
handle RTL languages properly (mainly the alignment left, center, right)
Browse files Browse the repository at this point in the history
  • Loading branch information
1gravity committed Dec 12, 2015
1 parent 2bafd03 commit 75696ee
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
import com.onegravity.rteditor.spans.RTSpan;
import com.onegravity.rteditor.utils.Constants;
import com.onegravity.rteditor.utils.Constants.MediaAction;
import com.onegravity.rteditor.utils.Helper;
import com.onegravity.rteditor.utils.Selection;

import java.net.MalformedURLException;
Expand Down Expand Up @@ -655,7 +656,8 @@ public void onSelectionChanged(RTEditText editor, int start, int end) {

// alignment (left, center, right)
if (alignments == null) {
toolbar.setAlignment(Layout.Alignment.ALIGN_NORMAL);
boolean isRTL = Helper.isRTL(editor.getText(), start, end);
toolbar.setAlignment(isRTL ? Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_NORMAL);
} else {
toolbar.setAlignments(alignments);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,13 @@
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.AlignmentSpan;
import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.QuoteSpan;
import android.text.style.RelativeSizeSpan;
import android.text.style.StrikethroughSpan;
import android.text.style.SubscriptSpan;
import android.text.style.SuperscriptSpan;
import com.onegravity.rteditor.spans.UnderlineSpan;

import com.onegravity.rteditor.api.RTMediaFactory;
import com.onegravity.rteditor.api.format.RTFormat;
Expand All @@ -44,14 +42,16 @@
import com.onegravity.rteditor.effects.LeadingMarginEffect;
import com.onegravity.rteditor.fonts.FontManager;
import com.onegravity.rteditor.fonts.RTTypeface;
import com.onegravity.rteditor.spans.AlignmentSpan;
import com.onegravity.rteditor.spans.BoldSpan;
import com.onegravity.rteditor.spans.BulletSpan;
import com.onegravity.rteditor.spans.TypefaceSpan;
import com.onegravity.rteditor.spans.ImageSpan;
import com.onegravity.rteditor.spans.IndentationSpan;
import com.onegravity.rteditor.spans.ItalicSpan;
import com.onegravity.rteditor.spans.LinkSpan;
import com.onegravity.rteditor.spans.NumberSpan;
import com.onegravity.rteditor.spans.TypefaceSpan;
import com.onegravity.rteditor.spans.UnderlineSpan;
import com.onegravity.rteditor.utils.Helper;

import org.xml.sax.Attributes;
Expand Down Expand Up @@ -381,17 +381,18 @@ private void endDiv() {

mResult.removeSpan(obj);
if (start != end) {
if (!checkDuplicateSpan(mResult, start, AlignmentSpan.Standard.class)) {
if (!checkDuplicateSpan(mResult, start, AlignmentSpan.class)) {
Div divObj = (Div) obj;
Layout.Alignment align = divObj.mAlign.equalsIgnoreCase("center") ? Layout.Alignment.ALIGN_CENTER :
divObj.mAlign.equalsIgnoreCase("right") ? Layout.Alignment.ALIGN_OPPOSITE : null;
divObj.mAlign.equalsIgnoreCase("right") ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_NORMAL;
if (align != null) {
if (mResult.charAt(end - 1) != '\n') {
// yes we need that linefeed, or we will get crashes
mResult.append('\n');
}
// use SPAN_EXCLUSIVE_EXCLUSIVE here, will be replaced later anyway when the cleanup function is called
mResult.setSpan(new AlignmentSpan.Standard(align), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
boolean isRTL = Helper.isRTL(mResult, start, end);
mResult.setSpan(new AlignmentSpan(align, isRTL), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
package com.onegravity.rteditor.converter;

import android.text.Layout;
import android.text.style.AlignmentSpan;
import android.text.style.ParagraphStyle;

import com.onegravity.rteditor.spans.AlignmentSpan;
import com.onegravity.rteditor.spans.BulletSpan;
import com.onegravity.rteditor.spans.IndentationSpan;
import com.onegravity.rteditor.spans.NumberSpan;
Expand All @@ -38,8 +38,8 @@ public enum ParagraphType {
INDENTATION_OL("<ol style='list-style-type:none;'>", "</ol>", "<li style='list-style-type:none;'>", "</li>", false, true);

public static ParagraphType getInstance(ParagraphStyle style) {
if (style instanceof AlignmentSpan.Standard) {
Layout.Alignment align = ((AlignmentSpan.Standard) style).getAlignment();
if (style instanceof AlignmentSpan) {
Layout.Alignment align = ((AlignmentSpan) style).getValue();
return align == Layout.Alignment.ALIGN_NORMAL ? ParagraphType.ALIGNMENT_LEFT :
align == Layout.Alignment.ALIGN_CENTER ? ParagraphType.ALIGNMENT_CENTER :
ParagraphType.ALIGNMENT_RIGHT;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.onegravity.rteditor.spans.AlignmentSpan;
import com.onegravity.rteditor.spans.ParagraphSpan;
import com.onegravity.rteditor.spans.RTSpan;
import com.onegravity.rteditor.utils.Helper;
import com.onegravity.rteditor.utils.Paragraph;
import com.onegravity.rteditor.utils.Selection;

Expand Down Expand Up @@ -77,10 +78,11 @@ public void applyToSelection(RTEditText editor, Selection selectedParagraphs, La

// if the paragraph is selected then we sure have an alignment
Alignment newAlignment = paragraph.isSelected(selectedParagraphs) ? alignment :
hasExistingSpans ? ((AlignmentSpan.Standard) existingSpans[0]).getAlignment() : null;
hasExistingSpans ? ((AlignmentSpan) existingSpans[0]).getValue() : null;

if (newAlignment != null) {
spans2Process.add(new ParagraphSpan(new AlignmentSpan.Standard(newAlignment), paragraph, false));
boolean isRTL = Helper.isRTL(str, paragraph.start(), paragraph.end());
spans2Process.add(new ParagraphSpan(new AlignmentSpan(newAlignment, isRTL), paragraph, false));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,30 @@
import android.os.Parcel;
import android.text.Layout;

import java.util.HashMap;
import java.util.Map;

/**
* Implementation for an alignment span (left, center, right alignment)
*/
public class AlignmentSpan extends android.text.style.AlignmentSpan.Standard implements RTSpan<Layout.Alignment> {

public AlignmentSpan(Layout.Alignment align) {
super(align);
/*
* Map alignment directions for RTL languages (Hebrew, Arabic etc.)
*/
private static Map<Layout.Alignment, Layout.Alignment> sRTLMapping = new HashMap<>();
static {
sRTLMapping.put(Layout.Alignment.ALIGN_CENTER, Layout.Alignment.ALIGN_CENTER);
sRTLMapping.put(Layout.Alignment.ALIGN_NORMAL, Layout.Alignment.ALIGN_OPPOSITE);
sRTLMapping.put(Layout.Alignment.ALIGN_OPPOSITE, Layout.Alignment.ALIGN_NORMAL);
}

private boolean mIsRTL;

public AlignmentSpan(Layout.Alignment align, boolean isRTL) {
super(isRTL ? sRTLMapping.get(align) : align);

mIsRTL = isRTL;
}

public AlignmentSpan(Parcel src) {
Expand All @@ -34,7 +51,8 @@ public AlignmentSpan(Parcel src) {

@Override
public Layout.Alignment getValue() {
return super.getAlignment();
Layout.Alignment align = getAlignment();
return mIsRTL ? sRTLMapping.get(align) : align;
}

}
42 changes: 42 additions & 0 deletions RTEditor/src/main/java/com/onegravity/rteditor/utils/Helper.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.Bidi;
import java.util.Locale;

/**
* Miscellaneous helper methods
Expand Down Expand Up @@ -126,4 +128,44 @@ public static String decodeQuery(String url) {

return url;
}

/**
* This method determines if the direction of a substring is right-to-left.
* If the string is empty that determination is based on the default system language determined
* by Locale.getDefault().
* The method can handle invalid substring definitions (start > end and similar cases), in which
* case the method returns False.
*
* @return True if the text direction is right-to-left, false otherwiese.
*/
public static boolean isRTL(CharSequence s, int start, int end) {
if (s.length() == 0) {
// empty string --> determine the direction from the default language
return isRTL(Locale.getDefault());
}

if (start == end) {
// if no character is selected we need to expand the selection
start = Math.max(0, --start);
if (start == end) {
end = Math.min(s.length(), ++end);
}

}

try {
Bidi bidi = new Bidi(s.subSequence(start, end).toString(), Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
return ! bidi.baseIsLeftToRight();
}
catch (IndexOutOfBoundsException e) {
return false;
}
}

private static boolean isRTL(Locale locale) {
int directionality = Character.getDirectionality(locale.getDisplayName().charAt(0));
return directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT ||
directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC;
}

}

0 comments on commit 75696ee

Please sign in to comment.