Skip to content

Commit 1e09b7d

Browse files
authored
Merge pull request #899 from wordpress-mobile/gutenberg_alignment
Update Heading, Preformat, and HiddenHtml Spans to allow view-level alignment
2 parents 6c08f3f + 49237c7 commit 1e09b7d

30 files changed

+575
-190
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## [1.3.42](https://github.com/wordpress-mobile/AztecEditor-Android/releases/tag/v1.3.42)
4+
### Changed
5+
- Update block-based span classes to allow view level alignment rendering (#899)
6+
37
## [1.3.41](https://github.com/wordpress-mobile/AztecEditor-Android/releases/tag/v1.3.41)
48
### Changed
59
- Add option to disable collapsing of whitespaces
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.wordpress.aztec
2+
3+
/**
4+
* With [SPAN_LEVEL] any alignment must be specified at the span level. Importantly, this
5+
* means that the View's gravity will always be ignored in determining the rendering of
6+
* the text's alignment.
7+
*
8+
* With [VIEW_LEVEL] alignment, the rendering of alignment is determined by the View's gravity.
9+
* Note that it is not possible to update the underlying alignment using [AztecText.toggleFormatting]
10+
* when you are using [VIEW_LEVEL] alignment rendering.
11+
*/
12+
enum class AlignmentRendering { SPAN_LEVEL, VIEW_LEVEL }

aztec/src/main/kotlin/org/wordpress/aztec/AztecParser.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ import java.util.ArrayList
5757
import java.util.Collections
5858
import java.util.Comparator
5959

60-
class AztecParser @JvmOverloads constructor(val plugins: List<IAztecPlugin> = listOf(),
60+
class AztecParser @JvmOverloads constructor(private val alignmentRendering: AlignmentRendering,
61+
val plugins: List<IAztecPlugin> = listOf(),
6162
private val ignoredTags: List<String> = listOf("body", "html")) {
6263
/**
6364
* A faster version of fromHtml(), intended for inspecting the span structure only. It doesn't prepare the text for
@@ -68,7 +69,7 @@ class AztecParser @JvmOverloads constructor(val plugins: List<IAztecPlugin> = li
6869
val tidySource = tidy(source)
6970

7071
val spanned = SpannableString(Html.fromHtml(tidySource,
71-
AztecTagHandler(context, plugins), context, plugins, ignoredTags, true))
72+
AztecTagHandler(context, plugins, alignmentRendering), context, plugins, ignoredTags, true))
7273

7374
postprocessSpans(spanned)
7475

@@ -82,7 +83,7 @@ class AztecParser @JvmOverloads constructor(val plugins: List<IAztecPlugin> = li
8283
val tidySource = if (shouldSkipTidying) source else tidy(source)
8384

8485
val spanned = SpannableStringBuilder(Html.fromHtml(tidySource,
85-
AztecTagHandler(context, plugins), context, plugins, ignoredTags, shouldIgnoreWhitespace))
86+
AztecTagHandler(context, plugins, alignmentRendering), context, plugins, ignoredTags, shouldIgnoreWhitespace))
8687

8788
addVisualNewlinesToBlockElements(spanned)
8889
markBlockElementsAsParagraphs(spanned)

aztec/src/main/kotlin/org/wordpress/aztec/AztecTagHandler.kt

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,28 +29,30 @@ import androidx.appcompat.content.res.AppCompatResources
2929
import org.wordpress.aztec.plugins.IAztecPlugin
3030
import org.wordpress.aztec.plugins.html2visual.IHtmlTagHandler
3131
import org.wordpress.aztec.spans.AztecAudioSpan
32-
import org.wordpress.aztec.spans.AztecHeadingSpan
3332
import org.wordpress.aztec.spans.AztecHorizontalRuleSpan
3433
import org.wordpress.aztec.spans.AztecImageSpan
35-
import org.wordpress.aztec.spans.AztecListItemSpan
3634
import org.wordpress.aztec.spans.AztecMediaClickableSpan
3735
import org.wordpress.aztec.spans.AztecMediaSpan
38-
import org.wordpress.aztec.spans.AztecOrderedListSpan
39-
import org.wordpress.aztec.spans.AztecPreformatSpan
40-
import org.wordpress.aztec.spans.AztecQuoteSpan
4136
import org.wordpress.aztec.spans.AztecStrikethroughSpan
42-
import org.wordpress.aztec.spans.AztecUnorderedListSpan
4337
import org.wordpress.aztec.spans.AztecVideoSpan
44-
import org.wordpress.aztec.spans.HiddenHtmlBlock
4538
import org.wordpress.aztec.spans.HiddenHtmlSpan
4639
import org.wordpress.aztec.spans.IAztecAttributedSpan
4740
import org.wordpress.aztec.spans.IAztecNestable
41+
import org.wordpress.aztec.spans.createAztecQuoteSpan
42+
import org.wordpress.aztec.spans.createHeadingSpan
43+
import org.wordpress.aztec.spans.createHiddenHtmlBlockSpan
44+
import org.wordpress.aztec.spans.createHiddenHtmlSpan
45+
import org.wordpress.aztec.spans.createListItemSpan
46+
import org.wordpress.aztec.spans.createOrderedListSpan
4847
import org.wordpress.aztec.spans.createParagraphSpan
48+
import org.wordpress.aztec.spans.createPreformatSpan
49+
import org.wordpress.aztec.spans.createUnorderedListSpan
4950
import org.wordpress.aztec.util.getLast
5051
import org.xml.sax.Attributes
5152
import java.util.ArrayList
5253

53-
class AztecTagHandler(val context: Context, val plugins: List<IAztecPlugin> = ArrayList()) : Html.TagHandler {
54+
class AztecTagHandler(val context: Context, val plugins: List<IAztecPlugin> = ArrayList(), private val alignmentRendering: AlignmentRendering
55+
) : Html.TagHandler {
5456
private val loadingDrawable: Drawable
5557

5658
// Simple LIFO stack to track the html tag nesting for easy reference when we need to handle the ending of a tag
@@ -72,31 +74,35 @@ class AztecTagHandler(val context: Context, val plugins: List<IAztecPlugin> = Ar
7274

7375
when (tag.toLowerCase()) {
7476
LIST_LI -> {
75-
handleElement(output, opening, AztecListItemSpan(nestingLevel, AztecAttributes(attributes)))
77+
val span = createListItemSpan(nestingLevel, alignmentRendering, AztecAttributes(attributes))
78+
handleElement(output, opening, span)
7679
return true
7780
}
7881
STRIKETHROUGH_S, STRIKETHROUGH_STRIKE, STRIKETHROUGH_DEL -> {
7982
handleElement(output, opening, AztecStrikethroughSpan(tag, AztecAttributes(attributes)))
8083
return true
8184
}
8285
SPAN -> {
83-
handleElement(output, opening, HiddenHtmlSpan(tag, AztecAttributes(attributes), nestingLevel))
86+
val span = createHiddenHtmlSpan(tag, AztecAttributes(attributes), nestingLevel, alignmentRendering)
87+
handleElement(output, opening, span)
8488
return true
8589
}
8690
DIV, FIGURE, FIGCAPTION, SECTION -> {
87-
handleElement(output, opening, HiddenHtmlBlock(tag, AztecAttributes(attributes), nestingLevel))
91+
val hiddenHtmlBlockSpan = createHiddenHtmlBlockSpan(tag, alignmentRendering, nestingLevel, AztecAttributes(attributes))
92+
handleElement(output, opening, hiddenHtmlBlockSpan)
8893
return true
8994
}
9095
LIST_UL -> {
91-
handleElement(output, opening, AztecUnorderedListSpan(nestingLevel, AztecAttributes(attributes)))
96+
handleElement(output, opening, createUnorderedListSpan(nestingLevel, alignmentRendering, AztecAttributes(attributes)))
9297
return true
9398
}
9499
LIST_OL -> {
95-
handleElement(output, opening, AztecOrderedListSpan(nestingLevel, AztecAttributes(attributes)))
100+
handleElement(output, opening, createOrderedListSpan(nestingLevel, alignmentRendering, AztecAttributes(attributes)))
96101
return true
97102
}
98103
BLOCKQUOTE -> {
99-
handleElement(output, opening, AztecQuoteSpan(nestingLevel, AztecAttributes(attributes)))
104+
val span = createAztecQuoteSpan(nestingLevel, AztecAttributes(attributes), alignmentRendering)
105+
handleElement(output, opening, span)
100106
return true
101107
}
102108
IMAGE -> {
@@ -118,7 +124,8 @@ class AztecTagHandler(val context: Context, val plugins: List<IAztecPlugin> = Ar
118124
return true
119125
}
120126
PARAGRAPH -> {
121-
handleElement(output, opening, createParagraphSpan(nestingLevel, AztecAttributes(attributes)))
127+
val paragraphSpan = createParagraphSpan(nestingLevel, alignmentRendering, AztecAttributes(attributes))
128+
handleElement(output, opening, paragraphSpan)
122129
return true
123130
}
124131
LINE -> {
@@ -133,12 +140,13 @@ class AztecTagHandler(val context: Context, val plugins: List<IAztecPlugin> = Ar
133140
return true
134141
}
135142
PREFORMAT -> {
136-
handleElement(output, opening, AztecPreformatSpan(nestingLevel, AztecAttributes(attributes)))
143+
val preformatSpan = createPreformatSpan(nestingLevel, alignmentRendering, AztecAttributes(attributes))
144+
handleElement(output, opening, preformatSpan)
137145
return true
138146
}
139147
else -> {
140148
if (tag.length == 2 && Character.toLowerCase(tag[0]) == 'h' && tag[1] >= '1' && tag[1] <= '6') {
141-
handleElement(output, opening, AztecHeadingSpan(nestingLevel, tag, AztecAttributes(attributes)))
149+
handleElement(output, opening, createHeadingSpan(nestingLevel, tag, AztecAttributes(attributes), alignmentRendering))
142150
return true
143151
}
144152
}

aztec/src/main/kotlin/org/wordpress/aztec/AztecText.kt

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
152152

153153
val DEFAULT_IMAGE_WIDTH = 800
154154

155+
val DEFAULT_ALIGNMENT_RENDERING = AlignmentRendering.SPAN_LEVEL
156+
155157
var watchersNestingLevel: Int = 0
156158

157159
private fun getPlaceholderDrawableFromResID(context: Context, @DrawableRes drawableId: Int, maxImageWidthForVisualEditor: Int): BitmapDrawable {
@@ -248,7 +250,8 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
248250
var commentsVisible = resources.getBoolean(R.bool.comments_visible)
249251

250252
var isInCalypsoMode = true
251-
var isInGutenbergMode = false
253+
var isInGutenbergMode: Boolean = false
254+
val alignmentRendering: AlignmentRendering
252255

253256
var consumeHistoryEvent: Boolean = false
254257

@@ -334,14 +337,22 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
334337
}
335338

336339
constructor(context: Context) : super(context) {
340+
alignmentRendering = DEFAULT_ALIGNMENT_RENDERING
341+
init(null)
342+
}
343+
344+
constructor(context: Context, alignmentRendering: AlignmentRendering) : super(context) {
345+
this.alignmentRendering = alignmentRendering
337346
init(null)
338347
}
339348

340349
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
350+
alignmentRendering = DEFAULT_ALIGNMENT_RENDERING
341351
init(attrs)
342352
}
343353

344354
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
355+
alignmentRendering = DEFAULT_ALIGNMENT_RENDERING
345356
init(attrs)
346357
}
347358

@@ -416,7 +427,8 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
416427
styles.getColor(R.styleable.AztecText_preformatBackground, 0),
417428
getPreformatBackgroundAlpha(styles),
418429
styles.getColor(R.styleable.AztecText_preformatColor, 0),
419-
verticalParagraphMargin)
430+
verticalParagraphMargin),
431+
alignmentRendering
420432
)
421433

422434
linkFormatter = LinkFormatter(this, LinkFormatter.LinkStyle(styles.getColor(
@@ -591,9 +603,9 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
591603
// will have the chance to run their "beforeTextChanged" and "onTextChanged" with the same string!
592604

593605
BlockElementWatcher(this)
594-
.add(HeadingHandler())
606+
.add(HeadingHandler(alignmentRendering))
595607
.add(ListHandler())
596-
.add(ListItemHandler())
608+
.add(ListItemHandler(alignmentRendering))
597609
.add(QuoteHandler())
598610
.add(PreformatHandler())
599611
.install(this)
@@ -1168,7 +1180,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
11681180

11691181
open fun fromHtml(source: String, isInit: Boolean = true) {
11701182
val builder = SpannableStringBuilder()
1171-
val parser = AztecParser(plugins)
1183+
val parser = AztecParser(alignmentRendering, plugins)
11721184

11731185
var cleanSource = CleaningUtils.cleanNestedBoldTags(source)
11741186
cleanSource = Format.removeSourceEditorFormatting(cleanSource, isInCalypsoMode, isInGutenbergMode)
@@ -1313,7 +1325,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
13131325
}
13141326

13151327
private fun parseHtml(content: Spannable, withCursorTag: Boolean): String {
1316-
val parser = AztecParser(plugins)
1328+
val parser = AztecParser(alignmentRendering, plugins)
13171329
val output: SpannableStringBuilder
13181330
try {
13191331
output = SpannableStringBuilder(content)
@@ -1559,7 +1571,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
15591571
// Convert selected text to html and add it to clipboard
15601572
fun copy(editable: Editable, start: Int, end: Int) {
15611573
val selectedText = editable.subSequence(start, end)
1562-
val parser = AztecParser(plugins)
1574+
val parser = AztecParser(alignmentRendering, plugins)
15631575
val output = SpannableStringBuilder(selectedText)
15641576

15651577
clearMetaSpans(output)
@@ -1625,7 +1637,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
16251637

16261638
if (clip.itemCount > 0) {
16271639
val textToPaste = if (asPlainText) clip.getItemAt(0).coerceToText(context).toString()
1628-
else clip.getItemAt(0).coerceToHtmlText(AztecParser(plugins))
1640+
else clip.getItemAt(0).coerceToHtmlText(AztecParser(alignmentRendering, plugins))
16291641

16301642
val oldHtml = toPlainHtml().replace("<aztec_cursor>", "")
16311643
val newHtml = oldHtml.replace(Constants.REPLACEMENT_MARKER_STRING, textToPaste + "<" + AztecCursorSpan.AZTEC_CURSOR_TAG + ">")
@@ -1743,7 +1755,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
17431755
val spanStart = text.getSpanStart(unknownHtmlSpan)
17441756

17451757
val textBuilder = SpannableStringBuilder()
1746-
textBuilder.append(AztecParser(plugins).fromHtml(source.getPureHtml(), context).trim())
1758+
textBuilder.append(AztecParser(alignmentRendering, plugins).fromHtml(source.getPureHtml(), context).trim())
17471759
setSelection(spanStart)
17481760

17491761
disableTextChangedListener()

0 commit comments

Comments
 (0)