Skip to content

Commit 412af29

Browse files
authored
Merge pull request #976 from wordpress-mobile/fix/block-media-at-the-end-of-editable
Fix issues with block media at the end of editable text
2 parents e69dca9 + 655a87d commit 412af29

File tree

2 files changed

+169
-14
lines changed

2 files changed

+169
-14
lines changed

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

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ class LineBlockFormatter(editor: AztecText) : AztecFormatter(editor) {
9292

9393
return false
9494
}
95+
9596
fun applyHorizontalRule(inline: Boolean) {
9697
val nestingLevel = if (inline) {
9798
editor.removeInlineStylesFromRange(selectionStart, selectionEnd)
@@ -117,7 +118,6 @@ class LineBlockFormatter(editor: AztecText) : AztecFormatter(editor) {
117118
val newSelectionPosition = editableText.indexOf(Constants.MAGIC_CHAR, selectionStart) + 1
118119
editor.setSelection(newSelectionPosition)
119120
} else {
120-
builder.append("\n")
121121
insertSpanAfterBlock(builder)
122122
}
123123
}
@@ -163,7 +163,6 @@ class LineBlockFormatter(editor: AztecText) : AztecFormatter(editor) {
163163

164164
private fun insertMediaAfterBlock(span: AztecMediaSpan) {
165165
val ssb = SpannableStringBuilder(Constants.IMG_STRING)
166-
ssb.append("\n")
167166
buildClickableMediaSpan(ssb, span)
168167
insertSpanAfterBlock(ssb)
169168
}
@@ -173,23 +172,39 @@ class LineBlockFormatter(editor: AztecText) : AztecFormatter(editor) {
173172
// We need to be sure the cursor is placed correctly after media insertion
174173
// Note that media has '\n' around them when needed
175174
val isLastItem = position == EndOfBufferMarkerAdder.safeLength(editor)
176-
val insertedLength = ssb.length
177-
editableText.insert(position, ssb)
178-
val spans = editableText.getSpans(position, position + insertedLength, IAztecBlockSpan::class.java).filter {
179-
it !is AztecMediaSpan && editableText.getSpanStart(it) == position
180-
}
181-
spans.forEach {
182-
val spanStart = editableText.getSpanStart(it)
183-
val spanEnd = editableText.getSpanEnd(it)
184-
val spanFlags = editableText.getSpanFlags(it)
185-
editableText.removeSpan(it)
186-
if (spanStart + insertedLength < spanEnd) {
187-
editableText.setSpan(it, spanStart + insertedLength, spanEnd, spanFlags)
175+
if (isLastItem) {
176+
editableText.getSpans(position, editableText.length, IAztecBlockSpan::class.java).filter {
177+
it !is AztecMediaSpan && editableText.getSpanEnd(it) == editableText.length
178+
}.map {
179+
SpanData(it, editableText.getSpanStart(it), position + 1, editableText.getSpanFlags(it))
180+
}.applyWithRemovedSpans {
181+
editableText.append(ssb)
182+
}
183+
} else {
184+
ssb.append("\n")
185+
186+
val ssbLength = ssb.length
187+
editableText.getSpans(position, position + ssbLength, IAztecBlockSpan::class.java).filter {
188+
it !is AztecMediaSpan && editableText.getSpanStart(it) == position
189+
}.map {
190+
SpanData(it, editableText.getSpanStart(it) + ssbLength, editableText.getSpanEnd(it) + ssbLength, editableText.getSpanFlags(it))
191+
}.applyWithRemovedSpans {
192+
editableText.insert(position, ssb)
188193
}
189194
}
190195
setSelection(isLastItem, position)
191196
}
192197

198+
private fun List<SpanData>.applyWithRemovedSpans(action: () -> Unit) {
199+
this.onEach { editableText.removeSpan(it.span) }
200+
action()
201+
this.onEach {
202+
editableText.setSpan(it.span, it.spanStart, it.spanEnd, it.spanFlags)
203+
}
204+
}
205+
206+
data class SpanData(val span: IAztecBlockSpan, val spanStart: Int, val spanEnd: Int, val spanFlags: Int)
207+
193208
private fun setSelection(isLastItem: Boolean, position: Int) {
194209
val newSelection = if (isLastItem) {
195210
EndOfBufferMarkerAdder.safeLength(editor)
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package org.wordpress.aztec
2+
3+
import android.app.Activity
4+
import android.view.MenuItem
5+
import android.widget.PopupMenu
6+
import org.junit.Assert
7+
import org.junit.Before
8+
import org.junit.Test
9+
import org.junit.runner.RunWith
10+
import org.robolectric.Robolectric
11+
import org.robolectric.RobolectricTestRunner
12+
import org.robolectric.annotation.Config
13+
import org.wordpress.aztec.source.SourceViewEditText
14+
import org.wordpress.aztec.toolbar.AztecToolbar
15+
16+
@RunWith(RobolectricTestRunner::class)
17+
@Config(sdk = intArrayOf(23))
18+
class ImageBlockTest {
19+
lateinit var editText: AztecText
20+
lateinit var menuList: PopupMenu
21+
lateinit var menuListOrdered: MenuItem
22+
lateinit var menuListUnordered: MenuItem
23+
lateinit var sourceText: SourceViewEditText
24+
lateinit var toolbar: AztecToolbar
25+
26+
/**
27+
* Initialize variables.
28+
*/
29+
@Before
30+
fun init() {
31+
val activity = Robolectric.buildActivity(Activity::class.java).create().visible().get()
32+
editText = AztecText(activity)
33+
editText.setCalypsoMode(false)
34+
editText.addMediaAfterBlocks()
35+
sourceText = SourceViewEditText(activity)
36+
sourceText.setCalypsoMode(false)
37+
toolbar = AztecToolbar(activity)
38+
toolbar.setEditor(editText, sourceText)
39+
menuList = toolbar.getListMenu() as PopupMenu
40+
menuListOrdered = menuList.menu.getItem(1)
41+
menuListUnordered = menuList.menu.getItem(0)
42+
activity.setContentView(editText)
43+
}
44+
45+
@Test
46+
@Throws(Exception::class)
47+
fun addImageAfterAListAtTheEnd() {
48+
editText.fromHtml("<ul><li>item 1</li><li>item 2</li></ul>")
49+
50+
editText.setSelection(editText.editableText.indexOf("2"))
51+
val attributes = AztecAttributes()
52+
attributes.setValue("id", "1234")
53+
editText.insertImage(null, attributes)
54+
55+
Assert.assertEquals("<ul><li>item 1</li><li>item 2</li></ul><img id=\"1234\" />", editText.toHtml())
56+
}
57+
58+
@Test
59+
@Throws(Exception::class)
60+
fun addHRAfterAListAtTheEnd() {
61+
editText.fromHtml("<ul><li>item 1</li><li>item 2</li></ul>")
62+
63+
editText.setSelection(editText.editableText.indexOf("2"))
64+
editText.lineBlockFormatter.applyHorizontalRule(false)
65+
66+
Assert.assertEquals("<ul><li>item 1</li><li>item 2</li></ul><hr />", editText.toHtml())
67+
}
68+
69+
@Test
70+
@Throws(Exception::class)
71+
fun addImageAfterAListInTheMiddle() {
72+
editText.fromHtml("<ul><li>item 1</li><li>item 2</li></ul>\n<p>test</p>")
73+
74+
editText.setSelection(editText.editableText.indexOf("2"))
75+
val attributes = AztecAttributes()
76+
attributes.setValue("id", "1234")
77+
editText.insertImage(null, attributes)
78+
79+
Assert.assertEquals("<ul><li>item 1</li><li>item 2</li></ul><img id=\"1234\" /><p>test</p>", editText.toHtml())
80+
}
81+
82+
@Test
83+
@Throws(Exception::class)
84+
fun addHRAfterAListInTheMiddle() {
85+
editText.fromHtml("<ul><li>item 1</li><li>item 2</li></ul>\n<p>test</p>")
86+
87+
editText.setSelection(editText.editableText.indexOf("2"))
88+
editText.lineBlockFormatter.applyHorizontalRule(false)
89+
90+
Assert.assertEquals("<ul><li>item 1</li><li>item 2</li></ul><hr /><p>test</p>", editText.toHtml())
91+
}
92+
93+
@Test
94+
@Throws(Exception::class)
95+
fun addImageAfterHeadline() {
96+
editText.fromHtml("<h1>Headline 1</h1>")
97+
98+
editText.setSelection(editText.editableText.indexOf("1"))
99+
val attributes = AztecAttributes()
100+
attributes.setValue("id", "1234")
101+
editText.insertImage(null, attributes)
102+
103+
Assert.assertEquals("<h1>Headline 1</h1><img id=\"1234\" />", editText.toHtml())
104+
}
105+
106+
@Test
107+
@Throws(Exception::class)
108+
fun addHRAfterHeadline() {
109+
editText.fromHtml("<h1>Headline 1</h1>")
110+
111+
editText.setSelection(editText.editableText.indexOf("1"))
112+
editText.lineBlockFormatter.applyHorizontalRule(false)
113+
114+
Assert.assertEquals("<h1>Headline 1</h1><hr />", editText.toHtml())
115+
}
116+
117+
@Test
118+
@Throws(Exception::class)
119+
fun addImageBetweenHeadlines() {
120+
editText.fromHtml("<h1>Headline 1</h1><h2>Headline 2</h2>")
121+
122+
editText.setSelection(editText.editableText.indexOf("1"))
123+
val attributes = AztecAttributes()
124+
attributes.setValue("id", "1234")
125+
editText.insertImage(null, attributes)
126+
127+
Assert.assertEquals("<h1>Headline 1</h1><img id=\"1234\" /><h2>Headline 2</h2>", editText.toHtml())
128+
}
129+
130+
@Test
131+
@Throws(Exception::class)
132+
fun addHRBetweenHeadlines() {
133+
editText.fromHtml("<h1>Headline 1</h1><h2>Headline 2</h2>")
134+
135+
editText.setSelection(editText.editableText.indexOf("1"))
136+
editText.lineBlockFormatter.applyHorizontalRule(false)
137+
138+
Assert.assertEquals("<h1>Headline 1</h1><hr /><h2>Headline 2</h2>", editText.toHtml())
139+
}
140+
}

0 commit comments

Comments
 (0)