Skip to content

Commit

Permalink
Merge pull request #1268 from wordpress-mobile/release/1.16.0
Browse files Browse the repository at this point in the history
Prepare release 1.16.0
  • Loading branch information
SergioEstevao authored Feb 5, 2020
2 parents 48e6bcc + a87dc54 commit 3005501
Show file tree
Hide file tree
Showing 14 changed files with 190 additions and 98 deletions.
6 changes: 4 additions & 2 deletions Aztec/Classes/Constants/Metrics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ public enum Metrics {

public static var defaultIndentation = CGFloat(12)
public static var maxIndentation = CGFloat(200)
public static var listTextIndentation = CGFloat(16)
public static var tabStepInterval = 8
public static var listTextIndentation = CGFloat(12)
public static var listTextCharIndentation = CGFloat(8)
public static var listMinimumIndentChars = 3
public static var tabStepInterval = 4
public static var tabStepCount = 12
public static var paragraphSpacing = CGFloat(6)
}
2 changes: 1 addition & 1 deletion Aztec/Classes/Libxml2/DOM/Data/Element.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public struct Element: RawRepresentable, Hashable {
public static var mergeableBlockLevelElements = Set<Element>([.blockquote, .div, .figure, .figcaption, .h1, .h2, .h3, .h4, .h5, .h6, .hr, .li, .ol, .ul, .p, .pre])

/// List of style HTML elements that can be merged together when they are sibling to each other
public static var mergeableStyleElements = Set<Element>([.i, .em, .b, .strong, .strike, .u, .code, .cite])
public static var mergeableStyleElements = Set<Element>([.i, .em, .b, .strong, .strike, .u, .code, .cite, .a])

/// List of block level elements that can be merged but only when they have a single children that is also mergeable
///
Expand Down
66 changes: 32 additions & 34 deletions Aztec/Classes/TextKit/LayoutManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ private extension LayoutManager {

enumerateLineFragments(forGlyphRange: blockquoteGlyphRange) { (rect, usedRect, textContainer, glyphRange, stop) in

let startIndent = paragraphStyle.blockquoteIndent
let startIndent = paragraphStyle.indentToFirst(Blockquote.self) - Metrics.listTextIndentation

let lineRange = self.characterRange(forGlyphRange: glyphRange, actualGlyphRange: nil)
let lineCharacters = textStorage.attributedSubstring(from: lineRange).string
Expand All @@ -78,13 +78,12 @@ private extension LayoutManager {

let nestDepth = paragraphStyle.blockquoteNestDepth
for index in 0...nestDepth {
let indent = startIndent + CGFloat(index) * Metrics.listTextIndentation
let indent = paragraphStyle.indent(to: index, of: Blockquote.self) - Metrics.listTextIndentation

let nestRect = self.blockquoteRect(origin: origin, lineRect: rect, blockquoteIndent: indent, lineEndsParagraph: lineEndsParagraph)
let nestRect = self.blockquoteRect(origin: origin, lineRect: rect, blockquoteIndent: indent, lineEndsParagraph: lineEndsParagraph)

self.drawBlockquoteBorder(in: nestRect.integral, with: context, at: index)
self.drawBlockquoteBorder(in: nestRect.integral, with: context, at: index)
}


}
}
Expand All @@ -100,7 +99,7 @@ private extension LayoutManager {
return
}

let extraIndent = paragraphStyle.blockquoteIndent
let extraIndent = paragraphStyle.indentToLast(Blockquote.self)
let extraRect = blockquoteRect(origin: origin, lineRect: extraLineFragmentRect, blockquoteIndent: extraIndent, lineEndsParagraph: false)

drawBlockquoteBackground(in: extraRect.integral, with: context)
Expand All @@ -121,11 +120,7 @@ private extension LayoutManager {
private func blockquoteRect(origin: CGPoint, lineRect: CGRect, blockquoteIndent: CGFloat, lineEndsParagraph: Bool) -> CGRect {
var blockquoteRect = lineRect.offsetBy(dx: origin.x, dy: origin.y)

guard blockquoteIndent != 0 else {
return blockquoteRect
}

let paddingWidth = Metrics.listTextIndentation * 0.5 + blockquoteIndent
let paddingWidth = blockquoteIndent
blockquoteRect.origin.x += paddingWidth
blockquoteRect.size.width -= paddingWidth

Expand Down Expand Up @@ -228,7 +223,7 @@ private extension LayoutManager {
else {
return
}

let attributes = textStorage.attributes(at: enclosingRange.location, effectiveRange: nil)
let glyphRange = self.glyphRange(forCharacterRange: enclosingRange, actualCharacterRange: nil)
let markerRect = rectForItem(range: glyphRange, origin: origin, paragraphStyle: paragraphStyle)
var markerNumber = textStorage.itemNumber(in: list, at: enclosingRange.location)
Expand All @@ -240,8 +235,8 @@ private extension LayoutManager {
}
}
markerNumber += start

drawItem(number: markerNumber, in: markerRect, from: list, using: paragraphStyle, at: enclosingRange.location)
let markerString = list.style.markerText(forItemNumber: markerNumber)
drawItem(markerString, in: markerRect, styled: attributes, at: enclosingRange.location)
}
}

Expand Down Expand Up @@ -278,42 +273,44 @@ private extension LayoutManager {
/// Draws the specified List Item Number, at a given location.
///
/// - Parameters:
/// - number: Marker Number of the item to be drawn
/// - markerText: Marker String of the item to be drawn
/// - rect: Visible Rect in which the Marker should be rendered
/// - list: Associated TextList
/// - style: ParagraphStyle associated to the list
/// - styled: Paragraph attributes associated to the list
/// - location: Text Location that should get the marker rendered.
///
private func drawItem(number: Int, in rect: CGRect, from list: TextList, using style: ParagraphStyle, at location: Int) {
guard let textStorage = textStorage else {
private func drawItem(_ markerText: String, in rect: CGRect, styled paragraphAttributes: [NSAttributedString.Key: Any], at location: Int) {
guard let style = paragraphAttributes[.paragraphStyle] as? ParagraphStyle else {
return
}

let paragraphAttributes = textStorage.attributes(at: location, effectiveRange: nil)
let markerAttributes = markerAttributesBasedOnParagraph(attributes: paragraphAttributes)

let markerPlain = list.style.markerText(forItemNumber: number)
let markerText = NSAttributedString(string: markerPlain, attributes: markerAttributes)
let markerAttributedText = NSAttributedString(string: markerText, attributes: markerAttributes)

var yOffset = CGFloat(0)
var xOffset = CGFloat(0)
let indentWidth = style.indentToLast(TextList.self)
let markerWidth = markerAttributedText.size().width * 1.5

if location > 0 {
yOffset += style.paragraphSpacingBefore
}
// If the marker width is larger than the indent available let's offset the area to draw to the left
if markerWidth > indentWidth {
xOffset = indentWidth - markerWidth
}

var markerRect = rect.offsetBy(dx: xOffset, dy: yOffset)

markerRect.size.width = max(indentWidth, markerWidth)

let markerRect = rect.offsetBy(dx: 0, dy: yOffset)
markerText.draw(in: markerRect)
markerAttributedText.draw(in: markerRect)
}


/// Returns the Marker Text Attributes, based on a collection that defines Regular Text Attributes.
///
private func markerAttributesBasedOnParagraph(attributes: [NSAttributedString.Key: Any]) -> [NSAttributedString.Key: Any] {
var resultAttributes = attributes
var indent: CGFloat = 0
if let style = attributes[.paragraphStyle] as? ParagraphStyle {
indent = style.listIndent + Metrics.listTextIndentation - (Metrics.listTextIndentation / 4)
}
let indent: CGFloat = CGFloat(Metrics.tabStepInterval)

resultAttributes[.paragraphStyle] = markerParagraphStyle(indent: indent)
resultAttributes.removeValue(forKey: .underlineStyle)
Expand All @@ -328,13 +325,14 @@ private extension LayoutManager {
}


/// Returns the Marker Paratraph Attributes
/// Returns the Marker Paragraph Attributes
///
private func markerParagraphStyle(indent: CGFloat) -> NSParagraphStyle {
let tabStop = NSTextTab(textAlignment: .right, location: indent, options: [:])

let paragraphStyle = NSMutableParagraphStyle()

paragraphStyle.tabStops = [tabStop]
paragraphStyle.alignment = .right
paragraphStyle.tailIndent = -indent
paragraphStyle.lineBreakMode = .byClipping

return paragraphStyle
}
Expand Down
4 changes: 2 additions & 2 deletions Aztec/Classes/TextKit/ParagraphProperty/TextList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ open class TextList: ParagraphProperty {

func markerText(forItemNumber number: Int) -> String {
switch self {
case .ordered: return "\t\(number)."
case .unordered: return "\t\u{2022}"
case .ordered: return "\(number)."
case .unordered: return "\u{2022}"
}
}
}
Expand Down
94 changes: 56 additions & 38 deletions Aztec/Classes/TextKit/ParagraphStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ open class ParagraphStyle: NSMutableParagraphStyle, CustomReflectable {

open override var headIndent: CGFloat {
get {
let extra: CGFloat = (CGFloat(lists.count + blockquotes.count) * Metrics.listTextIndentation)
let extra: CGFloat = (CGFloat(blockquotes.count) * Metrics.listTextIndentation) + listIndent

return baseHeadIndent + extra
}
Expand All @@ -152,7 +152,8 @@ open class ParagraphStyle: NSMutableParagraphStyle, CustomReflectable {

open override var firstLineHeadIndent: CGFloat {
get {
let extra: CGFloat = (CGFloat(lists.count + blockquotes.count) * Metrics.listTextIndentation)

let extra: CGFloat = (CGFloat(blockquotes.count) * Metrics.listTextIndentation) + listIndent

return baseFirstLineHeadIndent + extra
}
Expand All @@ -175,57 +176,74 @@ open class ParagraphStyle: NSMutableParagraphStyle, CustomReflectable {
super.tailIndent = newValue
}
}

/// The level of indent to start the blockquote of the paragraph. Includes list indentation.
/// Handles whether blockquote is outside or insdie of a list.
public var blockquoteIndent: CGFloat {
let listAndBlockquotes = properties.filter({ property in
return property is Blockquote || property is TextList
})
if listAndBlockquotes.first is Blockquote {

/// Calculates the indentation of the paragraph up, for up to a certain depth of nesting of the type provided
/// - Parameters:
/// - depth: the depth up to check
/// - type: the type to check
public func indent<T : ParagraphProperty>(to depth: Int, of type: T.Type) -> CGFloat {
var position = -1
var currentDepth = -1
for property in properties {
position += 1
if property is T {
currentDepth += 1
}
if depth == currentDepth {
break
}
}
if position == -1 || currentDepth == -1 {
return 0
}
var depth = 0
for position in (0..<listAndBlockquotes.count).reversed() {
if listAndBlockquotes[position] is Blockquote {
depth = position
break
return indent(through: position)
}

/// Calculates the indentation of the paragraph up to the fist of property of the type
/// - Parameter type: the type to check
public func indentToFirst<T : ParagraphProperty>(_ type: T.Type) -> CGFloat {
let depth = properties.firstIndex(where: {$0 is T}) ?? 0
return indent(through: depth)
}

/// Calculates the indentation of the paragraph up the last property of the type specified
/// - Parameter type: the paragraph property type to check
public func indentToLast<T : ParagraphProperty>(_ type: T.Type) -> CGFloat {
let depth = properties.lastIndex(where: {$0 is T}) ?? 0
return indent(through: depth)
}

/// Calculates the level of indent up to a certain depth
private func indent(through depth: Int) -> CGFloat {
let totalIndent = properties.prefix(through: depth).reduce(CGFloat(0)) { (total, property) in
if let list = property as? TextList {
return total + indent(for: list)
} else if property is Blockquote {
return total + Metrics.listTextIndentation
}
return total
}
return CGFloat(depth) * Metrics.listTextIndentation
return totalIndent
}

/// The level of depth for the nested blockquote of the paragraph. Excludes list indentation.
///
public var blockquoteNestDepth: Int {
let listAndBlockquotes = properties.filter({ property in
return property is Blockquote
})
var depth = 0
for position in (0..<listAndBlockquotes.count).reversed() {
if listAndBlockquotes[position] is Blockquote {
depth = position
break
}
}
return depth
return max(0, blockquotes.count - 1)
}

private func indent(for list: TextList) -> CGFloat {
let markerSize = CGFloat(list.style.markerText(forItemNumber: list.start ?? 1).count)
let markerMinimum = max(CGFloat(Metrics.listMinimumIndentChars), markerSize)
return Metrics.listTextIndentation + (markerMinimum * Metrics.listTextCharIndentation)
}
/// The amount of indent for the list of the paragraph if any.
///
public var listIndent: CGFloat {
let listAndBlockquotes = properties.filter({ property in
return property is Blockquote || property is TextList
})
var depth = 0
for position in (0..<listAndBlockquotes.count).reversed() {
if listAndBlockquotes[position] is TextList {
depth = position
break
}
let listIndent: CGFloat = lists.reduce(0) { (total, list) in
return total + indent(for: list)
}

return CGFloat(depth) * Metrics.listTextIndentation
return listIndent
}

open var baseHeadIndent: CGFloat = 0
Expand Down
17 changes: 14 additions & 3 deletions AztecTests/TextKit/TextViewTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2085,14 +2085,15 @@ class TextViewTests: XCTestCase {
pasteItems[kUTTypePlainText as String] = try! sourceAttributedText.data(from: sourceAttributedText.rangeOfEntireString, documentAttributes: [.documentType: DocumentType.plain])
UIPasteboard.general.setItems([pasteItems], options: [:])
let textView = TextViewStub(withHTML: "")
textView.defaultTextColor = UIColor.red
textView.textColor = UIColor.red
textView.paste(nil)

let attributedString = textView.attributedText!

let attributes = attributedString.attributes(at: 0, effectiveRange: nil)

XCTAssertEqual(attributes[.foregroundColor] as! UIColor, UIColor.red)
if let colorSet = attributes[.foregroundColor] as? UIColor {
XCTAssertEqual(colorSet, UIColor.red)
}
XCTAssertEqual(textView.text, "Hello world")
}

Expand All @@ -2106,4 +2107,14 @@ class TextViewTests: XCTestCase {
XCTAssertEqual(attributes[.foregroundColor] as! UIColor,UIColor.green)
}

func testLinksWithMultipleCharactersNonLatinDontBreak() {
let textView = TextViewStub(withHTML: "<p><a href=\"www.worpdress.com\">WordPress 워드 프레스</a></p>")
let html = textView.getHTML()
XCTAssertEqual(html, "<p><a href=\"www.worpdress.com\">WordPress 워드 프레스</a></p>")

textView.setHTML("<p><a href=\"www.worpdress.com\">WordPress</a><a href=\"www.jetpack.com\">워드 프레스</a></p>")
let htmlTwoLinks = textView.getHTML()
XCTAssertEqual(htmlTwoLinks, "<p><a href=\"www.worpdress.com\">WordPress</a><a href=\"www.jetpack.com\">워드 프레스</a></p>")
}

}
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
1.16.0
-----
* Improve display of ordered lists with large bullet numbers
* Fix bug where links with text that had a mix of Latin and non-Latin characters were getting split.

1.15.0
-----
* Allow to use headers fonts without bold effect applied
Expand Down
4 changes: 4 additions & 0 deletions Example/AztecExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
FF629DC9223BC418004C4106 /* videoShortcodes.html in Resources */ = {isa = PBXBuildFile; fileRef = FF629DC8223BC418004C4106 /* videoShortcodes.html */; };
FF9AF5481DB0E4E200C42ED3 /* AttachmentDetailsViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FF9AF5471DB0E4E200C42ED3 /* AttachmentDetailsViewController.storyboard */; };
FFC41BDE20DBC7BA004DFB4D /* video.html in Resources */ = {isa = PBXBuildFile; fileRef = FFC41BDD20DBC7BA004DFB4D /* video.html */; };
FFC6772223D07E3E00B76815 /* bigLists.html in Resources */ = {isa = PBXBuildFile; fileRef = FFC6772123D07E3E00B76815 /* bigLists.html */; };
FFFA53D023C4A64200829A43 /* MediaInserter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFFA53CF23C4A64200829A43 /* MediaInserter.swift */; };
FFFA53D523C4AD0B00829A43 /* TextViewAttachmentDelegateProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFFA53D423C4AD0B00829A43 /* TextViewAttachmentDelegateProvider.swift */; };
FFFA53D723C4C43700829A43 /* UIImage+SaveTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFFA53D623C4C43700829A43 /* UIImage+SaveTo.swift */; };
Expand Down Expand Up @@ -163,6 +164,7 @@
FF629DC8223BC418004C4106 /* videoShortcodes.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = videoShortcodes.html; sourceTree = "<group>"; };
FF9AF5471DB0E4E200C42ED3 /* AttachmentDetailsViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = AttachmentDetailsViewController.storyboard; sourceTree = "<group>"; };
FFC41BDD20DBC7BA004DFB4D /* video.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = video.html; sourceTree = "<group>"; };
FFC6772123D07E3E00B76815 /* bigLists.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = bigLists.html; sourceTree = "<group>"; };
FFFA53CF23C4A64200829A43 /* MediaInserter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaInserter.swift; sourceTree = "<group>"; };
FFFA53D423C4AD0B00829A43 /* TextViewAttachmentDelegateProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewAttachmentDelegateProvider.swift; sourceTree = "<group>"; };
FFFA53D623C4C43700829A43 /* UIImage+SaveTo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+SaveTo.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -211,6 +213,7 @@
FFC41BDD20DBC7BA004DFB4D /* video.html */,
FF629DC8223BC418004C4106 /* videoShortcodes.html */,
FF5CDACC239E78B200CF235B /* failedMedia.html */,
FFC6772123D07E3E00B76815 /* bigLists.html */,
);
path = SampleContent;
sourceTree = "<group>";
Expand Down Expand Up @@ -457,6 +460,7 @@
59280F2A1D47CAF40083FB59 /* content.html in Resources */,
FF5CDACD239E78B200CF235B /* failedMedia.html in Resources */,
B5FB212A1FEC38470067D597 /* captions.html in Resources */,
FFC6772223D07E3E00B76815 /* bigLists.html in Resources */,
FF1FD05C20932EDE00186384 /* gutenberg.html in Resources */,
59280F2B1D47CAF40083FB59 /* SampleText.rtf in Resources */,
607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */,
Expand Down
Loading

0 comments on commit 3005501

Please sign in to comment.