From 657af29e7de43c0918fc6e02d7877f9e64c3b2c8 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 4 Sep 2017 10:53:05 -0300 Subject: [PATCH 01/11] LayoutManager: Style Cleanup --- Aztec/Classes/TextKit/LayoutManager.swift | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Aztec/Classes/TextKit/LayoutManager.swift b/Aztec/Classes/TextKit/LayoutManager.swift index 62b04f2a2..7ac53553c 100644 --- a/Aztec/Classes/TextKit/LayoutManager.swift +++ b/Aztec/Classes/TextKit/LayoutManager.swift @@ -48,26 +48,32 @@ private extension LayoutManager { } let characterRange = self.characterRange(forGlyphRange: glyphsToShow, actualGlyphRange: nil) - //draw blockquotes - textStorage.enumerateAttribute(NSParagraphStyleAttributeName, in: characterRange, options: []){ (object, range, stop) in + + // Draw blockquotes + textStorage.enumerateAttribute(NSParagraphStyleAttributeName, in: characterRange, options: []) { (object, range, stop) in guard let paragraphStyle = object as? ParagraphStyle, !paragraphStyle.blockquotes.isEmpty else { return } - let blockquoteIndent = paragraphStyle.blockquoteIndent + let blockquoteIndent = paragraphStyle.blockquoteIndent let blockquoteGlyphRange = glyphRange(forCharacterRange: range, actualCharacterRange: nil) enumerateLineFragments(forGlyphRange: blockquoteGlyphRange) { (rect, usedRect, textContainer, glyphRange, stop) in let paddingWidth = blockquoteIndent + (blockquoteIndent == 0 ? 0 : (Metrics.listTextIndentation / 2)) var paddingHeight: CGFloat = blockquoteIndent == 0 ? 0 : (Metrics.paragraphSpacing / 2) + // Cheking if we this a middle line inside a blockquote paragraph let lineRange = self.characterRange(forGlyphRange: glyphRange, actualGlyphRange: nil) let lineCharacters = textStorage.attributedSubstring(from: lineRange).string if !lineCharacters.isEndOfLine(before: lineCharacters.endIndex) { paddingHeight = 0 } + let lineRect = rect.offsetBy(dx: origin.x , dy: origin.y) - let finalRect = CGRect(x: lineRect.origin.x + paddingWidth, y: lineRect.origin.y, width: lineRect.size.width - paddingWidth, height: lineRect.size.height - (paddingHeight*2)) + let finalRect = CGRect(x: lineRect.origin.x + paddingWidth, + y: lineRect.origin.y, + width: lineRect.size.width - paddingWidth, + height: lineRect.size.height - (paddingHeight * 2)) self.drawBlockquote(in: finalRect.integral, with: context) } } From e85ede2be634959bf5f9fb51b1bb81471514725c Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 4 Sep 2017 13:40:52 -0300 Subject: [PATCH 02/11] LayoutManager + Blockquotes: Handling Line Separators --- .../Classes/Extensions/String+EndOfLine.swift | 18 ++++++++++++++++++ Aztec/Classes/TextKit/LayoutManager.swift | 4 +++- AztecTests/StringEndOfLineTests.swift | 18 ++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/Aztec/Classes/Extensions/String+EndOfLine.swift b/Aztec/Classes/Extensions/String+EndOfLine.swift index 9b9a3a4b4..da6eec6c5 100644 --- a/Aztec/Classes/Extensions/String+EndOfLine.swift +++ b/Aztec/Classes/Extensions/String+EndOfLine.swift @@ -81,6 +81,24 @@ extension String { return isEndOfLine(at: index) } + /// Checks if the current string ends with (any) of the specified Characters. + /// + /// - Parameters: + /// - characterNamed: Array of Characters to be checked against. + /// + func ends(with characterNamed: [Character.Name]) -> Bool { + guard !isEmpty else { + return false + } + + let previousIndex = index(before: endIndex) + let lastIndex = index(after: previousIndex) + let endingString = substring(with: previousIndex ..< lastIndex) + + let characters = characterNamed.map { String($0) } + return characters.contains(endingString) + } + /// Checks if the location passed is the beggining of a new line. /// /// - Parameters: diff --git a/Aztec/Classes/TextKit/LayoutManager.swift b/Aztec/Classes/TextKit/LayoutManager.swift index 7ac53553c..b01b781ce 100644 --- a/Aztec/Classes/TextKit/LayoutManager.swift +++ b/Aztec/Classes/TextKit/LayoutManager.swift @@ -65,7 +65,8 @@ private extension LayoutManager { // Cheking if we this a middle line inside a blockquote paragraph let lineRange = self.characterRange(forGlyphRange: glyphRange, actualGlyphRange: nil) let lineCharacters = textStorage.attributedSubstring(from: lineRange).string - if !lineCharacters.isEndOfLine(before: lineCharacters.endIndex) { + + if !lineCharacters.ends(with: [.carriageReturn, .lineFeed, .paragraphSeparator]) { paddingHeight = 0 } @@ -74,6 +75,7 @@ private extension LayoutManager { y: lineRect.origin.y, width: lineRect.size.width - paddingWidth, height: lineRect.size.height - (paddingHeight * 2)) + self.drawBlockquote(in: finalRect.integral, with: context) } } diff --git a/AztecTests/StringEndOfLineTests.swift b/AztecTests/StringEndOfLineTests.swift index c88835232..28c953cc3 100644 --- a/AztecTests/StringEndOfLineTests.swift +++ b/AztecTests/StringEndOfLineTests.swift @@ -205,4 +205,22 @@ class StringEndOfLineTests: XCTestCase { XCTAssertFalse(string.isStartOfNewLine(at: index)) } } + + func testEndsWithCarriageReturnEffectivelyReturnsTrueWheneverTestStringEndsWithCarriageReturn() { + let test = "something\u{000D}" + + XCTAssert(test.ends(with: [.carriageReturn])) + } + + func testEndsWithCarriageReturnReturnsFalseWheneverTestStringDoesNotEndWithCarriageReturn() { + let test = "something" + + XCTAssertFalse(test.ends(with: [.carriageReturn])) + } + + func testEndsWithDoesNotCrashOnEmptyString() { + let empty = "" + + XCTAssertNoThrow(empty.ends(with: [.carriageReturn]), "") + } } From c730370070317618ae1f539496e6ba17fe2eab09 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 4 Sep 2017 16:05:32 -0300 Subject: [PATCH 03/11] LayoutManager: Tunning height padding --- Aztec/Classes/TextKit/LayoutManager.swift | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Aztec/Classes/TextKit/LayoutManager.swift b/Aztec/Classes/TextKit/LayoutManager.swift index b01b781ce..e6d7af662 100644 --- a/Aztec/Classes/TextKit/LayoutManager.swift +++ b/Aztec/Classes/TextKit/LayoutManager.swift @@ -66,7 +66,7 @@ private extension LayoutManager { let lineRange = self.characterRange(forGlyphRange: glyphRange, actualGlyphRange: nil) let lineCharacters = textStorage.attributedSubstring(from: lineRange).string - if !lineCharacters.ends(with: [.carriageReturn, .lineFeed, .paragraphSeparator]) { + if lineCharacters.ends(with: [.lineSeparator]) { paddingHeight = 0 } @@ -74,7 +74,7 @@ private extension LayoutManager { let finalRect = CGRect(x: lineRect.origin.x + paddingWidth, y: lineRect.origin.y, width: lineRect.size.width - paddingWidth, - height: lineRect.size.height - (paddingHeight * 2)) + height: lineRect.size.height - paddingHeight) self.drawBlockquote(in: finalRect.integral, with: context) } @@ -151,8 +151,9 @@ private extension LayoutManager { guard textStorage.string.isStartOfNewLine(atUTF16Offset: enclosingRange.location), let paragraphStyle = textStorage.attribute(NSParagraphStyleAttributeName, at: enclosingRange.location, effectiveRange: nil) as? ParagraphStyle, - let list = paragraphStyle.lists.last else { - return + let list = paragraphStyle.lists.last + else { + return } let glyphRange = self.glyphRange(forCharacterRange: enclosingRange, actualCharacterRange: nil) @@ -164,12 +165,11 @@ private extension LayoutManager { let markerNumber = textStorage.itemNumber(in: list, at: enclosingRange.location) - self.drawItem( - number: markerNumber, - in: lineFragmentRectWithOffset, - from: list, - using: paragraphStyle, - at: enclosingRange.location) + self.drawItem(number: markerNumber, + in: lineFragmentRectWithOffset, + from: list, + using: paragraphStyle, + at: enclosingRange.location) } } From 9313c7eab721e610a0321fbfdc6014a5bb9dffd9 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 4 Sep 2017 16:37:11 -0300 Subject: [PATCH 04/11] String+EndOfLine: Simplifies Helper --- Aztec/Classes/Extensions/String+EndOfLine.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Aztec/Classes/Extensions/String+EndOfLine.swift b/Aztec/Classes/Extensions/String+EndOfLine.swift index da6eec6c5..866256694 100644 --- a/Aztec/Classes/Extensions/String+EndOfLine.swift +++ b/Aztec/Classes/Extensions/String+EndOfLine.swift @@ -91,9 +91,7 @@ extension String { return false } - let previousIndex = index(before: endIndex) - let lastIndex = index(after: previousIndex) - let endingString = substring(with: previousIndex ..< lastIndex) + let endingString = substring(with: index(before: endIndex) ..< endIndex) let characters = characterNamed.map { String($0) } return characters.contains(endingString) From 4be148e2392174c119e8603688bc9899c1167a26 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 4 Sep 2017 17:09:34 -0300 Subject: [PATCH 05/11] LayoutManager: Fixing MarkerItem Layout --- Aztec/Classes/TextKit/LayoutManager.swift | 41 +++++++++++++++++------ 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/Aztec/Classes/TextKit/LayoutManager.swift b/Aztec/Classes/TextKit/LayoutManager.swift index e6d7af662..3ddb54204 100644 --- a/Aztec/Classes/TextKit/LayoutManager.swift +++ b/Aztec/Classes/TextKit/LayoutManager.swift @@ -157,20 +157,39 @@ private extension LayoutManager { } let glyphRange = self.glyphRange(forCharacterRange: enclosingRange, actualCharacterRange: nil) - - // Since only the first line in a paragraph can have a bullet, we only need the first line fragment. - // - let lineFragmentRect = self.lineFragmentRect(forGlyphAt: glyphRange.location, effectiveRange: nil) - let lineFragmentRectWithOffset = lineFragmentRect.offsetBy(dx: origin.x, dy: origin.y) - + let markerRect = rectForItem(range: glyphRange, origin: origin, paragraphStyle: paragraphStyle) let markerNumber = textStorage.itemNumber(in: list, at: enclosingRange.location) - self.drawItem(number: markerNumber, - in: lineFragmentRectWithOffset, - from: list, - using: paragraphStyle, - at: enclosingRange.location) + drawItem(number: markerNumber, in: markerRect, from: list, using: paragraphStyle, at: enclosingRange.location) + } + } + + /// Returns the Rect for the MarkerItem at the specified Range + Origin, within a given ParagraphStyle. + /// + /// - Parameters: + /// - range: List Item's Range + /// - origin: List Origin + /// - paragraphStyle: Container Style + /// + /// - Returns: CGRect in which we should render the MarkerItem. + /// + private func rectForItem(range: NSRange, origin: CGPoint, paragraphStyle: ParagraphStyle) -> CGRect { + var paddingY = CGFloat(0) + var effectiveLineRange = NSRange.zero + + // Since only the first line in a paragraph can have a bullet, we only need the first line fragment. + let lineFragmentRect = self.lineFragmentRect(forGlyphAt: range.location, effectiveRange: &effectiveLineRange) + + // Whenever we're rendering an Item with multiple lines, within a Blockquote, we need to account for the + // paragraph spacing. Otherwise the Marker will show up slightly off. + // + // Ref. #645 + // + if effectiveLineRange.length < range.length && paragraphStyle.blockquotes.isEmpty == false { + paddingY = Metrics.paragraphSpacing } + + return lineFragmentRect.offsetBy(dx: origin.x, dy: origin.y + paddingY) } From 7e16598509ce6a80ca37f7194539855cb355a041 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 4 Sep 2017 17:46:51 -0300 Subject: [PATCH 06/11] String+EndOfLine: Implements isEndOfParagraph Helper --- Aztec/Classes/Extensions/String+EndOfLine.swift | 14 ++++++++------ Aztec/Classes/TextKit/LayoutManager.swift | 2 +- AztecTests/StringEndOfLineTests.swift | 8 ++++---- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Aztec/Classes/Extensions/String+EndOfLine.swift b/Aztec/Classes/Extensions/String+EndOfLine.swift index 866256694..4a9e761aa 100644 --- a/Aztec/Classes/Extensions/String+EndOfLine.swift +++ b/Aztec/Classes/Extensions/String+EndOfLine.swift @@ -81,20 +81,22 @@ extension String { return isEndOfLine(at: index) } - /// Checks if the current string ends with (any) of the specified Characters. + /// This methods verifies if the receiver string contains an End of Paragraph at the specified index. /// /// - Parameters: - /// - characterNamed: Array of Characters to be checked against. + /// - index: the index to check + /// + /// - Returns: `true` if the receiver contains an end-of-paragraph character at the specified Index. /// - func ends(with characterNamed: [Character.Name]) -> Bool { + func isEndOfParagraph(at index: String.Index) -> Bool { guard !isEmpty else { return false } - let endingString = substring(with: index(before: endIndex) ..< endIndex) + let endingString = substring(with: self.index(before: index) ..< index) + let paragraphSeparators = [String(.carriageReturn), String(.lineFeed), String(.paragraphSeparator)] - let characters = characterNamed.map { String($0) } - return characters.contains(endingString) + return paragraphSeparators.contains(endingString) } /// Checks if the location passed is the beggining of a new line. diff --git a/Aztec/Classes/TextKit/LayoutManager.swift b/Aztec/Classes/TextKit/LayoutManager.swift index 3ddb54204..d889b968e 100644 --- a/Aztec/Classes/TextKit/LayoutManager.swift +++ b/Aztec/Classes/TextKit/LayoutManager.swift @@ -66,7 +66,7 @@ private extension LayoutManager { let lineRange = self.characterRange(forGlyphRange: glyphRange, actualGlyphRange: nil) let lineCharacters = textStorage.attributedSubstring(from: lineRange).string - if lineCharacters.ends(with: [.lineSeparator]) { + if lineCharacters.isEndOfParagraph(at: lineCharacters.endIndex) { paddingHeight = 0 } diff --git a/AztecTests/StringEndOfLineTests.swift b/AztecTests/StringEndOfLineTests.swift index 28c953cc3..4dbba9110 100644 --- a/AztecTests/StringEndOfLineTests.swift +++ b/AztecTests/StringEndOfLineTests.swift @@ -209,18 +209,18 @@ class StringEndOfLineTests: XCTestCase { func testEndsWithCarriageReturnEffectivelyReturnsTrueWheneverTestStringEndsWithCarriageReturn() { let test = "something\u{000D}" - XCTAssert(test.ends(with: [.carriageReturn])) + XCTAssert(test.isEndOfParagraph(at: test.endIndex)) } func testEndsWithCarriageReturnReturnsFalseWheneverTestStringDoesNotEndWithCarriageReturn() { let test = "something" - XCTAssertFalse(test.ends(with: [.carriageReturn])) + XCTAssertFalse(test.isEndOfParagraph(at: test.endIndex)) } func testEndsWithDoesNotCrashOnEmptyString() { - let empty = "" + let test = "" - XCTAssertNoThrow(empty.ends(with: [.carriageReturn]), "") + XCTAssertNoThrow(test.isEndOfParagraph(at: test.endIndex), "") } } From f2f15657fadf9e94909fe2ad235726b16b162429 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Tue, 5 Sep 2017 12:49:34 -0300 Subject: [PATCH 07/11] LayoutManager: Updating logic --- Aztec/Classes/TextKit/LayoutManager.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Aztec/Classes/TextKit/LayoutManager.swift b/Aztec/Classes/TextKit/LayoutManager.swift index d889b968e..433be0583 100644 --- a/Aztec/Classes/TextKit/LayoutManager.swift +++ b/Aztec/Classes/TextKit/LayoutManager.swift @@ -62,11 +62,15 @@ private extension LayoutManager { let paddingWidth = blockquoteIndent + (blockquoteIndent == 0 ? 0 : (Metrics.listTextIndentation / 2)) var paddingHeight: CGFloat = blockquoteIndent == 0 ? 0 : (Metrics.paragraphSpacing / 2) - // Cheking if we this a middle line inside a blockquote paragraph + // Cheking if we this a middle line inside a blockquote paragraph: + // Avoid applying the "Padding Height", otherwise we might cut off the Blockquote's BG. + // + // Ref. Issue #645 + // let lineRange = self.characterRange(forGlyphRange: glyphRange, actualGlyphRange: nil) let lineCharacters = textStorage.attributedSubstring(from: lineRange).string - if lineCharacters.isEndOfParagraph(at: lineCharacters.endIndex) { + if !lineCharacters.isEndOfParagraph(at: lineCharacters.endIndex) { paddingHeight = 0 } From 2e1b060849654835b61c263b9c31dbbae674c69a Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Tue, 5 Sep 2017 17:28:50 -0300 Subject: [PATCH 08/11] Implements String+EndOfParagraph --- .../Classes/Extensions/String+EndOfLine.swift | 18 ------------ .../Extensions/String+EndOfParagraph.swift | 28 +++++++++++++++++++ 2 files changed, 28 insertions(+), 18 deletions(-) create mode 100644 Aztec/Classes/Extensions/String+EndOfParagraph.swift diff --git a/Aztec/Classes/Extensions/String+EndOfLine.swift b/Aztec/Classes/Extensions/String+EndOfLine.swift index 4a9e761aa..9b9a3a4b4 100644 --- a/Aztec/Classes/Extensions/String+EndOfLine.swift +++ b/Aztec/Classes/Extensions/String+EndOfLine.swift @@ -81,24 +81,6 @@ extension String { return isEndOfLine(at: index) } - /// This methods verifies if the receiver string contains an End of Paragraph at the specified index. - /// - /// - Parameters: - /// - index: the index to check - /// - /// - Returns: `true` if the receiver contains an end-of-paragraph character at the specified Index. - /// - func isEndOfParagraph(at index: String.Index) -> Bool { - guard !isEmpty else { - return false - } - - let endingString = substring(with: self.index(before: index) ..< index) - let paragraphSeparators = [String(.carriageReturn), String(.lineFeed), String(.paragraphSeparator)] - - return paragraphSeparators.contains(endingString) - } - /// Checks if the location passed is the beggining of a new line. /// /// - Parameters: diff --git a/Aztec/Classes/Extensions/String+EndOfParagraph.swift b/Aztec/Classes/Extensions/String+EndOfParagraph.swift new file mode 100644 index 000000000..a57e56593 --- /dev/null +++ b/Aztec/Classes/Extensions/String+EndOfParagraph.swift @@ -0,0 +1,28 @@ +import Foundation + + +// MARK: - Paragraph Analysis Helpers +// +extension String { + + /// This methods verifies if the receiver string contains an End of Paragraph before the specified index. + /// + /// - Parameters: + /// - index: the index to check + /// + /// - Returns: `true` if the receiver contains an end-of-paragraph character before the specified Index. + /// + func isEndOfParagraph(before index: String.Index) -> Bool { + assert(index != startIndex) + + let previousIndex = self.index(before: index) + guard previousIndex != endIndex else { + return true + } + + let endingString = substring(with: previousIndex ..< index) + let paragraphSeparators = [String(.carriageReturn), String(.lineFeed), String(.paragraphSeparator)] + + return paragraphSeparators.contains(endingString) + } +} From 3c9a9ea5714d9461cab7ac47c2af27e7af6df972 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Tue, 5 Sep 2017 17:29:06 -0300 Subject: [PATCH 09/11] Implements StringEndOfParagraphTests --- Aztec.xcodeproj/project.pbxproj | 8 +++++++ .../StringEndOfParagraphTests.swift | 23 +++++++++++++++++++ AztecTests/StringEndOfLineTests.swift | 18 --------------- 3 files changed, 31 insertions(+), 18 deletions(-) create mode 100644 AztecTests/Extensions/StringEndOfParagraphTests.swift diff --git a/Aztec.xcodeproj/project.pbxproj b/Aztec.xcodeproj/project.pbxproj index ad3e2cbc0..501a9419a 100644 --- a/Aztec.xcodeproj/project.pbxproj +++ b/Aztec.xcodeproj/project.pbxproj @@ -47,6 +47,8 @@ B57D1C3D1E92C38000EA4B16 /* HTMLAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D1C3C1E92C38000EA4B16 /* HTMLAttachment.swift */; }; B59C9F9F1DF74BB80073B1D6 /* UIFont+Traits.swift in Sources */ = {isa = PBXBuildFile; fileRef = B59C9F9E1DF74BB80073B1D6 /* UIFont+Traits.swift */; }; B5A99D841EBA073D00DED081 /* HTMLStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A99D831EBA073D00DED081 /* HTMLStorage.swift */; }; + B5AB79F81F5F3E0B00DF26F5 /* String+EndOfParagraph.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AB79F71F5F3E0B00DF26F5 /* String+EndOfParagraph.swift */; }; + B5AB79FA1F5F403C00DF26F5 /* StringEndOfParagraphTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AB79F91F5F403C00DF26F5 /* StringEndOfParagraphTests.swift */; }; B5AF89321E93CFC80051EFDB /* RenderableAttachmentDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AF89311E93CFC80051EFDB /* RenderableAttachmentDelegate.swift */; }; B5B86D371DA3EC250083DB3F /* NSRange+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = F18733C41DA096EE005AEB80 /* NSRange+Helpers.swift */; }; B5B96DAB1E01B2F300791315 /* UIPasteboard+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5B96DAA1E01B2F300791315 /* UIPasteboard+Helpers.swift */; }; @@ -219,6 +221,8 @@ B57D1C3C1E92C38000EA4B16 /* HTMLAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTMLAttachment.swift; sourceTree = ""; }; B59C9F9E1DF74BB80073B1D6 /* UIFont+Traits.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIFont+Traits.swift"; sourceTree = ""; }; B5A99D831EBA073D00DED081 /* HTMLStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTMLStorage.swift; sourceTree = ""; }; + B5AB79F71F5F3E0B00DF26F5 /* String+EndOfParagraph.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+EndOfParagraph.swift"; sourceTree = ""; }; + B5AB79F91F5F403C00DF26F5 /* StringEndOfParagraphTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StringEndOfParagraphTests.swift; path = Extensions/StringEndOfParagraphTests.swift; sourceTree = ""; }; B5AF89311E93CFC80051EFDB /* RenderableAttachmentDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RenderableAttachmentDelegate.swift; sourceTree = ""; }; B5B96DAA1E01B2F300791315 /* UIPasteboard+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIPasteboard+Helpers.swift"; sourceTree = ""; }; B5BC4FED1DA2C17800614582 /* NSAttributedString+Lists.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+Lists.swift"; sourceTree = ""; }; @@ -507,6 +511,7 @@ B5B96DAA1E01B2F300791315 /* UIPasteboard+Helpers.swift */, B5C99D3E1E72E2E700335355 /* UIStackView+Helpers.swift */, F1DE83D41EF20493009269E6 /* UIColor+Parsers.swift */, + B5AB79F71F5F3E0B00DF26F5 /* String+EndOfParagraph.swift */, ); path = Extensions; sourceTree = ""; @@ -774,6 +779,7 @@ B5375F481EC2569500F5D7EC /* StringHTMLTests.swift */, FF152D8D1E68552A00FF596C /* StringRangeConversionTests.swift */, FF7DCB4A1E815F9400AB77CB /* UIColorHexParserTests.swift */, + B5AB79F91F5F403C00DF26F5 /* StringEndOfParagraphTests.swift */, ); name = Extensions; sourceTree = ""; @@ -964,6 +970,7 @@ F12F586C1EF20394008AE298 /* HTMLParagraphFormatter.swift in Sources */, F17BC86B1F4E466100398E2B /* NSAttributedString+HTMLInitializer.swift in Sources */, F12F58661EF20394008AE298 /* StandardAttributeFormatter.swift in Sources */, + B5AB79F81F5F3E0B00DF26F5 /* String+EndOfParagraph.swift in Sources */, B5A99D841EBA073D00DED081 /* HTMLStorage.swift in Sources */, F13CE53E1F4DD05E0043368D /* PipelineProcessor.swift in Sources */, F17BC8AA1F4E512800398E2B /* AttributedStringParser.swift in Sources */, @@ -1070,6 +1077,7 @@ B5F84B631E706B720089A76C /* NSAttributedStringAnalyzerTests.swift in Sources */, F10BE61C1EA7B1DB002E4625 /* NSAttributedStringReplaceOcurrencesTests.swift in Sources */, B5375F491EC2569500F5D7EC /* StringHTMLTests.swift in Sources */, + B5AB79FA1F5F403C00DF26F5 /* StringEndOfParagraphTests.swift in Sources */, B57534521F267D63009D4904 /* ArrayHelperTests.swift in Sources */, F14665451EA7C230008DE2B8 /* NSMutableAttributedStringReplaceOcurrencesTests.swift in Sources */, F17BC8B51F4E517100398E2B /* AttributedStringParserTests.swift in Sources */, diff --git a/AztecTests/Extensions/StringEndOfParagraphTests.swift b/AztecTests/Extensions/StringEndOfParagraphTests.swift new file mode 100644 index 000000000..3a0e2179d --- /dev/null +++ b/AztecTests/Extensions/StringEndOfParagraphTests.swift @@ -0,0 +1,23 @@ +import XCTest +@testable import Aztec + +class StringEndOfParagraphTests: XCTestCase { + + func testEndsWithCarriageReturnEffectivelyReturnsTrueWheneverTestStringEndsWithCarriageReturn() { + let test = "something\u{000D}" + + XCTAssert(test.isEndOfParagraph(before: test.endIndex)) + } + + func testEndsWithCarriageReturnReturnsFalseWheneverTestStringDoesNotEndWithCarriageReturn() { + let test = "something" + + XCTAssertFalse(test.isEndOfParagraph(before: test.endIndex)) + } + + func testEndsWithDoesNotCrashOnEmptyString() { + let test = "" + + XCTAssertNoThrow(test.isEndOfParagraph(before: test.endIndex), "") + } +} diff --git a/AztecTests/StringEndOfLineTests.swift b/AztecTests/StringEndOfLineTests.swift index 4dbba9110..c88835232 100644 --- a/AztecTests/StringEndOfLineTests.swift +++ b/AztecTests/StringEndOfLineTests.swift @@ -205,22 +205,4 @@ class StringEndOfLineTests: XCTestCase { XCTAssertFalse(string.isStartOfNewLine(at: index)) } } - - func testEndsWithCarriageReturnEffectivelyReturnsTrueWheneverTestStringEndsWithCarriageReturn() { - let test = "something\u{000D}" - - XCTAssert(test.isEndOfParagraph(at: test.endIndex)) - } - - func testEndsWithCarriageReturnReturnsFalseWheneverTestStringDoesNotEndWithCarriageReturn() { - let test = "something" - - XCTAssertFalse(test.isEndOfParagraph(at: test.endIndex)) - } - - func testEndsWithDoesNotCrashOnEmptyString() { - let test = "" - - XCTAssertNoThrow(test.isEndOfParagraph(at: test.endIndex), "") - } } From 2eeefdfab82ba7a1eb41c5a80d74a81c5e0de564 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Tue, 5 Sep 2017 17:29:16 -0300 Subject: [PATCH 10/11] LayoutManager: Wiring new helper --- Aztec/Classes/TextKit/LayoutManager.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Aztec/Classes/TextKit/LayoutManager.swift b/Aztec/Classes/TextKit/LayoutManager.swift index 433be0583..78a1612eb 100644 --- a/Aztec/Classes/TextKit/LayoutManager.swift +++ b/Aztec/Classes/TextKit/LayoutManager.swift @@ -70,7 +70,7 @@ private extension LayoutManager { let lineRange = self.characterRange(forGlyphRange: glyphRange, actualGlyphRange: nil) let lineCharacters = textStorage.attributedSubstring(from: lineRange).string - if !lineCharacters.isEndOfParagraph(at: lineCharacters.endIndex) { + if !lineCharacters.isEndOfParagraph(before: lineCharacters.endIndex) { paddingHeight = 0 } From a76f708e91097b7c1f3efc3d91dc15c36fbc72b4 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Tue, 5 Sep 2017 17:33:59 -0300 Subject: [PATCH 11/11] StringEndOfParagraphTests: Updates Tests --- .../Extensions/StringEndOfParagraphTests.swift | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/AztecTests/Extensions/StringEndOfParagraphTests.swift b/AztecTests/Extensions/StringEndOfParagraphTests.swift index 3a0e2179d..e95a83f8c 100644 --- a/AztecTests/Extensions/StringEndOfParagraphTests.swift +++ b/AztecTests/Extensions/StringEndOfParagraphTests.swift @@ -3,21 +3,15 @@ import XCTest class StringEndOfParagraphTests: XCTestCase { - func testEndsWithCarriageReturnEffectivelyReturnsTrueWheneverTestStringEndsWithCarriageReturn() { - let test = "something\u{000D}" + func testIsEndOfParagraphReturnsTrueWheneverTestStringEndsWithCarriageReturn() { + let test = "something" + String(.carriageReturn) - XCTAssert(test.isEndOfParagraph(before: test.endIndex)) + XCTAssertTrue(test.isEndOfParagraph(before: test.endIndex)) } - func testEndsWithCarriageReturnReturnsFalseWheneverTestStringDoesNotEndWithCarriageReturn() { - let test = "something" + func testIsEndOfParagraphReturnsFalseWheneverTestStringEndsWithLineSeparator() { + let test = "something" + String(.lineSeparator) XCTAssertFalse(test.isEndOfParagraph(before: test.endIndex)) } - - func testEndsWithDoesNotCrashOnEmptyString() { - let test = "" - - XCTAssertNoThrow(test.isEndOfParagraph(before: test.endIndex), "") - } }