diff --git a/Aztec/Classes/Constants/Metrics.swift b/Aztec/Classes/Constants/Metrics.swift
index 146e14042..ca632cced 100644
--- a/Aztec/Classes/Constants/Metrics.swift
+++ b/Aztec/Classes/Constants/Metrics.swift
@@ -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)
}
diff --git a/Aztec/Classes/Libxml2/DOM/Data/Element.swift b/Aztec/Classes/Libxml2/DOM/Data/Element.swift
index 09acd1410..2f208af83 100644
--- a/Aztec/Classes/Libxml2/DOM/Data/Element.swift
+++ b/Aztec/Classes/Libxml2/DOM/Data/Element.swift
@@ -30,7 +30,7 @@ public struct Element: RawRepresentable, Hashable {
public static var mergeableBlockLevelElements = Set([.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([.i, .em, .b, .strong, .strike, .u, .code, .cite])
+ public static var mergeableStyleElements = Set([.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
///
diff --git a/Aztec/Classes/TextKit/LayoutManager.swift b/Aztec/Classes/TextKit/LayoutManager.swift
index 7a5e4467e..5ffdca08a 100644
--- a/Aztec/Classes/TextKit/LayoutManager.swift
+++ b/Aztec/Classes/TextKit/LayoutManager.swift
@@ -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
@@ -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)
}
-
}
}
@@ -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)
@@ -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
@@ -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)
@@ -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)
}
}
@@ -278,31 +273,36 @@ 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)
}
@@ -310,10 +310,7 @@ private extension LayoutManager {
///
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)
@@ -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
}
diff --git a/Aztec/Classes/TextKit/ParagraphProperty/TextList.swift b/Aztec/Classes/TextKit/ParagraphProperty/TextList.swift
index 8c4d0bc44..a2cf28306 100644
--- a/Aztec/Classes/TextKit/ParagraphProperty/TextList.swift
+++ b/Aztec/Classes/TextKit/ParagraphProperty/TextList.swift
@@ -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}"
}
}
}
diff --git a/Aztec/Classes/TextKit/ParagraphStyle.swift b/Aztec/Classes/TextKit/ParagraphStyle.swift
index c52a20ae2..eb01f7029 100644
--- a/Aztec/Classes/TextKit/ParagraphStyle.swift
+++ b/Aztec/Classes/TextKit/ParagraphStyle.swift
@@ -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
}
@@ -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
}
@@ -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(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..(_ 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(_ 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.. 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..WordPress 워드 프레스
")
+ let html = textView.getHTML()
+ XCTAssertEqual(html, "WordPress 워드 프레스
")
+
+ textView.setHTML("WordPress워드 프레스
")
+ let htmlTwoLinks = textView.getHTML()
+ XCTAssertEqual(htmlTwoLinks, "WordPress워드 프레스
")
+ }
+
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 661ef9b60..2547e7ef1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/Example/AztecExample.xcodeproj/project.pbxproj b/Example/AztecExample.xcodeproj/project.pbxproj
index f715d733d..b4e81ccd2 100644
--- a/Example/AztecExample.xcodeproj/project.pbxproj
+++ b/Example/AztecExample.xcodeproj/project.pbxproj
@@ -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 */; };
@@ -163,6 +164,7 @@
FF629DC8223BC418004C4106 /* videoShortcodes.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = videoShortcodes.html; sourceTree = ""; };
FF9AF5471DB0E4E200C42ED3 /* AttachmentDetailsViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = AttachmentDetailsViewController.storyboard; sourceTree = ""; };
FFC41BDD20DBC7BA004DFB4D /* video.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = video.html; sourceTree = ""; };
+ FFC6772123D07E3E00B76815 /* bigLists.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = bigLists.html; sourceTree = ""; };
FFFA53CF23C4A64200829A43 /* MediaInserter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaInserter.swift; sourceTree = ""; };
FFFA53D423C4AD0B00829A43 /* TextViewAttachmentDelegateProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewAttachmentDelegateProvider.swift; sourceTree = ""; };
FFFA53D623C4C43700829A43 /* UIImage+SaveTo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+SaveTo.swift"; sourceTree = ""; };
@@ -211,6 +213,7 @@
FFC41BDD20DBC7BA004DFB4D /* video.html */,
FF629DC8223BC418004C4106 /* videoShortcodes.html */,
FF5CDACC239E78B200CF235B /* failedMedia.html */,
+ FFC6772123D07E3E00B76815 /* bigLists.html */,
);
path = SampleContent;
sourceTree = "";
@@ -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 */,
diff --git a/Example/AztecExample.xcodeproj/xcshareddata/xcschemes/AztecExample.xcscheme b/Example/AztecExample.xcodeproj/xcshareddata/xcschemes/AztecExample.xcscheme
index 22ca47bca..56d832f51 100644
--- a/Example/AztecExample.xcodeproj/xcshareddata/xcschemes/AztecExample.xcscheme
+++ b/Example/AztecExample.xcodeproj/xcshareddata/xcschemes/AztecExample.xcscheme
@@ -40,9 +40,18 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES"
- onlyGenerateCoverageForSpecifiedTargets = "YES"
- shouldUseLaunchSchemeArgsEnv = "YES">
+ onlyGenerateCoverageForSpecifiedTargets = "YES">
+
+
+
+
-
-
-
-
-
-
-
-
One digit list
+
+ - First
+ - Second
+ - Third
+ - Fourth
+
+Two digits list
+
+ - First
+ - Second
+ - Third
+ - Fourth
+
+ - First
+ - Second
+ - Third
+ - Fourth
+
+
+
+Three digits list
+
+ - First
+ - Second
+ - Third
+ - Fourth
+
+Four digits list
+
+ - First
+ - Second
+ - Third
+ - Fourth
+
+ - First
+ - Second
+ - Third
+ - Fourth
+
+
+
+
+Five digits list
+
+ - First
+ - Second
+ - Third
+ - Fourth
+
+ - First
+ - Second
+ - Third
+ - Fourth
+
+
+
diff --git a/Example/Example/ViewController.swift b/Example/Example/ViewController.swift
index ce4a71df9..7ccafeb8d 100644
--- a/Example/Example/ViewController.swift
+++ b/Example/Example/ViewController.swift
@@ -20,6 +20,7 @@ class ViewController: UITableViewController
DemoRow(title: "Image Overlays", action: { self.showEditorDemo(filename: "imagesOverlays") }),
DemoRow(title: "Video Demo", action: { self.showEditorDemo(filename: "video", wordPressMode: false) }),
DemoRow(title: "Failed Media", action: { self.showEditorDemo(filename: "failedMedia") }),
+ DemoRow(title: "Big Lists", action: { self.showEditorDemo(filename: "bigLists") }),
DemoRow(title: "Empty Demo", action: { self.showEditorDemo() })
]
),
diff --git a/WordPress-Aztec-iOS.podspec b/WordPress-Aztec-iOS.podspec
index a6aabfd54..e991ddd83 100644
--- a/WordPress-Aztec-iOS.podspec
+++ b/WordPress-Aztec-iOS.podspec
@@ -8,7 +8,7 @@
Pod::Spec.new do |s|
s.name = 'WordPress-Aztec-iOS'
- s.version = '1.15.0'
+ s.version = '1.16.0'
s.summary = 'The native HTML Editor.'
# This description is used to generate tags and improve search results.
diff --git a/WordPress-Editor-iOS.podspec b/WordPress-Editor-iOS.podspec
index 8a29e48ab..c1f383a7d 100644
--- a/WordPress-Editor-iOS.podspec
+++ b/WordPress-Editor-iOS.podspec
@@ -8,7 +8,7 @@
Pod::Spec.new do |s|
s.name = 'WordPress-Editor-iOS'
- s.version = '1.15.0'
+ s.version = '1.16.0'
s.summary = 'The WordPress HTML Editor.'
# This description is used to generate tags and improve search results.