Skip to content

Commit a006f2f

Browse files
Merge pull request #1203 from wordpress-mobile/issue/fix_crash_on_toogle_quotes
Issue/fix crash on toggle quotes
2 parents 4080dba + 7cf6a49 commit a006f2f

3 files changed

Lines changed: 32 additions & 4 deletions

File tree

Aztec/Classes/Extensions/NSMutableAttributedString+ReplaceOcurrences.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,19 @@ extension NSMutableAttributedString {
3232

3333
assert(!replacementString.contains(stringToFind),
3434
"Allowing the replacement string to contain the original string would result in a ininite loop.")
35-
36-
let swiftUTF16Range = string.utf16.range(from: range)
35+
let rangeDifference = (replacementString as NSString).length - (stringToFind as NSString).length
36+
var swiftUTF16Range = string.utf16.range(from: range)
3737
var swiftRange = string.range(from: swiftUTF16Range)
38-
3938
while let matchRange = string.range(of: stringToFind, options: [], range: swiftRange, locale: nil) {
4039
let matchNSRange = string.utf16NSRange(from: matchRange)
4140

4241
replaceCharacters(in: matchNSRange, with: replacementString)
4342

4443
// Since the new string may invalidate the initial swift range, we want to update it.
45-
swiftRange = swiftRange.lowerBound ..< string.index(matchRange.lowerBound, offsetBy: replacementString.count)
44+
// And because the string that backs the NSAttributeString will change after the replace we need to recalculate the index from scratch
45+
let updatedRange = range.extendedRight(by: rangeDifference)
46+
swiftUTF16Range = string.utf16.range(from: updatedRange)
47+
swiftRange = string.range(from: swiftUTF16Range)
4648
}
4749
}
4850
}

AztecTests/Extensions/NSMutableAttributedStringReplaceOcurrencesTests.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,14 @@ class NSMutableAttributedStringReplaceOcurrencesTests: XCTestCase {
8888

8989
XCTAssertEqual(newAttrString, NSAttributedString(string: "🌎💚💚😬💚🌎"))
9090
}
91+
92+
/// Tests that replacing ocurrences on the end of a range work correctly
93+
///
94+
func testReplaceOcurrencesThatAreOnEndOfRange() {
95+
let attrString = NSAttributedString(string: "Hello"+String(.paragraphSeparator)+"Amazing"+String(.paragraphSeparator)+"World"+String(.paragraphSeparator))
96+
let newAttrString = NSMutableAttributedString(attributedString: attrString)
97+
newAttrString.replaceOcurrences(of: String(.paragraphSeparator), with: String(.lineFeed), within: NSRange(location:6, length: 8))
98+
99+
XCTAssertEqual(newAttrString, NSAttributedString(string: "Hello"+String(.paragraphSeparator)+"Amazing"+String(.lineFeed)+"World"+String(.paragraphSeparator)))
100+
}
91101
}

AztecTests/TextKit/TextViewTests.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,6 +1254,22 @@ class TextViewTests: XCTestCase {
12541254
XCTAssertEqual(textView.text, Constants.sampleText0 + Constants.sampleText1 + String(.lineFeed) + String(.lineFeed))
12551255
}
12561256

1257+
/// Verifies that toggling a Blockquote paragraph in the middle of paragraph does not crash system.
1258+
///
1259+
func testTogglingBlockquoteOnMiddleOfRangeDoesNotCrash() {
1260+
let initialQuote = """
1261+
<blockquote><strong>Quote One</strong></blockquote>
1262+
<blockquote><strong>Quote Two</strong></blockquote>
1263+
<blockquote><strong>Quote Three</strong></blockquote>
1264+
"""
1265+
let textView = TextViewStub(withHTML: initialQuote)
1266+
1267+
textView.selectedTextRange = textView.textRange(from: textView.endOfDocument, to: textView.endOfDocument)
1268+
textView.toggleBlockquote(range: NSRange(location: 11, length: 0))
1269+
1270+
XCTAssertEqual(textView.text, "Quote One" + String(.paragraphSeparator)+"Quote Two"+String(.lineFeed)+"Quote Three")
1271+
}
1272+
12571273

12581274
// MARK: - Pre
12591275

0 commit comments

Comments
 (0)