@@ -7,8 +7,6 @@ import android.text.TextUtils
77import androidx.appcompat.content.res.AppCompatResources
88import org.wordpress.aztec.AztecAttributes
99import org.wordpress.aztec.AztecText
10- import org.wordpress.aztec.AztecText.OnImageTappedListener
11- import org.wordpress.aztec.AztecText.OnVideoTappedListener
1210import org.wordpress.aztec.AztecTextFormat
1311import org.wordpress.aztec.Constants
1412import org.wordpress.aztec.ITextFormat
@@ -19,10 +17,10 @@ import org.wordpress.aztec.spans.AztecImageSpan
1917import org.wordpress.aztec.spans.AztecMediaClickableSpan
2018import org.wordpress.aztec.spans.AztecMediaSpan
2119import org.wordpress.aztec.spans.AztecVideoSpan
20+ import org.wordpress.aztec.spans.IAztecBlockSpan
2221import org.wordpress.aztec.spans.IAztecNestable
2322import org.wordpress.aztec.watchers.EndOfBufferMarkerAdder
2423import org.xml.sax.Attributes
25- import java.util.ArrayList
2624
2725class LineBlockFormatter (editor : AztecText ) : AztecFormatter(editor) {
2826
@@ -94,12 +92,14 @@ class LineBlockFormatter(editor: AztecText) : AztecFormatter(editor) {
9492
9593 return false
9694 }
97-
98- fun applyHorizontalRule () {
99- editor.removeInlineStylesFromRange(selectionStart, selectionEnd)
100- editor.removeBlockStylesFromRange(selectionStart, selectionEnd, true )
101-
102- val nestingLevel = IAztecNestable .getNestingLevelAt(editableText, selectionStart)
95+ fun applyHorizontalRule (inline : Boolean ) {
96+ val nestingLevel = if (inline) {
97+ editor.removeInlineStylesFromRange(selectionStart, selectionEnd)
98+ editor.removeBlockStylesFromRange(selectionStart, selectionEnd, true )
99+ IAztecNestable .getNestingLevelAt(editableText, selectionStart)
100+ } else {
101+ 0
102+ }
103103
104104 val span = AztecHorizontalRuleSpan (
105105 editor.context,
@@ -112,34 +112,95 @@ class LineBlockFormatter(editor: AztecText) : AztecFormatter(editor) {
112112 val builder = SpannableStringBuilder (Constants .MAGIC_STRING )
113113 builder.setSpan(span, 0 , 1 , Spanned .SPAN_EXCLUSIVE_EXCLUSIVE )
114114
115- val start = selectionStart
116- editableText.replace(start, selectionEnd, builder)
117-
118- val newSelectionPosition = editableText.indexOf(Constants .MAGIC_CHAR , start) + 1
119- editor.setSelection(newSelectionPosition)
115+ if (inline) {
116+ editableText.replace(selectionStart, selectionEnd, builder)
117+ val newSelectionPosition = editableText.indexOf(Constants .MAGIC_CHAR , selectionStart) + 1
118+ editor.setSelection(newSelectionPosition)
119+ } else {
120+ builder.append(" \n " )
121+ insertSpanAfterBlock(builder)
122+ }
120123 }
121124
122- fun insertVideo (drawable : Drawable ? , attributes : Attributes , onVideoTappedListener : OnVideoTappedListener ? ,
125+ fun insertVideo (inline : Boolean , drawable : Drawable ? , attributes : Attributes , onVideoTappedListener : AztecText . OnVideoTappedListener ? ,
123126 onMediaDeletedListener : AztecText .OnMediaDeletedListener ? ) {
124- val nestingLevel = IAztecNestable .getNestingLevelAt(editableText, selectionStart)
127+ val nestingLevel = if (inline) IAztecNestable .getNestingLevelAt(editableText, selectionStart) else 0
125128 val span = AztecVideoSpan (editor.context, drawable, nestingLevel, AztecAttributes (attributes), onVideoTappedListener,
126129 onMediaDeletedListener, editor)
127- insertMedia(span)
130+ if (inline) {
131+ insertMediaInline(span)
132+ } else {
133+ insertMediaAfterBlock(span)
134+ }
128135 }
129136
130- fun insertImage (drawable : Drawable ? , attributes : Attributes , onImageTappedListener : OnImageTappedListener ? ,
137+ fun insertImage (inline : Boolean , drawable : Drawable ? , attributes : Attributes , onImageTappedListener : AztecText . OnImageTappedListener ? ,
131138 onMediaDeletedListener : AztecText .OnMediaDeletedListener ? ) {
132- val nestingLevel = IAztecNestable .getNestingLevelAt(editableText, selectionStart)
139+ val nestingLevel = if (inline) IAztecNestable .getNestingLevelAt(editableText, selectionStart) else 0
133140 val span = AztecImageSpan (editor.context, drawable, nestingLevel, AztecAttributes (attributes), onImageTappedListener,
134141 onMediaDeletedListener, editor)
135- insertMedia(span)
142+ if (inline) {
143+ insertMediaInline(span)
144+ } else {
145+ insertMediaAfterBlock(span)
146+ }
136147 }
137148
138- private fun insertMedia (span : AztecMediaSpan ) {
149+ private fun insertMediaInline (span : AztecMediaSpan ) {
139150 editor.removeInlineStylesFromRange(selectionStart, selectionEnd)
140151
141152 val ssb = SpannableStringBuilder (Constants .IMG_STRING )
142153
154+ buildClickableMediaSpan(ssb, span)
155+
156+ // We need to be sure the cursor is placed correctly after media insertion
157+ // Note that media has '\n' around them when needed
158+ val isLastItem = selectionEnd == EndOfBufferMarkerAdder .safeLength(editor)
159+ editableText.replace(selectionStart, selectionEnd, ssb)
160+
161+ setSelection(isLastItem, selectionEnd)
162+ }
163+
164+ private fun insertMediaAfterBlock (span : AztecMediaSpan ) {
165+ val ssb = SpannableStringBuilder (Constants .IMG_STRING )
166+ ssb.append(" \n " )
167+ buildClickableMediaSpan(ssb, span)
168+ insertSpanAfterBlock(ssb)
169+ }
170+
171+ private fun insertSpanAfterBlock (ssb : SpannableStringBuilder ) {
172+ val position = getEndOfBlock()
173+ // We need to be sure the cursor is placed correctly after media insertion
174+ // Note that media has '\n' around them when needed
175+ 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)
188+ }
189+ }
190+ setSelection(isLastItem, position)
191+ }
192+
193+ private fun setSelection (isLastItem : Boolean , position : Int ) {
194+ val newSelection = if (isLastItem) {
195+ EndOfBufferMarkerAdder .safeLength(editor)
196+ } else {
197+ if (position < EndOfBufferMarkerAdder .safeLength(editor)) position + 1 else position
198+ }
199+ editor.setSelection(newSelection)
200+ editor.isMediaAdded = true
201+ }
202+
203+ private fun buildClickableMediaSpan (ssb : SpannableStringBuilder , span : AztecMediaSpan ) {
143204 ssb.setSpan(
144205 span,
145206 0 ,
@@ -153,18 +214,16 @@ class LineBlockFormatter(editor: AztecText) : AztecFormatter(editor) {
153214 1 ,
154215 Spanned .SPAN_EXCLUSIVE_EXCLUSIVE
155216 )
217+ }
156218
157- // We need to be sure the cursor is placed correctly after media insertion
158- // Note that media has '\n' around them when needed
159- val isLastItem = selectionEnd == EndOfBufferMarkerAdder .safeLength(editor)
160- editableText.replace(selectionStart, selectionEnd, ssb)
161-
162- val newSelection = if (isLastItem) {
163- EndOfBufferMarkerAdder .safeLength(editor)
164- } else {
165- if (selectionEnd < EndOfBufferMarkerAdder .safeLength(editor)) selectionEnd + 1 else selectionEnd
219+ private fun getEndOfBlock (): Int {
220+ var position = 0
221+ editableText.getSpans(selectionStart, selectionEnd, IAztecBlockSpan ::class .java).forEach {
222+ val spanEnd = editableText.getSpanEnd(it)
223+ if (spanEnd > position) {
224+ position = spanEnd
225+ }
166226 }
167- editor.setSelection(newSelection)
168- editor.isMediaAdded = true
227+ return position
169228 }
170229}
0 commit comments