Skip to content

Commit d2baefd

Browse files
authored
Merge pull request #887 from wordpress-mobile/feature/add-content-watcher-for-aztec-text
Add content watcher for aztec text
2 parents 4720b41 + 807062a commit d2baefd

File tree

3 files changed

+119
-0
lines changed

3 files changed

+119
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package org.wordpress.aztec
2+
3+
import java.lang.ref.WeakReference
4+
5+
class AztecContentChangeWatcher {
6+
private val observers = mutableListOf<WeakReference<AztecTextChangeObserver>>()
7+
fun registerObserver(observer: AztecTextChangeObserver) {
8+
if (observers.none { it.get() == observer }) {
9+
observers.add(WeakReference(observer))
10+
}
11+
}
12+
13+
fun unregisterObserver(observer: AztecTextChangeObserver) {
14+
observers.removeAll { it.get() == observer }
15+
}
16+
17+
internal fun notifyContentChanged() {
18+
val iterator = observers.iterator()
19+
while (iterator.hasNext()) {
20+
val item = iterator.next()
21+
val foundObserver = item.get()
22+
if (foundObserver == null) {
23+
iterator.remove()
24+
} else {
25+
foundObserver.onContentChanged()
26+
}
27+
}
28+
}
29+
30+
interface AztecTextChangeObserver {
31+
fun onContentChanged()
32+
}
33+
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,8 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
293293

294294
private var focusOnVisible = true
295295

296+
val contentChangeWatcher = AztecContentChangeWatcher()
297+
296298
interface OnSelectionChangedListener {
297299
fun onSelectionChanged(selStart: Int, selEnd: Int)
298300
}
@@ -497,6 +499,8 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
497499
// use HTML from the new text to set the state of the editText directly
498500
fromHtml(toFormattedHtml(newText), false)
499501

502+
contentChangeWatcher.notifyContentChanged()
503+
500504
// re-enable MediaDeleted listener
501505
enableMediaDeletedListener()
502506
// re-enable this very filter
@@ -565,6 +569,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
565569
setText("")
566570
enableTextChangedListener()
567571
}
572+
contentChangeWatcher.notifyContentChanged()
568573
}
569574
return wasStyleRemoved
570575
}
@@ -627,6 +632,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
627632
}
628633

629634
override fun afterTextChanged(text: Editable) {
635+
contentChangeWatcher.notifyContentChanged()
630636
if (isTextChangedListenerDisabled()) {
631637
return
632638
}
@@ -1024,6 +1030,8 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
10241030
.forEach { it.toggle() }
10251031
}
10261032
}
1033+
1034+
contentChangeWatcher.notifyContentChanged()
10271035
}
10281036

10291037
fun contains(format: ITextFormat, selStart: Int = selectionStart, selEnd: Int = selectionEnd): Boolean {
@@ -1128,10 +1136,12 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
11281136

11291137
fun redo() {
11301138
history.redo(this)
1139+
contentChangeWatcher.notifyContentChanged()
11311140
}
11321141

11331142
fun undo() {
11341143
history.undo(this)
1144+
contentChangeWatcher.notifyContentChanged()
11351145
}
11361146

11371147
// Helper ======================================================================================
@@ -1618,6 +1628,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
16181628
fromHtml(newHtml, false)
16191629
inlineFormatter.joinStyleSpans(0, length())
16201630
}
1631+
contentChangeWatcher.notifyContentChanged()
16211632
}
16221633
}
16231634

@@ -1643,6 +1654,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
16431654
} else {
16441655
linkFormatter.addLink(url, anchor, openInNewWindow, selectionStart, selectionEnd)
16451656
}
1657+
contentChangeWatcher.notifyContentChanged()
16461658
}
16471659

16481660
fun removeLink() {
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package org.wordpress.aztec
2+
3+
import org.junit.Assert.assertFalse
4+
import org.junit.Assert.assertTrue
5+
import org.junit.Before
6+
import org.junit.Test
7+
import org.junit.runner.RunWith
8+
import org.junit.runners.JUnit4
9+
10+
@RunWith(JUnit4::class)
11+
class AztecContentChangeWatcherTest {
12+
private lateinit var aztecContentChangeWatcher: AztecContentChangeWatcher
13+
@Before
14+
fun setUp() {
15+
aztecContentChangeWatcher = AztecContentChangeWatcher()
16+
}
17+
18+
@Test
19+
fun `notifies registered observer`() {
20+
// Given
21+
var contentChanged = false
22+
setupRegisteredObserver {
23+
contentChanged = true
24+
}
25+
26+
// When
27+
aztecContentChangeWatcher.notifyContentChanged()
28+
29+
// Then
30+
assertTrue(contentChanged)
31+
}
32+
33+
@Test
34+
fun `does not notify unregistered observer`() {
35+
// Given
36+
var contentChanged = false
37+
val observer = setupRegisteredObserver {
38+
contentChanged = true
39+
}
40+
41+
// When
42+
aztecContentChangeWatcher.unregisterObserver(observer)
43+
aztecContentChangeWatcher.notifyContentChanged()
44+
45+
// Then
46+
assertFalse(contentChanged)
47+
}
48+
49+
@Test
50+
fun `observer is garbage collected and reference is lost`() {
51+
// Given
52+
var contentChanged = false
53+
setupRegisteredObserver {
54+
contentChanged = true
55+
}
56+
System.gc()
57+
58+
// When
59+
aztecContentChangeWatcher.notifyContentChanged()
60+
61+
// Then
62+
assertFalse(contentChanged)
63+
}
64+
65+
private fun setupRegisteredObserver(onContentChanged: () -> Unit): AztecContentChangeWatcher.AztecTextChangeObserver {
66+
val observer = object : AztecContentChangeWatcher.AztecTextChangeObserver {
67+
override fun onContentChanged() {
68+
onContentChanged()
69+
}
70+
}
71+
aztecContentChangeWatcher.registerObserver(observer)
72+
return observer
73+
}
74+
}

0 commit comments

Comments
 (0)