@@ -85,7 +85,8 @@ class BlockFormatter(editor: AztecText, val listStyle: ListStyle, val quoteStyle
8585 }
8686 }
8787 }
88- else -> { }
88+ else -> {
89+ }
8990 }
9091 }
9192
@@ -130,8 +131,11 @@ class BlockFormatter(editor: AztecText, val listStyle: ListStyle, val quoteStyle
130131 var end = originalEnd
131132
132133 // if splitting block set a range that would be excluded from it
133- val boundsOfSelectedText = if (ignoreLineBounds) IntRange (start, end)
134- else getSelectedTextBounds(editableText, start, end)
134+ val boundsOfSelectedText = if (ignoreLineBounds) {
135+ IntRange (start, end)
136+ } else {
137+ getSelectedTextBounds(editableText, start, end)
138+ }
135139
136140 var startOfBounds = boundsOfSelectedText.start
137141 var endOfBounds = boundsOfSelectedText.endInclusive
@@ -182,7 +186,16 @@ class BlockFormatter(editor: AztecText, val listStyle: ListStyle, val quoteStyle
182186 }
183187
184188 spanTypes.forEach { spanType ->
185- val spans = editableText.getSpans(start, end, spanType)
189+ // when removing style from multiple selected lines, if the last selected line is empty
190+ // or at the end of editor the selection wont include the trailing newline/EOB marker
191+ // that will leave us with orphan <li> tag, so we need to shift index to the right
192+ val hasLingeringEmptyListItem = spanType.isAssignableFrom(AztecListItemSpan ::class .java)
193+ && editableText.length > end
194+ && (editableText[end] == ' \n ' || editableText[end] == Constants .END_OF_BUFFER_MARKER )
195+
196+ val endModifier = if (hasLingeringEmptyListItem) 1 else 0
197+
198+ val spans = editableText.getSpans(start, end + endModifier, spanType)
186199 spans.forEach { span ->
187200
188201 val spanStart = editableText.getSpanStart(span)
@@ -299,7 +312,9 @@ class BlockFormatter(editor: AztecText, val listStyle: ListStyle, val quoteStyle
299312 }
300313 } else {
301314 if (indexOfLastLineBreak == - 1 ) {
302- indexOfFirstLineBreak = editable.lastIndexOf(" \n " , selectionStart) + 1
315+ indexOfFirstLineBreak = if (selectionStart == 0 ) 0 else {
316+ editable.lastIndexOf(" \n " , selectionStart) + 1
317+ }
303318 } else {
304319 indexOfFirstLineBreak = editable.lastIndexOf(" \n " , selectionStart)
305320 }
@@ -342,7 +357,9 @@ class BlockFormatter(editor: AztecText, val listStyle: ListStyle, val quoteStyle
342357 if (numberOfLines == numberOfLinesWithSpanApplied) {
343358 removeBlockStyle(blockElementType)
344359 } else {
345- applyBlock(makeBlockSpan(blockElementType, nestingLevel), startOfBlock + 1 ,
360+ // if block starts with newline do not move index to the right
361+ val startOfBlockModifier = if (startOfBlock >= 0 && editableText[startOfBlock] == ' \n ' ) 0 else 1
362+ applyBlock(makeBlockSpan(blockElementType, nestingLevel), startOfBlock + startOfBlockModifier,
346363 (if (endOfBlock == editableText.length) endOfBlock else endOfBlock + 1 ))
347364 }
348365 } else {
@@ -412,20 +429,29 @@ class BlockFormatter(editor: AztecText, val listStyle: ListStyle, val quoteStyle
412429
413430 private fun applyListBlock (listSpan : AztecListSpan , start : Int , end : Int ) {
414431 BlockHandler .set(editableText, listSpan, start, end)
432+ // special case for styling single empty lines
433+ if (end - start == 1 && (editableText[end - 1 ] == ' \n ' || editableText[end - 1 ] == Constants .END_OF_BUFFER_MARKER )) {
434+ ListItemHandler .newListItem(editableText, start, end, listSpan.nestingLevel + 1 )
435+ } else {
436+ // there is always something at the end (newline or EOB), so we shift end index to the left
437+ // to avoid empty lines
438+ val listContent = editableText.substring(start, end - 1 )
415439
416- val lines = TextUtils .split(editableText.substring(start, end) , " \n " )
417- for (i in lines.indices) {
418- val lineLength = lines[i].length
440+ val lines = TextUtils .split(listContent , " \n " )
441+ for (i in lines.indices) {
442+ val lineLength = lines[i].length
419443
420- val lineStart = (0 .. i - 1 ).sumBy { lines[it].length + 1 }
421- val lineEnd = (lineStart + lineLength).let {
422- if ((start + it) != editableText.length) it + 1 else it // include the newline or not
423- }
444+ val lineStart = (0 .. i - 1 ).sumBy { lines[it].length + 1 }
424445
425- if (lineLength == 0 ) continue
446+ val lineEnd = (lineStart + lineLength).let {
447+ if ((start + it) != editableText.length) it + 1 else it // include the newline or not
448+ }
426449
427- ListItemHandler .newListItem(editableText, start + lineStart, start + lineEnd, listSpan.nestingLevel + 1 )
450+ ListItemHandler .newListItem(editableText, start + lineStart, start + lineEnd, listSpan.nestingLevel + 1 )
451+ }
428452 }
453+
454+
429455 }
430456
431457 private fun applyHeadingBlock (headingSpan : AztecHeadingSpan , start : Int , end : Int ) {
@@ -624,6 +650,7 @@ class BlockFormatter(editor: AztecText, val listStyle: ListStyle, val quoteStyle
624650 return false
625651 }
626652
653+
627654 fun containsOtherHeadings (textFormat : ITextFormat , selStart : Int = selectionStart, selEnd : Int = selectionEnd): Boolean {
628655 arrayOf(AztecTextFormat .FORMAT_HEADING_1 ,
629656 AztecTextFormat .FORMAT_HEADING_2 ,
@@ -632,12 +659,12 @@ class BlockFormatter(editor: AztecText, val listStyle: ListStyle, val quoteStyle
632659 AztecTextFormat .FORMAT_HEADING_5 ,
633660 AztecTextFormat .FORMAT_HEADING_6 ,
634661 AztecTextFormat .FORMAT_PREFORMAT )
635- .filter { it != textFormat }
636- .forEach {
637- if (containsHeading(it, selStart, selEnd)) {
638- return true
662+ .filter { it != textFormat }
663+ .forEach {
664+ if (containsHeading(it, selStart, selEnd)) {
665+ return true
666+ }
639667 }
640- }
641668
642669 return false
643670 }
@@ -651,7 +678,7 @@ class BlockFormatter(editor: AztecText, val listStyle: ListStyle, val quoteStyle
651678 AztecTextFormat .FORMAT_HEADING_5 ,
652679 AztecTextFormat .FORMAT_HEADING_6 ,
653680 AztecTextFormat .FORMAT_PREFORMAT )
654- .filter { it != textFormat }
681+ .filter { it != textFormat }
655682
656683 return containsHeading(textFormat, selStart, selEnd) && otherHeadings.none { containsHeading(it, selStart, selEnd) }
657684 }
0 commit comments