Skip to content

Commit d3988c7

Browse files
authored
Merge pull request #309 from wordpress-mobile/issue/258-fixing-missing-paragraphs
Issue/258 fixing missing paragraphs
2 parents 6944530 + f44e08e commit d3988c7

File tree

21 files changed

+733
-374
lines changed

21 files changed

+733
-374
lines changed

app/src/main/kotlin/org/wordpress/aztec/demo/MainActivity.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ class MainActivity : AppCompatActivity(),
8383
private val CODE = "<code>if (value == 5) printf(value)</code><br>"
8484
private val IMG = "<img src=\"https://cloud.githubusercontent.com/assets/3827611/21950131/3def4804-d9b5-11e6-88e6-d7d8864392e0.png\" />"
8585
private val EMOJI = "aaa&#x1F44D;&#x2764;ccc"
86+
87+
private val LONG_TEXT = "<br><br>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "
88+
8689
private val EXAMPLE =
8790
IMG +
8891
HEADING +
@@ -101,7 +104,8 @@ class MainActivity : AppCompatActivity(),
101104
COMMENT_PAGE +
102105
CODE +
103106
UNKNOWN +
104-
EMOJI
107+
EMOJI +
108+
LONG_TEXT
105109
}
106110

107111
private val MEDIA_CAMERA_PHOTO_PERMISSION_REQUEST_CODE: Int = 1001

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,8 @@ class AztecParser {
220220
}
221221

222222
if (spanned.getSpans(spanStart, spanStart, AztecSurroundedWithNewlines::class.java).any { before ->
223-
spanned.getSpanEnd(before) == spanStart }) {
223+
spanned.getSpanEnd(before) == spanStart
224+
}) {
224225
// the newline before us is the end of a previous block element so, return
225226
return@forEach
226227
}
@@ -283,14 +284,14 @@ class AztecParser {
283284
}
284285

285286
private fun withinHtml(out: StringBuilder, text: Spanned, start: Int, end: Int,
286-
grandParents: ArrayList<AztecNestable>?, nestingLevel: Int) {
287+
grandParents: ArrayList<AztecNestable>?, nestingLevel: Int) {
287288
var next: Int
288289
var i = start
289290
var parents: ArrayList<AztecNestable>?
290291

291292
do {
292293
val paragraphs = text.getSpans(i, end, AztecNestable::class.java)
293-
.filter{ it !is AztecFullWidthImageSpan}
294+
.filter { it !is AztecFullWidthImageSpan }
294295
.toTypedArray()
295296

296297
paragraphs.sortWith(Comparator { a, b ->
@@ -359,7 +360,7 @@ class AztecParser {
359360
}
360361

361362
private fun withinContent(out: StringBuilder, text: Spanned, start: Int, end: Int,
362-
parents: ArrayList<AztecNestable>?) {
363+
parents: ArrayList<AztecNestable>?) {
363364
var next: Int
364365

365366
var i = start
@@ -388,7 +389,7 @@ class AztecParser {
388389
// Copy from https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/text/Html.java,
389390
// remove some tag because we don't need them in Aztec.
390391
private fun withinParagraph(out: StringBuilder, text: Spanned, start: Int, end: Int, nl: Int,
391-
parents: ArrayList<AztecNestable>?) {
392+
parents: ArrayList<AztecNestable>?) {
392393
var next: Int
393394

394395
var i = start
@@ -453,14 +454,14 @@ class AztecParser {
453454
i = next
454455
}
455456

456-
for (i in 0..nl - 1) {
457-
val parentSharesEnd = parents?.any { text.getSpanEnd(it) == end + 1 + i } ?: false
457+
for (z in 0..nl - 1) {
458+
val parentSharesEnd = parents?.any {text.getSpanEnd(it) == end + 1 + z } ?: false
458459
if (parentSharesEnd) {
459460
continue
460461
}
461462

462463
out.append("<br>")
463-
consumeCursorIfInInput(out, text, end + i)
464+
consumeCursorIfInInput(out, text, end + z)
464465
}
465466
}
466467

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

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,14 @@ import android.text.Spannable
2828
import android.text.Spanned
2929
import org.wordpress.aztec.spans.*
3030
import org.xml.sax.Attributes
31-
import org.wordpress.aztec.AztecAttributes
3231

3332
class AztecTagHandler : Html.TagHandler {
3433

3534
private var order = 0
3635

3736
override fun handleTag(opening: Boolean, tag: String, output: Editable,
38-
onMediaTappedListener: AztecText.OnMediaTappedListener?, context: Context, attributes: Attributes,
39-
nestingLevel: Int): Boolean {
37+
onMediaTappedListener: AztecText.OnMediaTappedListener?, context: Context, attributes: Attributes,
38+
nestingLevel: Int): Boolean {
4039

4140
when (tag.toLowerCase()) {
4241
LIST_LI -> {
@@ -105,7 +104,7 @@ class AztecTagHandler : Html.TagHandler {
105104
}
106105

107106
private fun createImageSpan(attributes: AztecAttributes, onMediaTappedListener: AztecText.OnMediaTappedListener?,
108-
context: Context) : AztecMediaSpan {
107+
context: Context) : AztecMediaSpan {
109108
val styles = context.obtainStyledAttributes(R.styleable.AztecText)
110109
val loadingDrawable = ContextCompat.getDrawable(context, styles.getResourceId(R.styleable.AztecText_drawableLoading, R.drawable.ic_image_loading))
111110
styles.recycle()
@@ -186,10 +185,9 @@ class AztecTagHandler : Html.TagHandler {
186185
if (spans.isEmpty()) {
187186
return null
188187
} else {
189-
return (spans.size downTo 1)
190-
.firstOrNull { text.getSpanFlags(spans[it - 1]) == Spannable.SPAN_MARK_MARK && !(spans[it - 1] as HiddenHtmlSpan).isClosed }
191-
?.let { spans[it - 1] }
188+
spans.sortByDescending { it.startOrder }
189+
return spans.firstOrNull { text.getSpanFlags(it) == Spannable.SPAN_MARK_MARK && !(it as HiddenHtmlSpan).isClosed }
192190
}
193191
}
194192
}
195-
}
193+
}

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

Lines changed: 79 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ class AztecText : EditText, TextWatcher, UnknownHtmlSpan.OnUnknownHtmlClickListe
9292
private var isViewInitialized = false
9393
private var previousCursorPosition = 0
9494

95+
var isInCalypsoMode = true
96+
9597
private var unknownBlockSpanStart = -1
9698

9799
private var formatToolbar: AztecToolbar? = null
@@ -116,6 +118,8 @@ class AztecText : EditText, TextWatcher, UnknownHtmlSpan.OnUnknownHtmlClickListe
116118

117119
var widthMeasureSpec: Int = 0
118120

121+
var verticalParagraphMargin: Int = 0
122+
119123
interface OnSelectionChangedListener {
120124
fun onSelectionChanged(selStart: Int, selEnd: Int)
121125
}
@@ -140,6 +144,10 @@ class AztecText : EditText, TextWatcher, UnknownHtmlSpan.OnUnknownHtmlClickListe
140144
init(attrs)
141145
}
142146

147+
fun setCalypsoMode(isCompatibleWithCalypso: Boolean) {
148+
isInCalypsoMode = isCompatibleWithCalypso
149+
}
150+
143151
private fun init(attrs: AttributeSet?) {
144152
disableTextChangedListener()
145153

@@ -164,6 +172,8 @@ class AztecText : EditText, TextWatcher, UnknownHtmlSpan.OnUnknownHtmlClickListe
164172
historyEnable = styles.getBoolean(R.styleable.AztecText_historyEnable, historyEnable)
165173
historySize = styles.getInt(R.styleable.AztecText_historySize, historySize)
166174

175+
verticalParagraphMargin = styles.getDimensionPixelSize(R.styleable.AztecText_blockVerticalPadding, 0)
176+
167177
inlineFormatter = InlineFormatter(this,
168178
InlineFormatter.CodeStyle(
169179
styles.getColor(R.styleable.AztecText_codeBackground, 0),
@@ -176,18 +186,18 @@ class AztecText : EditText, TextWatcher, UnknownHtmlSpan.OnUnknownHtmlClickListe
176186
styles.getDimensionPixelSize(R.styleable.AztecText_bulletMargin, 0),
177187
styles.getDimensionPixelSize(R.styleable.AztecText_bulletPadding, 0),
178188
styles.getDimensionPixelSize(R.styleable.AztecText_bulletWidth, 0),
179-
styles.getDimensionPixelSize(R.styleable.AztecText_blockVerticalPadding, 0)),
189+
verticalParagraphMargin),
180190
BlockFormatter.QuoteStyle(
181191
styles.getColor(R.styleable.AztecText_quoteBackground, 0),
182192
styles.getColor(R.styleable.AztecText_quoteColor, 0),
183193
styles.getFraction(R.styleable.AztecText_quoteBackgroundAlpha, 1, 1, 0f),
184194
styles.getDimensionPixelSize(R.styleable.AztecText_quoteMargin, 0),
185195
styles.getDimensionPixelSize(R.styleable.AztecText_quotePadding, 0),
186196
styles.getDimensionPixelSize(R.styleable.AztecText_quoteWidth, 0),
187-
styles.getDimensionPixelSize(R.styleable.AztecText_blockVerticalPadding, 0)),
197+
verticalParagraphMargin),
188198
BlockFormatter.HeaderStyle(
189-
styles.getDimensionPixelSize(R.styleable.AztecText_blockVerticalPadding, 0))
190-
)
199+
verticalParagraphMargin)
200+
)
191201

192202
linkFormatter = LinkFormatter(this, LinkFormatter.LinkStyle(styles.getColor(
193203
R.styleable.AztecText_linkColor, 0),
@@ -236,6 +246,8 @@ class AztecText : EditText, TextWatcher, UnknownHtmlSpan.OnUnknownHtmlClickListe
236246
ParagraphCollapseAdjuster.install(this)
237247
ParagraphCollapseRemover.install(this)
238248

249+
EndOfParagraphMarkerAdder.install(this, verticalParagraphMargin)
250+
239251
InlineTextWatcher.install(inlineFormatter, this)
240252

241253
// NB: text change handler should not alter text before "afterTextChanged" is called otherwise not all watchers
@@ -625,7 +637,11 @@ class AztecText : EditText, TextWatcher, UnknownHtmlSpan.OnUnknownHtmlClickListe
625637
fun fromHtml(source: String) {
626638
val builder = SpannableStringBuilder()
627639
val parser = AztecParser()
628-
builder.append(parser.fromHtml(Format.clearFormatting(source), onMediaTappedListener, this, context))
640+
builder.append(parser.fromHtml(
641+
Format.removeSourceEditorFormatting(
642+
Format.addSourceEditorFormatting(source, isInCalypsoMode), isInCalypsoMode), onMediaTappedListener, this, context))
643+
644+
Format.preProcessSpannedText(builder, isInCalypsoMode)
629645

630646
switchToAztecStyle(builder, 0, builder.length)
631647
disableTextChangedListener()
@@ -679,7 +695,21 @@ class AztecText : EditText, TextWatcher, UnknownHtmlSpan.OnUnknownHtmlClickListe
679695
}
680696
}
681697

698+
//returns regular or "calypso" html depending on the mode
682699
fun toHtml(withCursorTag: Boolean = false): String {
700+
val html = toPlainHtml(withCursorTag)
701+
702+
if (isInCalypsoMode) {
703+
//calypso format is a mix of newline characters and html
704+
//paragraphs and line breaks are added on server, from newline characters
705+
return Format.addSourceEditorFormatting(html, true)
706+
} else {
707+
return html
708+
}
709+
}
710+
711+
//platform agnostic HTML
712+
fun toPlainHtml(withCursorTag: Boolean = false): String {
683713
val parser = AztecParser()
684714
val output = SpannableStringBuilder(text)
685715

@@ -688,21 +718,24 @@ class AztecText : EditText, TextWatcher, UnknownHtmlSpan.OnUnknownHtmlClickListe
688718
for (span in output.getSpans(0, output.length, AztecCursorSpan::class.java)) {
689719
output.removeSpan(span)
690720
}
691-
if (withCursorTag) {
721+
if (withCursorTag && !isInCalypsoMode) {
692722
output.setSpan(AztecCursorSpan(), selectionEnd, selectionEnd, Spanned.SPAN_MARK_MARK)
693723
}
694724

695725
parser.syncVisualNewlinesOfBlockElements(output)
696726

697-
return Format.clearFormatting(EndOfBufferMarkerAdder.removeEndOfTextMarker(parser.toHtml(output, withCursorTag)))
727+
Format.postProcessSpanedText(output, isInCalypsoMode)
728+
729+
return EndOfBufferMarkerAdder.removeEndOfTextMarker(parser.toHtml(output, withCursorTag))
698730
}
699731

700732
fun toFormattedHtml(): String {
701-
return Format.addFormatting(toHtml())
733+
return Format.addSourceEditorFormatting(toHtml(), isInCalypsoMode)
702734
}
703735

704736
private fun switchToAztecStyle(editable: Editable, start: Int, end: Int) {
705737
editable.getSpans(start, end, AztecBlockSpan::class.java).forEach { blockFormatter.setBlockStyle(it) }
738+
editable.getSpans(start, end, EndOfParagraphMarker::class.java).forEach { it.verticalPadding = verticalParagraphMargin }
706739

707740
val urlSpans = editable.getSpans(start, end, AztecURLSpan::class.java)
708741
for (span in urlSpans) {
@@ -791,7 +824,7 @@ class AztecText : EditText, TextWatcher, UnknownHtmlSpan.OnUnknownHtmlClickListe
791824
output.getSpans(0, output.length, ParagraphStyle::class.java).forEach { output.removeSpan(it) }
792825
clearMetaSpans(output)
793826
parser.syncVisualNewlinesOfBlockElements(output)
794-
val html = Format.clearFormatting(parser.toHtml(output))
827+
val html = Format.removeSourceEditorFormatting(parser.toHtml(output))
795828

796829
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager
797830
clipboard.primaryClip = ClipData.newPlainText(null, html)
@@ -808,7 +841,7 @@ class AztecText : EditText, TextWatcher, UnknownHtmlSpan.OnUnknownHtmlClickListe
808841
val textToPaste = clip.getItemAt(i).coerceToText(context)
809842

810843
val builder = SpannableStringBuilder()
811-
builder.append(parser.fromHtml(Format.clearFormatting(textToPaste.toString()), onMediaTappedListener,
844+
builder.append(parser.fromHtml(Format.removeSourceEditorFormatting(textToPaste.toString()), onMediaTappedListener,
812845
this, context).trim())
813846
Selection.setSelection(editable, max)
814847

@@ -977,20 +1010,20 @@ class AztecText : EditText, TextWatcher, UnknownHtmlSpan.OnUnknownHtmlClickListe
9771010

9781011
fun removeMedia(attributePredicate: AttributePredicate) {
9791012
text.getSpans(0, text.length, AztecMediaSpan::class.java)
980-
.filter {
981-
attributePredicate.matches(it.attributes)
982-
}
983-
.forEach {
984-
val start = text.getSpanStart(it)
985-
val end = text.getSpanEnd(it)
1013+
.filter {
1014+
attributePredicate.matches(it.attributes)
1015+
}
1016+
.forEach {
1017+
val start = text.getSpanStart(it)
1018+
val end = text.getSpanEnd(it)
9861019

987-
val clickableSpan = text.getSpans(start, end, AztecMediaClickableSpan::class.java).firstOrNull()
1020+
val clickableSpan = text.getSpans(start, end, AztecMediaClickableSpan::class.java).firstOrNull()
9881021

989-
text.removeSpan(clickableSpan)
990-
text.removeSpan(it)
1022+
text.removeSpan(clickableSpan)
1023+
text.removeSpan(it)
9911024

992-
text.delete(start, end)
993-
}
1025+
text.delete(start, end)
1026+
}
9941027
}
9951028

9961029
interface AttributePredicate {
@@ -1002,45 +1035,45 @@ class AztecText : EditText, TextWatcher, UnknownHtmlSpan.OnUnknownHtmlClickListe
10021035

10031036
fun updateElementAttributes(attributePredicate: AttributePredicate, attrs: AztecAttributes) {
10041037
text.getSpans(0, text.length, AztecAttributedSpan::class.java)
1005-
.filter {
1006-
attributePredicate.matches(it.attributes)
1007-
}
1008-
.firstOrNull()?.attributes = attrs
1038+
.filter {
1039+
attributePredicate.matches(it.attributes)
1040+
}
1041+
.firstOrNull()?.attributes = attrs
10091042
}
10101043

10111044
fun setOverlayLevel(attributePredicate: AttributePredicate, index: Int, level: Int) {
10121045
text.getSpans(0, text.length, AztecMediaSpan::class.java)
1013-
.filter {
1014-
attributePredicate.matches(it.attributes)
1015-
}
1016-
.forEach {
1017-
it.setOverayLevel(index, level)
1018-
}
1046+
.filter {
1047+
attributePredicate.matches(it.attributes)
1048+
}
1049+
.forEach {
1050+
it.setOverayLevel(index, level)
1051+
}
10191052
}
10201053

10211054
fun setOverlay(attributePredicate: AttributePredicate, index: Int, overlay: Drawable?, gravity: Int) {
10221055
text.getSpans(0, text.length, AztecMediaSpan::class.java)
1023-
.filter {
1024-
attributePredicate.matches(it.attributes)
1025-
}
1026-
.forEach {
1027-
// set the new overlay drawable
1028-
it.setOverlay(index, overlay, gravity)
1056+
.filter {
1057+
attributePredicate.matches(it.attributes)
1058+
}
1059+
.forEach {
1060+
// set the new overlay drawable
1061+
it.setOverlay(index, overlay, gravity)
10291062

1030-
invalidate()
1031-
}
1063+
invalidate()
1064+
}
10321065
}
10331066

10341067
fun clearOverlays(attributePredicate: AttributePredicate) {
10351068
text.getSpans(0, text.length, AztecMediaSpan::class.java)
1036-
.filter {
1037-
attributePredicate.matches(it.attributes)
1038-
}
1039-
.forEach {
1040-
it.clearOverlays()
1069+
.filter {
1070+
attributePredicate.matches(it.attributes)
1071+
}
1072+
.forEach {
1073+
it.clearOverlays()
10411074

1042-
invalidate()
1043-
}
1075+
invalidate()
1076+
}
10441077
}
10451078

10461079
fun getElementAttributes(attributePredicate: AttributePredicate): AztecAttributes {

aztec/src/main/kotlin/org/wordpress/aztec/formatting/InlineFormatter.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ package org.wordpress.aztec.formatting
33
import android.graphics.Typeface
44
import android.text.Spanned
55
import android.text.style.StyleSpan
6+
import org.wordpress.aztec.AztecAttributes
67
import org.wordpress.aztec.AztecPart
78
import org.wordpress.aztec.AztecText
89
import org.wordpress.aztec.TextFormat
910
import org.wordpress.aztec.spans.*
1011
import org.wordpress.aztec.watchers.TextChangedEvent
11-
import org.wordpress.aztec.AztecAttributes
1212
import java.util.*
1313

1414

@@ -405,4 +405,4 @@ class InlineFormatter(editor: AztecText, val codeStyle: CodeStyle) : AztecFormat
405405
}
406406
}
407407
}
408-
}
408+
}

0 commit comments

Comments
 (0)