diff --git a/Aztec/Classes/TextKit/TextStorage.swift b/Aztec/Classes/TextKit/TextStorage.swift
index 2596bfda0..1d25aa39f 100644
--- a/Aztec/Classes/TextKit/TextStorage.swift
+++ b/Aztec/Classes/TextKit/TextStorage.swift
@@ -267,8 +267,15 @@ open class TextStorage: NSTextStorage {
edited([.editedAttributes, .editedCharacters], range: range, changeInLength: attrString.length - range.length)
- let invalidateRange = NSMakeRange(range.location, attrString.length)
- invalidateAttributes(in: invalidateRange)
+ // Whenever we're actually replacing text, let's trigger a `fixAttributes` call. This is done to prevent a glitch in which
+ // TextView may not render characters, in the same line, that carry partitioned attributes.
+ //
+ // Ref. https://github.com/wordpress-mobile/AztecEditor-iOS/issues/811
+ //
+ if range.length > 0 {
+ let invalidateRange = NSMakeRange(range.location, attrString.length)
+ invalidateAttributes(in: invalidateRange)
+ }
endEditing()
}
diff --git a/AztecTests/TextKit/TextStorageTests.swift b/AztecTests/TextKit/TextStorageTests.swift
index 65ccde7d0..bd985f8da 100644
--- a/AztecTests/TextKit/TextStorageTests.swift
+++ b/AztecTests/TextKit/TextStorageTests.swift
@@ -17,6 +17,11 @@ class TextStorageTests: XCTestCase {
///
var mockDelegate: MockAttachmentsDelegate!
+ /// Default Text Attributes
+ ///
+ let defaultAttributes: [NSAttributedStringKey: Any] = [.foregroundColor: UIColor.black,
+ .font: UIFont.systemFont(ofSize: 14),
+ .paragraphStyle: ParagraphStyle.default]
override func setUp() {
super.setUp()
@@ -162,10 +167,7 @@ class TextStorageTests: XCTestCase {
let updatedHTML = "
\(updatedHTML)
" - // Setup - let defaultAttributes: [AttributedStringKey: Any] = [.font: UIFont.systemFont(ofSize: 14), - .paragraphStyle: ParagraphStyle.default] - + // Setup storage.setHTML(initialHTML, defaultAttributes: defaultAttributes) // Find the Attachment @@ -381,7 +383,7 @@ class TextStorageTests: XCTestCase { let defaultAttributes: [AttributedStringKey: Any] = [.font: UIFont.systemFont(ofSize: 14), .paragraphStyle: ParagraphStyle.default] - + storage.setHTML(html, defaultAttributes: defaultAttributes) storage.replaceCharacters(in: NSRange(location: 0, length: 1), with: NSAttributedString(string: "")) @@ -389,4 +391,57 @@ class TextStorageTests: XCTestCase { XCTAssertEqual(String(), resultHTML) } + + /// This test verifies that, whenever a NSAttributedString is inserted inline (and has a different font), the ParagraphStyle + /// attribute will be 'fixed'. This translates into: there won't be different instances of ParagraphStyle for characters in the same line. + /// This has been tracked to be causing display issues when using the `Chinese (Simplified) Pinyin` keyboard. + /// + /// Reference: https://github.com/wordpress-mobile/AztecEditor-iOS/issues/811 + /// + func testAttributesAreFixedWheneverStringsWithDifferentAttributesAreInsertedOnTheSameLine() { + + /// Attributes + /// + let formatterH1 = HeaderFormatter(headerLevel: .h1) + let headerAttributes = formatterH1.apply(to: defaultAttributes, andStore: nil) + + /// Precondition: Newline at the top + /// + let newlineString = NSAttributedString(string: "\n", attributes: defaultAttributes) + + storage.replaceCharacters(in: .zero, with: newlineString) + + /// Insert + Replace: with H1 Attributes + /// + let insertionRange1 = NSRange(location: 1, length: 0) + let characterRange1 = NSRange(location: 1, length: 1) + + let chineseStringH1 = NSAttributedString(string: "上", attributes: headerAttributes) + let regularStringH1 = NSAttributedString(string: "s", attributes: headerAttributes) + + storage.replaceCharacters(in: insertionRange1, with: regularStringH1) + storage.replaceCharacters(in: characterRange1, with: chineseStringH1) + + /// After the two calls above, when typing, TextView will not relay properly apply the `H1` attributes. We'll simulate that: + /// + let chineseStringNormal = NSAttributedString(string: "上", attributes: defaultAttributes) + let regularStringNormal = NSAttributedString(string: "s", attributes: defaultAttributes) + + let insertionRange2 = NSRange(location: 2, length: 0) + let characterRange2 = NSRange(location: 2, length: 1) + + storage.replaceCharacters(in: insertionRange2, with: regularStringNormal) + storage.replaceCharacters(in: characterRange2, with: chineseStringNormal) + + /// Context: + /// storage.string at this point contains "\n上上" + /// + /// PROBLEM: + /// If characters 1 and 2 have different paragraphStyles, the second character may not get properly displayed by the TextView. + /// + let paragraphStyle1 = storage.attribute(.paragraphStyle, at: characterRange1.location, effectiveRange: nil) as! NSParagraphStyle + let paragraphStyle2 = storage.attribute(.paragraphStyle, at: characterRange2.location, effectiveRange: nil) as! NSParagraphStyle + + XCTAssertEqual(paragraphStyle1, paragraphStyle2) + } }