diff --git a/Aztec/Classes/Formatters/AttributeFormatter.swift b/Aztec/Classes/Formatters/AttributeFormatter.swift index 0cd0abb76..ce818537c 100644 --- a/Aztec/Classes/Formatters/AttributeFormatter.swift +++ b/Aztec/Classes/Formatters/AttributeFormatter.swift @@ -64,6 +64,8 @@ protocol AttributeFormatter { func applicationRange(for range: NSRange, in text: NSAttributedString) -> NSRange func worksInEmptyRange() -> Bool + + func needsEmptyLinePlaceholder() -> Bool } @@ -118,7 +120,7 @@ extension AttributeFormatter { @discardableResult func applyAttributes(to text: NSMutableAttributedString, at range: NSRange) -> NSRange { var rangeToApply = applicationRange(for: range, in: text) - if worksInEmptyRange() && ( rangeToApply.length == 0 || text.length == 0) { + if needsEmptyLinePlaceholder() && worksInEmptyRange() && ( rangeToApply.length == 0 || text.length == 0) { let placeholder = placeholderForEmptyLine(using: placeholderAttributes) text.insert(placeholder, at: rangeToApply.location) rangeToApply = NSMakeRange(rangeToApply.location, placeholder.length) @@ -210,6 +212,10 @@ extension CharacterAttributeFormatter { func worksInEmptyRange() -> Bool { return false } + + func needsEmptyLinePlaceholder() -> Bool { + return false + } } @@ -227,4 +233,8 @@ extension ParagraphAttributeFormatter { func worksInEmptyRange() -> Bool { return true } + + func needsEmptyLinePlaceholder() -> Bool { + return true + } } diff --git a/Aztec/Classes/Formatters/HeaderFormatter.swift b/Aztec/Classes/Formatters/HeaderFormatter.swift index a08db0cbe..5e9d302c2 100644 --- a/Aztec/Classes/Formatters/HeaderFormatter.swift +++ b/Aztec/Classes/Formatters/HeaderFormatter.swift @@ -97,5 +97,9 @@ open class HeaderFormatter: ParagraphAttributeFormatter { } return false } + + func needsEmptyLinePlaceholder() -> Bool { + return false + } } diff --git a/Aztec/Classes/TextKit/TextView.swift b/Aztec/Classes/TextKit/TextView.swift index 694807fd9..1b968cf7e 100644 --- a/Aztec/Classes/TextKit/TextView.swift +++ b/Aztec/Classes/TextKit/TextView.swift @@ -803,8 +803,8 @@ open class TextView: UITextView { } for formatter in formattersThatBreakAfterEnter { - if formatter.present(in: textStorage, at: range.location) { - formatter.removeAttributes(from: textStorage, at: range) + if formatter.present(in: typingAttributes) { + typingAttributes = formatter.remove(from: typingAttributes) return true } } @@ -833,8 +833,10 @@ open class TextView: UITextView { DispatchQueue.main.asyncAfter(deadline: .now() + delay) { let pristine = self.selectedRange let updated = NSMakeRange(max(pristine.location - 1, 0), 0) + let beforeTypingAttributes = self.typingAttributes self.selectedRange = updated self.selectedRange = pristine + self.typingAttributes = beforeTypingAttributes } } diff --git a/AztecTests/TextViewTests.swift b/AztecTests/TextViewTests.swift index 794746d70..cffd40eb0 100644 --- a/AztecTests/TextViewTests.swift +++ b/AztecTests/TextViewTests.swift @@ -652,4 +652,31 @@ class AztecVisualTextViewTests: XCTestCase { XCTAssertEqual(textView.getHTML(), "

Header

") } + + + /// Tests that there is no HTML Corruption when editing text, after toggling H1 and entering two lines of text. + /// + /// Input: + /// - "Header\n12" (Inserted character by character) + /// - Delete Backwards event. + /// + /// Ref. https://github.com/wordpress-mobile/WordPress-Aztec-iOS/issues/407 + /// + func testDeletingBackwardAfterTogglingHeaderDoesNotTriggerInvalidHTML() { + let textView = createTextView(withHTML: "") + + textView.toggleHeader(.h1, range: .zero) + textView.insertText("H") + textView.insertText("e") + textView.insertText("a") + textView.insertText("d") + textView.insertText("e") + textView.insertText("r") + textView.insertText("\n") + textView.insertText("1") + textView.insertText("2") + textView.deleteBackward() + + XCTAssertEqual(textView.getHTML(), "

Header

1") + } }