Skip to content

Commit aa7f3f5

Browse files
authored
Merge pull request #291 from wordpress-mobile/issue/289-multiple-headings
Different headings in consecutive lines
2 parents c8bbee9 + a30168b commit aa7f3f5

File tree

2 files changed

+49
-32
lines changed

2 files changed

+49
-32
lines changed

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

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,8 @@ class BlockFormatter(editor: AztecText, val listStyle: ListStyle, val quoteStyle
317317
if (numberOfLines == numberOfLinesWithSpanApplied) {
318318
removeBlockStyle(blockElementType)
319319
} else {
320-
applyBlock(blockElementType, startOfBlock + 1,
321-
(if (endOfBlock == editableText.length) endOfBlock else endOfBlock + 1), nestingLevel)
320+
applyBlock(makeBlockSpan(blockElementType, nestingLevel), startOfBlock + 1,
321+
(if (endOfBlock == editableText.length) endOfBlock else endOfBlock + 1))
322322
}
323323

324324
} else {
@@ -327,31 +327,39 @@ class BlockFormatter(editor: AztecText, val listStyle: ListStyle, val quoteStyle
327327
val startOfLine = boundsOfSelectedText.start
328328
val endOfLine = boundsOfSelectedText.endInclusive
329329

330-
val spanToApply = getOuterBlockSpanType(blockElementType)
330+
val nestingLevel = AztecNestable.getNestingLevelAt(editableText, start) + 1
331+
332+
val spanToApply = makeBlockSpan(blockElementType, nestingLevel)
331333

332334
var startOfBlock: Int = startOfLine
333335
var endOfBlock: Int = endOfLine
334336

335337

336338
if (startOfLine != 0) {
337-
val spansOnPreviousLine = editableText.getSpans(startOfLine - 1, startOfLine - 1, spanToApply).firstOrNull()
338-
if (spansOnPreviousLine != null) {
339+
val spansOnPreviousLine = editableText.getSpans(startOfLine - 1, startOfLine - 1, spanToApply.javaClass)
340+
.firstOrNull()
341+
// if same span type is found (also check for heading style equality if a heading) extend the start
342+
if (spansOnPreviousLine != null
343+
&& (spansOnPreviousLine !is AztecHeadingSpan
344+
|| spansOnPreviousLine.heading == (spanToApply as AztecHeadingSpan).heading)) {
339345
startOfBlock = editableText.getSpanStart(spansOnPreviousLine)
340346
liftBlock(blockElementType, startOfBlock, endOfBlock)
341347
}
342348
}
343349

344350
if (endOfLine != editableText.length) {
345-
val spanOnNextLine = editableText.getSpans(endOfLine + 1, endOfLine + 1, spanToApply).firstOrNull()
346-
if (spanOnNextLine != null) {
351+
val spanOnNextLine = editableText.getSpans(endOfLine + 1, endOfLine + 1, spanToApply.javaClass)
352+
.firstOrNull()
353+
// if same span type is found (also check for heading style equality if a heading) extend the end
354+
if (spanOnNextLine != null
355+
&& (spanOnNextLine !is AztecHeadingSpan
356+
|| spanOnNextLine.heading == (spanToApply as AztecHeadingSpan).heading)) {
347357
endOfBlock = editableText.getSpanEnd(spanOnNextLine)
348358
liftBlock(blockElementType, startOfBlock, endOfBlock)
349359
}
350360
}
351361

352-
val nestingLevel = AztecNestable.getNestingLevelAt(editableText, start) + 1
353-
354-
applyBlock(blockElementType, startOfBlock, endOfBlock, nestingLevel)
362+
applyBlock(spanToApply, startOfBlock, endOfBlock)
355363

356364
//if the line was empty trigger onSelectionChanged manually to update toolbar buttons status
357365
// if (isEmptyLine) {
@@ -360,22 +368,17 @@ class BlockFormatter(editor: AztecText, val listStyle: ListStyle, val quoteStyle
360368
}
361369
}
362370

363-
private fun applyBlock(textFormat: TextFormat, start: Int, end: Int, nestingLevel: Int, attrs: String = "") {
364-
when (textFormat) {
365-
TextFormat.FORMAT_ORDERED_LIST -> applyListBlock(AztecOrderedListSpan(nestingLevel, attrs, listStyle), start, end, nestingLevel)
366-
TextFormat.FORMAT_UNORDERED_LIST -> applyListBlock(AztecUnorderedListSpan(nestingLevel, attrs, listStyle), start, end, nestingLevel)
367-
TextFormat.FORMAT_QUOTE -> BlockHandler.set(editableText, AztecQuoteSpan(nestingLevel, attrs, quoteStyle), start, end)
368-
TextFormat.FORMAT_HEADING_1,
369-
TextFormat.FORMAT_HEADING_2,
370-
TextFormat.FORMAT_HEADING_3,
371-
TextFormat.FORMAT_HEADING_4,
372-
TextFormat.FORMAT_HEADING_5,
373-
TextFormat.FORMAT_HEADING_6 -> applyHeadingBlock(AztecHeadingSpan(nestingLevel, textFormat, attrs, headerStyle), start, end, nestingLevel)
374-
else -> editableText.setSpan(ParagraphSpan(nestingLevel, attrs), start, end, Spanned.SPAN_PARAGRAPH)
371+
private fun applyBlock(blockSpan: AztecBlockSpan, start: Int, end: Int) {
372+
when (blockSpan) {
373+
is AztecOrderedListSpan -> applyListBlock(blockSpan, start, end)
374+
is AztecUnorderedListSpan -> applyListBlock(blockSpan, start, end)
375+
is AztecQuoteSpan -> BlockHandler.set(editableText, blockSpan, start, end)
376+
is AztecHeadingSpan -> applyHeadingBlock(blockSpan, start, end)
377+
else -> editableText.setSpan(blockSpan, start, end, Spanned.SPAN_PARAGRAPH)
375378
}
376379
}
377380

378-
private fun applyListBlock(listSpan: AztecListSpan, start: Int, end: Int, nestingLevel: Int) {
381+
private fun applyListBlock(listSpan: AztecListSpan, start: Int, end: Int) {
379382
BlockHandler.set(editableText, listSpan, start, end)
380383

381384
val lines = TextUtils.split(editableText.substring(start, end), "\n")
@@ -389,23 +392,22 @@ class BlockFormatter(editor: AztecText, val listStyle: ListStyle, val quoteStyle
389392

390393
if (lineLength == 0) continue
391394

392-
ListItemHandler.newListItem(editableText, start + lineStart, start + lineEnd, nestingLevel + 1)
395+
ListItemHandler.newListItem(editableText, start + lineStart, start + lineEnd, listSpan.nestingLevel + 1)
393396
}
394397
}
395398

396-
private fun applyHeadingBlock(headingSpan: AztecHeadingSpan, start: Int, end: Int, nestingLevel: Int) {
399+
private fun applyHeadingBlock(headingSpan: AztecHeadingSpan, start: Int, end: Int) {
397400
val lines = TextUtils.split(editableText.substring(start, end), "\n")
398401
for (i in lines.indices) {
399-
val lineLength = lines[i].length
402+
val splitLength = lines[i].length
400403

401-
val lineStart = (0..i - 1).sumBy { lines[it].length + 1 }
402-
val lineEnd = (lineStart + lineLength).let {
403-
if ((start + it) != editableText.length) it + 1 else it // include the newline or not
404-
}
404+
val lineStart = start + (0..i - 1).sumBy { lines[it].length + 1 }
405+
val lineEnd = Math.min(lineStart + splitLength + 1, end) // +1 to include the newline
405406

407+
val lineLength = lineEnd - lineStart
406408
if (lineLength == 0) continue
407409

408-
HeadingHandler.cloneHeading(editableText, headingSpan, start + lineStart, start + lineEnd)
410+
HeadingHandler.cloneHeading(editableText, headingSpan, lineStart, lineEnd)
409411
}
410412
}
411413

aztec/src/test/kotlin/org/wordpress/aztec/HeadingTest.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,4 +247,19 @@ class HeadingTest() {
247247
editText.text.delete(l - 1, l)
248248
Assert.assertEquals("<h1></h1>", editText.toHtml())
249249
}
250-
}
250+
251+
@Test
252+
@Throws(Exception::class)
253+
fun addHeading_issue289() {
254+
editText.fromHtml("<h1>Heading 1</h1>")
255+
256+
safeAppend(editText, "\n")
257+
258+
editText.setSelection(safeLength(editText))
259+
editText.toggleFormatting(TextFormat.FORMAT_HEADING_2)
260+
Assert.assertEquals("<h1>Heading 1</h1><h2></h2>", editText.toHtml())
261+
262+
safeAppend(editText, "Heading 2")
263+
Assert.assertEquals("<h1>Heading 1</h1><h2>Heading 2</h2>", editText.toHtml())
264+
}
265+
}

0 commit comments

Comments
 (0)