Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Aztec/Classes/Converters/HTMLNodeToNSAttributedString.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
41 changes: 30 additions & 11 deletions Aztec/Classes/Extensions/NSAttributedString+Lists.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,30 +66,40 @@ 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
}
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.textList,
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.textList,
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;
Expand All @@ -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
}
Expand All @@ -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
}
Expand Down Expand Up @@ -177,7 +196,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.
Expand All @@ -196,7 +215,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
}
Expand Down
26 changes: 17 additions & 9 deletions Aztec/Classes/Formatters/TextListFormatter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}


Expand All @@ -31,13 +34,15 @@ class TextListFormatter: ParagraphAttributeFormatter {
newParagraphStyle.setParagraphStyle(paragraphStyle)
}

if newParagraphStyle.textList == nil {
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))
}

newParagraphStyle.textList = TextList(style: self.listStyle)

var resultingAttributes = attributes
resultingAttributes[NSParagraphStyleAttributeName] = newParagraphStyle

Expand All @@ -46,7 +51,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
}
Expand All @@ -55,7 +61,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
Expand All @@ -64,16 +70,18 @@ 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
}

return list.style == listStyle
}

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)
}
}

2 changes: 1 addition & 1 deletion Aztec/Classes/TextKit/LayoutManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
30 changes: 13 additions & 17 deletions Aztec/Classes/TextKit/ParagraphStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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])
}
}

Expand All @@ -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

Expand All @@ -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
Expand All @@ -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))
Expand All @@ -60,7 +56,7 @@ open class ParagraphStyle: NSMutableParagraphStyle, CustomReflectable {
blockquote = paragrahStyle.blockquote
headerLevel = paragrahStyle.headerLevel
htmlParagraph = paragrahStyle.htmlParagraph
textList = paragrahStyle.textList
textLists = paragrahStyle.textLists
}
}

Expand Down Expand Up @@ -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
}

Expand All @@ -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
}
Expand All @@ -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
}
Expand All @@ -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
Expand All @@ -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)"
}
}
2 changes: 1 addition & 1 deletion Aztec/Classes/TextKit/TextStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion AztecTests/Extensions/NSAttributedStringListsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
17 changes: 17 additions & 0 deletions Example/Example/SampleContent/content.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,23 @@ <h3>Ordered List:</h3>
<li>Two</li>
<li>Three</li>
</ol>

<h3>Nested lists:</h3>
<ol>
<li>One
<ol>
<li>One</li>
<li>Two</li>
</ol>
</li>
<li>Two
<ul>
<li>One</li>
<li>Two</li>
</ul>
</li>
<li>Three</li>
</ol>
</p>

<hr/>
Expand Down