From 18f0e21993c9451c90a4c3d59cc9ca77f3a6515f Mon Sep 17 00:00:00 2001
From: Sergio Estevao
Date: Mon, 8 May 2017 22:00:15 +0100
Subject: [PATCH 1/7] Just change textList to and array of textLists.
---
.../Extensions/NSAttributedString+Lists.swift | 10 +++----
.../Formatters/TextListFormatter.swift | 17 ++++++-----
Aztec/Classes/TextKit/LayoutManager.swift | 2 +-
Aztec/Classes/TextKit/ParagraphStyle.swift | 30 ++++++++-----------
Aztec/Classes/TextKit/TextStorage.swift | 2 +-
5 files changed, 30 insertions(+), 31 deletions(-)
diff --git a/Aztec/Classes/Extensions/NSAttributedString+Lists.swift b/Aztec/Classes/Extensions/NSAttributedString+Lists.swift
index 1d2b2f78c..84e2121c5 100644
--- a/Aztec/Classes/Extensions/NSAttributedString+Lists.swift
+++ b/Aztec/Classes/Extensions/NSAttributedString+Lists.swift
@@ -66,7 +66,7 @@ extension NSAttributedString
let targetRange = rangeOfEntireString
guard
let paragraphStyle = attribute(NSParagraphStyleAttributeName, at: location, longestEffectiveRange: &effectiveRange, in: targetRange) as? ParagraphStyle,
- let foundList = paragraphStyle.textList,
+ let foundList = paragraphStyle.textLists.last,
foundList == list
else {
return nil
@@ -78,7 +78,7 @@ extension NSAttributedString
while resultRange.location > 0 {
if
let paragraphStyle = attribute(NSParagraphStyleAttributeName, at: resultRange.location-1, longestEffectiveRange: &effectiveRange, in: targetRange) as? ParagraphStyle,
- let foundList = paragraphStyle.textList,
+ let foundList = paragraphStyle.textLists.last,
foundList == list {
resultRange = resultRange.union(withRange: effectiveRange)
} else {
@@ -88,7 +88,7 @@ extension NSAttributedString
while resultRange.endLocation < self.length {
if
let paragraphStyle = attribute(NSParagraphStyleAttributeName, at: resultRange.endLocation, longestEffectiveRange: &effectiveRange, in: targetRange) as? ParagraphStyle,
- let foundList = paragraphStyle.textList,
+ let foundList = paragraphStyle.textLists.last,
foundList == list {
resultRange = resultRange.union(withRange: effectiveRange)
} else {
@@ -177,7 +177,7 @@ extension NSAttributedString
/// - Returns: A TextList optional.
///
func textListAttribute(atIndex index: Int) -> TextList? {
- return (attribute(NSParagraphStyleAttributeName, at: index, effectiveRange: nil) as? ParagraphStyle)?.textList
+ return (attribute(NSParagraphStyleAttributeName, at: index, effectiveRange: nil) as? ParagraphStyle)?.textLists.last
}
/// Returns the TextList attribute, assuming that there is one, spanning the specified Range.
@@ -196,7 +196,7 @@ extension NSAttributedString
enumerateAttribute(NSParagraphStyleAttributeName, in: range, options: []) { (attribute, range, stop) in
if let paragraphStyle = attribute as? ParagraphStyle {
- list = paragraphStyle.textList
+ list = paragraphStyle.textLists.last
}
stop.pointee = true
}
diff --git a/Aztec/Classes/Formatters/TextListFormatter.swift b/Aztec/Classes/Formatters/TextListFormatter.swift
index 0db9e6844..f9286a797 100644
--- a/Aztec/Classes/Formatters/TextListFormatter.swift
+++ b/Aztec/Classes/Formatters/TextListFormatter.swift
@@ -31,12 +31,12 @@ class TextListFormatter: ParagraphAttributeFormatter {
newParagraphStyle.setParagraphStyle(paragraphStyle)
}
- if newParagraphStyle.textList == nil {
+ if newParagraphStyle.textLists.last == nil {
newParagraphStyle.headIndent += Metrics.listTextIndentation
newParagraphStyle.firstLineHeadIndent += Metrics.listTextIndentation
}
- newParagraphStyle.textList = TextList(style: self.listStyle)
+ newParagraphStyle.textLists.append(TextList(style: self.listStyle))
var resultingAttributes = attributes
resultingAttributes[NSParagraphStyleAttributeName] = newParagraphStyle
@@ -46,7 +46,8 @@ class TextListFormatter: ParagraphAttributeFormatter {
func remove(from attributes: [String: Any]) -> [String: Any] {
guard let paragraphStyle = attributes[NSParagraphStyleAttributeName] as? ParagraphStyle,
- paragraphStyle.textList?.style == self.listStyle
+ let currentList = paragraphStyle.textLists.last,
+ currentList.style == self.listStyle
else {
return attributes
}
@@ -55,7 +56,7 @@ class TextListFormatter: ParagraphAttributeFormatter {
newParagraphStyle.setParagraphStyle(paragraphStyle)
newParagraphStyle.headIndent -= Metrics.listTextIndentation
newParagraphStyle.firstLineHeadIndent -= Metrics.listTextIndentation
- newParagraphStyle.textList = nil
+ newParagraphStyle.textLists.removeLast()
var resultingAttributes = attributes
resultingAttributes[NSParagraphStyleAttributeName] = newParagraphStyle
@@ -64,7 +65,7 @@ class TextListFormatter: ParagraphAttributeFormatter {
}
func present(in attributes: [String : Any]) -> Bool {
- guard let style = attributes[NSParagraphStyleAttributeName] as? ParagraphStyle, let list = style.textList else {
+ guard let style = attributes[NSParagraphStyleAttributeName] as? ParagraphStyle, let list = style.textLists.last else {
return false
}
@@ -72,8 +73,10 @@ class TextListFormatter: ParagraphAttributeFormatter {
}
static func listsOfAnyKindPresent(in attributes: [String: Any]) -> Bool {
- let style = attributes[NSParagraphStyleAttributeName] as? ParagraphStyle
- return style?.textList != nil
+ guard let style = attributes[NSParagraphStyleAttributeName] as? ParagraphStyle else {
+ return false
+ }
+ return !(style.textLists.isEmpty)
}
}
diff --git a/Aztec/Classes/TextKit/LayoutManager.swift b/Aztec/Classes/TextKit/LayoutManager.swift
index 38ecd522c..e41d0a1a9 100644
--- a/Aztec/Classes/TextKit/LayoutManager.swift
+++ b/Aztec/Classes/TextKit/LayoutManager.swift
@@ -85,7 +85,7 @@ private extension LayoutManager {
let characterRange = self.characterRange(forGlyphRange: glyphsToShow, actualGlyphRange: nil)
textStorage.enumerateAttribute(NSParagraphStyleAttributeName, in: characterRange, options: []) { (object, range, stop) in
- guard let paragraphStyle = object as? ParagraphStyle, let list = paragraphStyle.textList else {
+ guard let paragraphStyle = object as? ParagraphStyle, let list = paragraphStyle.textLists.last else {
return
}
diff --git a/Aztec/Classes/TextKit/ParagraphStyle.swift b/Aztec/Classes/TextKit/ParagraphStyle.swift
index b20018ca9..f3fe965d4 100644
--- a/Aztec/Classes/TextKit/ParagraphStyle.swift
+++ b/Aztec/Classes/TextKit/ParagraphStyle.swift
@@ -7,7 +7,7 @@ open class ParagraphStyle: NSMutableParagraphStyle, CustomReflectable {
public var customMirror: Mirror {
get {
- return Mirror(self, children: ["blockquote": blockquote as Any, "headerLevel": headerLevel, "htmlParagraph": htmlParagraph as Any, "textList": textList as Any])
+ return Mirror(self, children: ["blockquote": blockquote as Any, "headerLevel": headerLevel, "htmlParagraph": htmlParagraph as Any, "textList": textLists as Any])
}
}
@@ -17,7 +17,7 @@ open class ParagraphStyle: NSMutableParagraphStyle, CustomReflectable {
var blockquote: Blockquote?
var htmlParagraph: HTMLParagraph?
- var textList: TextList?
+ var textLists: [TextList] = []
var headerLevel: Int = 0
@@ -26,11 +26,8 @@ open class ParagraphStyle: NSMutableParagraphStyle, CustomReflectable {
}
public required init?(coder aDecoder: NSCoder) {
- if aDecoder.containsValue(forKey: String(describing: TextList.self)) {
- let styleRaw = aDecoder.decodeInteger(forKey: String(describing: TextList.self))
- if let style = TextList.Style(rawValue:styleRaw) {
- textList = TextList(style: style)
- }
+ if let encodedLists = aDecoder.decodeObject(forKey:String(describing: TextList.self)) as? [TextList] {
+ textLists = encodedLists
}
if aDecoder.containsValue(forKey: String(describing: Blockquote.self)) {
blockquote = aDecoder.decodeObject(forKey: String(describing: Blockquote.self)) as? Blockquote
@@ -43,9 +40,8 @@ open class ParagraphStyle: NSMutableParagraphStyle, CustomReflectable {
override open func encode(with aCoder: NSCoder) {
super.encode(with: aCoder)
- if let textListSet = textList {
- aCoder.encode(textListSet.style.rawValue, forKey: String(describing: TextList.self))
- }
+
+ aCoder.encode(textLists, forKey: String(describing: TextList.self))
if let blockquote = self.blockquote {
aCoder.encode(blockquote, forKey: String(describing: Blockquote.self))
@@ -60,7 +56,7 @@ open class ParagraphStyle: NSMutableParagraphStyle, CustomReflectable {
blockquote = paragrahStyle.blockquote
headerLevel = paragrahStyle.headerLevel
htmlParagraph = paragrahStyle.htmlParagraph
- textList = paragrahStyle.textList
+ textLists = paragrahStyle.textLists
}
}
@@ -89,7 +85,7 @@ open class ParagraphStyle: NSMutableParagraphStyle, CustomReflectable {
if blockquote != otherParagraph.blockquote
|| headerLevel != otherParagraph.headerLevel
|| htmlParagraph != otherParagraph.htmlParagraph
- || textList != otherParagraph.textList {
+ || textLists != otherParagraph.textLists {
return false
}
@@ -107,7 +103,7 @@ open class ParagraphStyle: NSMutableParagraphStyle, CustomReflectable {
copy.blockquote = blockquote
copy.headerLevel = headerLevel
copy.htmlParagraph = htmlParagraph
- copy.textList = textList
+ copy.textLists = textLists
return copy
}
@@ -119,7 +115,7 @@ open class ParagraphStyle: NSMutableParagraphStyle, CustomReflectable {
copy.blockquote = blockquote
copy.headerLevel = headerLevel
copy.htmlParagraph = htmlParagraph
- copy.textList = textList
+ copy.textLists = textLists
return copy
}
@@ -129,8 +125,8 @@ open class ParagraphStyle: NSMutableParagraphStyle, CustomReflectable {
if blockquote != nil {
hash = hash ^ String(describing: Blockquote.self).hashValue
}
- if let listStyle = textList?.style {
- hash = hash ^ listStyle.hashValue
+ for list in textLists {
+ hash = hash ^ list.style.hashValue
}
hash = hash ^ headerLevel.hashValue
@@ -142,6 +138,6 @@ open class ParagraphStyle: NSMutableParagraphStyle, CustomReflectable {
}
open override var description: String {
- return super.description + " Blockquote: \(String(describing:blockquote)),\n HeaderLevel: \(headerLevel),\n HTMLParagraph: \(String(describing: htmlParagraph)),\n TextList: \(String(describing: textList?.style))"
+ return super.description + " Blockquote: \(String(describing:blockquote)),\n HeaderLevel: \(headerLevel),\n HTMLParagraph: \(String(describing: htmlParagraph)),\n TextLists: \(textLists)"
}
}
diff --git a/Aztec/Classes/TextKit/TextStorage.swift b/Aztec/Classes/TextKit/TextStorage.swift
index 3ef2284be..6e19b8fc5 100644
--- a/Aztec/Classes/TextKit/TextStorage.swift
+++ b/Aztec/Classes/TextKit/TextStorage.swift
@@ -504,7 +504,7 @@ open class TextStorage: NSTextStorage {
let targetStyle = targetValue as? ParagraphStyle
processBlockquoteDifferences(in: domRange, betweenOriginal: sourceStyle?.blockquote, andNew: targetStyle?.blockquote)
- processListDifferences(in: domRange, betweenOriginal: sourceStyle?.textList, andNew: targetStyle?.textList, canMergeLeft: canMergeLeft, canMergeRight: canMergeRight)
+ processListDifferences(in: domRange, betweenOriginal: sourceStyle?.textLists.last, andNew: targetStyle?.textLists.last, canMergeLeft: canMergeLeft, canMergeRight: canMergeRight)
processHeaderDifferences(in: domRange, betweenOriginal: sourceStyle?.headerLevel, andNew: targetStyle?.headerLevel)
processHTMLParagraphDifferences(in: domRange, betweenOriginal: sourceStyle?.htmlParagraph, andNew: targetStyle?.htmlParagraph)
case NSLinkAttributeName:
From f3cd5fc8a6af555202bd05ef91ada6c4645b92a9 Mon Sep 17 00:00:00 2001
From: Sergio Estevao
Date: Mon, 8 May 2017 22:09:06 +0100
Subject: [PATCH 2/7] Fix unit tests.
---
AztecTests/Extensions/NSAttributedStringListsTests.swift | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/AztecTests/Extensions/NSAttributedStringListsTests.swift b/AztecTests/Extensions/NSAttributedStringListsTests.swift
index a953a6d12..fcf606c97 100644
--- a/AztecTests/Extensions/NSAttributedStringListsTests.swift
+++ b/AztecTests/Extensions/NSAttributedStringListsTests.swift
@@ -503,7 +503,7 @@ extension NSAttributedStringListsTests
let range = (sample.string as NSString).range(of: sampleListContents)
let listParagraphStyle = ParagraphStyle()
- listParagraphStyle.textList = TextList(style: .ordered)
+ listParagraphStyle.textLists.append(TextList(style: .ordered))
let attributes = [NSParagraphStyleAttributeName: listParagraphStyle]
sample.addAttributes(attributes, range: range)
From 8b94730628ac4ae57c2a6c897567ee61dccf2c48 Mon Sep 17 00:00:00 2001
From: Sergio Estevao
Date: Mon, 8 May 2017 22:10:49 +0100
Subject: [PATCH 3/7] Add sample content.
---
Example/Example/SampleContent/content.html | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/Example/Example/SampleContent/content.html b/Example/Example/SampleContent/content.html
index 364c112d0..74f772c89 100644
--- a/Example/Example/SampleContent/content.html
+++ b/Example/Example/SampleContent/content.html
@@ -38,6 +38,15 @@ Ordered List:
Two
Three
+
+Nested lists:
+
+ - One
+ - One
- Two
+ - Two
+
+ - Three
+
From a7bd0b4c4d7e3e3aa7eed1868874f49c4ab7d0ef Mon Sep 17 00:00:00 2001
From: Sergio Estevao
Date: Mon, 8 May 2017 22:15:25 +0100
Subject: [PATCH 4/7] All multiple indentations on the same paragraph.
---
Aztec/Classes/Formatters/TextListFormatter.swift | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/Aztec/Classes/Formatters/TextListFormatter.swift b/Aztec/Classes/Formatters/TextListFormatter.swift
index f9286a797..01cef2f2d 100644
--- a/Aztec/Classes/Formatters/TextListFormatter.swift
+++ b/Aztec/Classes/Formatters/TextListFormatter.swift
@@ -31,10 +31,8 @@ class TextListFormatter: ParagraphAttributeFormatter {
newParagraphStyle.setParagraphStyle(paragraphStyle)
}
- if newParagraphStyle.textLists.last == nil {
- newParagraphStyle.headIndent += Metrics.listTextIndentation
- newParagraphStyle.firstLineHeadIndent += Metrics.listTextIndentation
- }
+ newParagraphStyle.headIndent += Metrics.listTextIndentation
+ newParagraphStyle.firstLineHeadIndent += Metrics.listTextIndentation
newParagraphStyle.textLists.append(TextList(style: self.listStyle))
From 60a1b3b381bd5e031c5aac4aac90616d9c3ba84e Mon Sep 17 00:00:00 2001
From: Sergio Estevao
Date: Mon, 8 May 2017 23:18:05 +0100
Subject: [PATCH 5/7] Refactor the list detection algorithms for markers and
position to support nested lists.
---
.../Extensions/NSAttributedString+Lists.swift | 35 ++++++++++++++-----
1 file changed, 27 insertions(+), 8 deletions(-)
diff --git a/Aztec/Classes/Extensions/NSAttributedString+Lists.swift b/Aztec/Classes/Extensions/NSAttributedString+Lists.swift
index 84e2121c5..9f6f1f735 100644
--- a/Aztec/Classes/Extensions/NSAttributedString+Lists.swift
+++ b/Aztec/Classes/Extensions/NSAttributedString+Lists.swift
@@ -71,25 +71,35 @@ extension NSAttributedString
else {
return nil
}
+ let listDepth = paragraphStyle.textLists.count
+
var resultRange = effectiveRange
//Note: The effective range will only return the range of the in location NSParagraphStyleAttributed
// but this can be different on preceding or suceeding range but is the same TextList,
// so we need to expand the range to grab all the TextList coverage.
while resultRange.location > 0 {
- if
+ guard
let paragraphStyle = attribute(NSParagraphStyleAttributeName, at: resultRange.location-1, longestEffectiveRange: &effectiveRange, in: targetRange) as? ParagraphStyle,
- let foundList = paragraphStyle.textLists.last,
- foundList == list {
- resultRange = resultRange.union(withRange: effectiveRange)
+ let foundList = paragraphStyle.textLists.last
+ else {
+ break;
+ }
+ if ((listDepth == paragraphStyle.textLists.count && foundList == list) ||
+ listDepth < paragraphStyle.textLists.count) {
+ resultRange = resultRange.union(withRange: effectiveRange)
} else {
break;
}
}
while resultRange.endLocation < self.length {
- if
+ guard
let paragraphStyle = attribute(NSParagraphStyleAttributeName, at: resultRange.endLocation, longestEffectiveRange: &effectiveRange, in: targetRange) as? ParagraphStyle,
- let foundList = paragraphStyle.textLists.last,
- foundList == list {
+ let foundList = paragraphStyle.textLists.last
+ else {
+ break;
+ }
+ if ((listDepth == paragraphStyle.textLists.count && foundList == list) ||
+ listDepth < paragraphStyle.textLists.count) {
resultRange = resultRange.union(withRange: effectiveRange)
} else {
break;
@@ -108,6 +118,12 @@ extension NSAttributedString
/// - Returns: Returns the index within the list.
///
func itemNumber(in list: TextList, at location: Int) -> Int {
+ guard
+ let paragraphStyle = attribute(NSParagraphStyleAttributeName, at: location, effectiveRange: nil) as? ParagraphStyle
+ else {
+ return NSNotFound
+ }
+ let listDepth = paragraphStyle.textLists.count
guard let rangeOfList = range(of:list, at: location) else {
return NSNotFound
}
@@ -118,7 +134,10 @@ extension NSAttributedString
if NSLocationInRange(location, range) {
return numberInList
}
- numberInList += 1
+ if let paragraphStyle = attribute(NSParagraphStyleAttributeName, at: range.location, effectiveRange: nil) as? ParagraphStyle,
+ listDepth == paragraphStyle.textLists.count {
+ numberInList += 1
+ }
}
return NSNotFound
}
From 67965ac1845bac10d946c34490e98dec725529f6 Mon Sep 17 00:00:00 2001
From: Sergio Estevao
Date: Mon, 8 May 2017 23:18:31 +0100
Subject: [PATCH 6/7] Fix the sample content to be proper nested lists html.
---
Example/Example/SampleContent/content.html | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/Example/Example/SampleContent/content.html b/Example/Example/SampleContent/content.html
index 74f772c89..6069db6a5 100644
--- a/Example/Example/SampleContent/content.html
+++ b/Example/Example/SampleContent/content.html
@@ -41,10 +41,18 @@ Ordered List:
Nested lists:
- - One
- - One
- Two
- - Two
-
+ - One
+
+ - One
+ - Two
+
+
+ - Two
+
+
- Three
From d6387a2411565d4ba12a1008fe470265b95f16e8 Mon Sep 17 00:00:00 2001
From: Sergio Estevao
Date: Tue, 9 May 2017 10:49:43 +0100
Subject: [PATCH 7/7] Support list formatter modes for increasing or
maintaining depth of lists.
---
.../HTMLNodeToNSAttributedString.swift | 4 ++--
.../Classes/Formatters/TextListFormatter.swift | 17 ++++++++++++-----
2 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/Aztec/Classes/Converters/HTMLNodeToNSAttributedString.swift b/Aztec/Classes/Converters/HTMLNodeToNSAttributedString.swift
index 0c6b5b229..1d85675fd 100644
--- a/Aztec/Classes/Converters/HTMLNodeToNSAttributedString.swift
+++ b/Aztec/Classes/Converters/HTMLNodeToNSAttributedString.swift
@@ -275,8 +275,8 @@ class HMTLNodeToNSAttributedString: SafeConverter {
}
public let elementToFormattersMap: [StandardElementType: AttributeFormatter] = [
- .ol: TextListFormatter(style: .ordered),
- .ul: TextListFormatter(style: .unordered),
+ .ol: TextListFormatter(style: .ordered, increaseDepth: true),
+ .ul: TextListFormatter(style: .unordered, increaseDepth: true),
.blockquote: BlockquoteFormatter(),
.strong: BoldFormatter(),
.em: ItalicFormatter(),
diff --git a/Aztec/Classes/Formatters/TextListFormatter.swift b/Aztec/Classes/Formatters/TextListFormatter.swift
index 01cef2f2d..3eb5d6b92 100644
--- a/Aztec/Classes/Formatters/TextListFormatter.swift
+++ b/Aztec/Classes/Formatters/TextListFormatter.swift
@@ -14,12 +14,15 @@ class TextListFormatter: ParagraphAttributeFormatter {
///
let placeholderAttributes: [String : Any]?
+ /// Tells if the formatter is increasing the depth of a list or simple changing the current one if any
+ let increaseDepth: Bool
/// Designated Initializer
///
- init(style: TextList.Style, placeholderAttributes: [String : Any]? = nil) {
+ init(style: TextList.Style, placeholderAttributes: [String : Any]? = nil, increaseDepth: Bool = false) {
self.listStyle = style
self.placeholderAttributes = placeholderAttributes
+ self.increaseDepth = increaseDepth
}
@@ -31,10 +34,14 @@ class TextListFormatter: ParagraphAttributeFormatter {
newParagraphStyle.setParagraphStyle(paragraphStyle)
}
- newParagraphStyle.headIndent += Metrics.listTextIndentation
- newParagraphStyle.firstLineHeadIndent += Metrics.listTextIndentation
-
- newParagraphStyle.textLists.append(TextList(style: self.listStyle))
+ if (increaseDepth || newParagraphStyle.textLists.isEmpty) {
+ newParagraphStyle.headIndent += Metrics.listTextIndentation
+ newParagraphStyle.firstLineHeadIndent += Metrics.listTextIndentation
+ newParagraphStyle.textLists.append(TextList(style: self.listStyle))
+ } else {
+ newParagraphStyle.textLists.removeLast()
+ newParagraphStyle.textLists.append(TextList(style: self.listStyle))
+ }
var resultingAttributes = attributes
resultingAttributes[NSParagraphStyleAttributeName] = newParagraphStyle