From 29af51f34bca9efbc4ce037e70354eac5d703829 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 6 Nov 2017 14:51:11 -0300 Subject: [PATCH 01/20] Aztec is now Swift 4 Friendly. Mark I --- Aztec.xcodeproj/project.pbxproj | 32 +++-- .../NSAttributedString+Analyzers.swift | 4 +- .../NSAttributedString+Attachments.swift | 8 +- .../NSAttributedString+CharacterName.swift | 2 +- .../NSAttributedString+FontTraits.swift | 10 +- .../NSAttributedString+HTMLInitializer.swift | 2 +- .../Extensions/NSAttributedString+Lists.swift | 14 +-- .../Extensions/NSAttributedString+Strip.swift | 2 +- .../NSAttributedStringKey+Conversion.swift | 32 +++++ .../Extensions/NSTextingResult+Helpers.swift | 2 +- .../Extensions/UIPasteboard+Helpers.swift | 8 +- .../Formatters/Base/AttributeFormatter.swift | 16 +-- .../Formatters/Base/FontFormatter.swift | 22 ++-- .../Base/StandardAttributeFormatter.swift | 14 +-- .../Implementations/BlockquoteFormatter.swift | 21 ++-- .../Implementations/BoldFormatter.swift | 2 +- .../Implementations/ColorFormatter.swift | 4 +- .../Implementations/HRFormatter.swift | 4 +- .../Implementations/HTMLDivFormatter.swift | 20 +-- .../HTMLParagraphFormatter.swift | 20 +-- .../Implementations/HeaderFormatter.swift | 34 ++--- .../Implementations/ImageFormatter.swift | 6 +- .../Implementations/ItalicFormatter.swift | 2 +- .../Implementations/LinkFormatter.swift | 6 +- .../Implementations/PreFormatter.swift | 16 +-- .../StrikethroughFormatter.swift | 4 +- .../Implementations/TextListFormatter.swift | 24 ++-- .../Implementations/UnderlineFormatter.swift | 4 +- .../Implementations/VideoFormatter.swift | 6 +- Aztec/Classes/GUI/FormatBar/FormatBar.swift | 4 +- .../Attributes/HTMLRepresentation.swift | 4 +- .../Attributes/UnsupportedHTML.swift | 2 +- .../Conversions/AttributedStringParser.swift | 44 +++---- .../AttributedStringSerializer.swift | 36 +++--- Aztec/Classes/TextKit/HTMLStorage.swift | 18 +-- Aztec/Classes/TextKit/LayoutManager.swift | 26 ++-- Aztec/Classes/TextKit/MediaAttachment.swift | 4 +- Aztec/Classes/TextKit/ParagraphStyle.swift | 6 +- Aztec/Classes/TextKit/TextStorage.swift | 22 ++-- Aztec/Classes/TextKit/TextView.swift | 118 ++++++++++-------- .../NSAttributedStringAnalyzerTests.swift | 8 +- ...AttributedStringHTMLInitializerTests.swift | 4 +- .../NSAttributedStringListsTests.swift | 2 +- .../Formatters/BlockquoteFormatterTests.swift | 4 +- .../Formatters/FontFormatterTests.swift | 17 +-- .../Formatters/HeaderFormatterTests.swift | 12 +- AztecTests/Formatters/PreFormaterTests.swift | 14 +-- .../AttributedStringParserTests.swift | 6 +- .../AttributedStringSerializerTests.swift | 6 +- AztecTests/TextKit/TextStorageTests.swift | 16 +-- AztecTests/TextKit/TextViewTests.swift | 6 +- .../AztecExample.xcodeproj/project.pbxproj | 28 +++-- .../Example/CommentAttachmentRenderer.swift | 6 +- Example/Example/EditorDemoController.swift | 35 +++--- Example/Example/HTMLAttachmentRenderer.swift | 6 +- .../SpecialTagAttachmentRenderer.swift | 2 +- 56 files changed, 433 insertions(+), 364 deletions(-) create mode 100644 Aztec/Classes/Extensions/NSAttributedStringKey+Conversion.swift diff --git a/Aztec.xcodeproj/project.pbxproj b/Aztec.xcodeproj/project.pbxproj index a7f9b0c02..e004ccb1f 100644 --- a/Aztec.xcodeproj/project.pbxproj +++ b/Aztec.xcodeproj/project.pbxproj @@ -40,6 +40,7 @@ B542D6421E9EB122009D12D3 /* PreFormaterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B542D6411E9EB122009D12D3 /* PreFormaterTests.swift */; }; B551A4A01E770B3800EE3A7F /* UIFont+Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = B551A49F1E770B3800EE3A7F /* UIFont+Emoji.swift */; }; B572AC281E817CFE008948C2 /* CommentAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = B572AC271E817CFE008948C2 /* CommentAttachment.swift */; }; + B574F4A41FB0CF3B0048F355 /* NSAttributedStringKey+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B574F4A31FB0CF3A0048F355 /* NSAttributedStringKey+Conversion.swift */; }; B57534501F267D0B009D4904 /* Array+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B575344F1F267D0B009D4904 /* Array+Helpers.swift */; }; B57534521F267D63009D4904 /* ArrayHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57534511F267D63009D4904 /* ArrayHelperTests.swift */; }; B57D1C3D1E92C38000EA4B16 /* HTMLAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D1C3C1E92C38000EA4B16 /* HTMLAttachment.swift */; }; @@ -217,6 +218,7 @@ B542D6411E9EB122009D12D3 /* PreFormaterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreFormaterTests.swift; sourceTree = ""; }; B551A49F1E770B3800EE3A7F /* UIFont+Emoji.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIFont+Emoji.swift"; sourceTree = ""; }; B572AC271E817CFE008948C2 /* CommentAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommentAttachment.swift; sourceTree = ""; }; + B574F4A31FB0CF3A0048F355 /* NSAttributedStringKey+Conversion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedStringKey+Conversion.swift"; sourceTree = ""; }; B575344F1F267D0B009D4904 /* Array+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+Helpers.swift"; sourceTree = ""; }; B57534511F267D63009D4904 /* ArrayHelperTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ArrayHelperTests.swift; path = Extensions/ArrayHelperTests.swift; sourceTree = ""; }; B57D1C3C1E92C38000EA4B16 /* HTMLAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTMLAttachment.swift; sourceTree = ""; }; @@ -500,6 +502,7 @@ B5BC4FED1DA2C17800614582 /* NSAttributedString+Lists.swift */, F10BE6191EA7AE9D002E4625 /* NSAttributedString+ReplaceOcurrences.swift */, B50CE7311F1FA6260018CAA1 /* NSAttributedString+Strip.swift */, + B574F4A31FB0CF3A0048F355 /* NSAttributedStringKey+Conversion.swift */, FFD0FEB61DAE59A700430586 /* NSLayoutManager+Attachments.swift */, F10BE6171EA7ADA6002E4625 /* NSMutableAttributedString+ReplaceOcurrences.swift */, F18733C41DA096EE005AEB80 /* NSRange+Helpers.swift */, @@ -907,12 +910,12 @@ 5951CB8D1D8BC93600E1866F = { CreatedOnToolsVersion = 8.0; DevelopmentTeam = PZYM8XX95Q; - LastSwiftMigration = 0810; + LastSwiftMigration = 0910; ProvisioningStyle = Manual; }; 5951CB961D8BC93600E1866F = { CreatedOnToolsVersion = 8.0; - LastSwiftMigration = 0820; + LastSwiftMigration = 0910; ProvisioningStyle = Automatic; }; E8CE3EFE1F213AAA003254AB = { @@ -1003,6 +1006,7 @@ 599F254F1D8BC9A1002871D6 /* FormatBarItem.swift in Sources */, F17BC8931F4E4BA500398E2B /* HTMLRepresentation.swift in Sources */, F18B81ED1EA560B700885F43 /* StringUTF16+RangeConversion.swift in Sources */, + B574F4A41FB0CF3B0048F355 /* NSAttributedStringKey+Conversion.swift in Sources */, F12F58631EF20394008AE298 /* AttributeFormatter.swift in Sources */, F19544051F588F1A00671B73 /* CSSParser.swift in Sources */, 599F254E1D8BC9A1002871D6 /* FormatBarDelegate.swift in Sources */, @@ -1263,7 +1267,8 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/Aztec/Modulemaps/libxml2"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 1; }; name = Debug; @@ -1291,7 +1296,8 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/Aztec/Modulemaps/libxml2"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 1; }; name = Release; @@ -1311,7 +1317,8 @@ PRODUCT_BUNDLE_IDENTIFIER = com.wordpress.AztecTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -1329,7 +1336,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.wordpress.AztecTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; }; name = Release; }; @@ -1458,7 +1466,8 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/Aztec/Modulemaps/libxml2"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 1; }; name = Profiling; @@ -1477,7 +1486,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.wordpress.AztecTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; }; name = Profiling; }; @@ -1565,7 +1575,8 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/Aztec/Modulemaps/libxml2"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 1; }; name = "Release-Alpha"; @@ -1585,7 +1596,8 @@ PRODUCT_BUNDLE_IDENTIFIER = com.wordpress.AztecTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; }; name = "Release-Alpha"; }; diff --git a/Aztec/Classes/Extensions/NSAttributedString+Analyzers.swift b/Aztec/Classes/Extensions/NSAttributedString+Analyzers.swift index d9351f6e6..4fd484f2a 100644 --- a/Aztec/Classes/Extensions/NSAttributedString+Analyzers.swift +++ b/Aztec/Classes/Extensions/NSAttributedString+Analyzers.swift @@ -14,7 +14,7 @@ extension NSAttributedString { return false } - return attribute(NSLinkAttributeName, at: beforeRange.location, effectiveRange: nil) != nil + return attribute(.link, at: beforeRange.location, effectiveRange: nil) != nil } /// Returns true if the text immediately succeding a given location contains the NSLinkAttribute. @@ -25,7 +25,7 @@ extension NSAttributedString { return false } - return attribute(NSLinkAttributeName, at: afterRange.location, effectiveRange: nil) != nil + return attribute(.link, at: afterRange.location, effectiveRange: nil) != nil } /// Returns the Substring at the specified range, whenever the received range is valid, or nil diff --git a/Aztec/Classes/Extensions/NSAttributedString+Attachments.swift b/Aztec/Classes/Extensions/NSAttributedString+Attachments.swift index 65ff6df17..342b2f9ec 100644 --- a/Aztec/Classes/Extensions/NSAttributedString+Attachments.swift +++ b/Aztec/Classes/Extensions/NSAttributedString+Attachments.swift @@ -20,9 +20,9 @@ extension NSAttributedString /// Helper Initializer: returns an Attributed String, with the specified attachment, styled with a given /// collection of attributes. /// - convenience init(attachment: NSTextAttachment, attributes: [String: Any]) { + convenience init(attachment: NSTextAttachment, attributes: [NSAttributedStringKey: Any]) { var attributesWithAttachment = attributes - attributesWithAttachment[NSAttachmentAttributeName] = attachment + attributesWithAttachment[.attachment] = attachment self.init(string: NSAttributedString.textAttachmentString, attributes: attributesWithAttachment) } @@ -52,7 +52,7 @@ extension NSAttributedString /// func enumerateAttachmentsOfType(_ type: T.Type, range: NSRange? = nil, block: ((T, NSRange, UnsafeMutablePointer) -> Void)) { let range = range ?? NSMakeRange(0, length) - enumerateAttribute(NSAttachmentAttributeName, in: range, options: []) { (object, range, stop) in + enumerateAttribute(.attachment, in: range, options: []) { (object, range, stop) in if let object = object as? T { block(object, range, stop) } @@ -69,7 +69,7 @@ extension NSAttributedString public func ranges(forAttachment attachment: NSTextAttachment) -> [NSRange] { let range = NSRange(location: 0, length: length) var attachmentRanges = [NSRange]() - enumerateAttribute(NSAttachmentAttributeName, in: range, options: []) { (value, effectiveRange, nil) in + enumerateAttribute(.attachment, in: range, options: []) { (value, effectiveRange, nil) in guard let foundAttachment = value as? NSTextAttachment, foundAttachment == attachment else { return } diff --git a/Aztec/Classes/Extensions/NSAttributedString+CharacterName.swift b/Aztec/Classes/Extensions/NSAttributedString+CharacterName.swift index b79b89531..8ec869e25 100644 --- a/Aztec/Classes/Extensions/NSAttributedString+CharacterName.swift +++ b/Aztec/Classes/Extensions/NSAttributedString+CharacterName.swift @@ -1,7 +1,7 @@ import Foundation extension NSAttributedString { - convenience init(_ characterName: Character.Name, attributes: [String:Any]?) { + convenience init(_ characterName: Character.Name, attributes: [NSAttributedStringKey: Any]?) { self.init(string: String(characterName), attributes: attributes) } } diff --git a/Aztec/Classes/Extensions/NSAttributedString+FontTraits.swift b/Aztec/Classes/Extensions/NSAttributedString+FontTraits.swift index c911fc2ff..dd7d70e96 100644 --- a/Aztec/Classes/Extensions/NSAttributedString+FontTraits.swift +++ b/Aztec/Classes/Extensions/NSAttributedString+FontTraits.swift @@ -15,7 +15,7 @@ public extension NSAttributedString { /// - Returns: True if found. /// public func fontTrait(_ traits: UIFontDescriptorSymbolicTraits, existsAtIndex index: Int) -> Bool { - guard let attr = attribute(NSFontAttributeName, at: index, effectiveRange: nil) else { + guard let attr = attribute(.font, at: index, effectiveRange: nil) else { return false } if let font = attr as? UIFont { @@ -37,7 +37,7 @@ public extension NSAttributedString { var spansRange = true // Assume we're removing the trait. If the trait is missing anywhere in the range assign it. - enumerateAttribute(NSFontAttributeName, + enumerateAttribute(.font, in: range, options: [], using: { (object: Any?, range: NSRange, stop: UnsafeMutablePointer) in @@ -75,7 +75,7 @@ public extension NSMutableAttributedString { fileprivate func modify(_ fontTraits: UIFontDescriptorSymbolicTraits, range: NSRange, enable: Bool) { - enumerateAttribute(NSFontAttributeName, + enumerateAttribute(.font, in: range, options: [], using: { (object: Any, range: NSRange, stop: UnsafeMutablePointer) in @@ -86,8 +86,8 @@ public extension NSMutableAttributedString { let newFont = font.modifyTraits(fontTraits, enable: enable) self.beginEditing() - self.removeAttribute(NSFontAttributeName, range: range) - self.addAttribute(NSFontAttributeName, value: newFont, range: range) + self.removeAttribute(.font, range: range) + self.addAttribute(.font, value: newFont, range: range) self.endEditing() }) } diff --git a/Aztec/Classes/Extensions/NSAttributedString+HTMLInitializer.swift b/Aztec/Classes/Extensions/NSAttributedString+HTMLInitializer.swift index 1c5a5077e..917706158 100644 --- a/Aztec/Classes/Extensions/NSAttributedString+HTMLInitializer.swift +++ b/Aztec/Classes/Extensions/NSAttributedString+HTMLInitializer.swift @@ -5,7 +5,7 @@ extension NSAttributedString { convenience init( withHTML html: String, - defaultAttributes: [String: Any], + defaultAttributes: [NSAttributedStringKey: Any], postProcessingHTMLWith htmlTreeProcessor: HTMLTreeProcessor? = nil) { let htmlParser = HTMLParser() diff --git a/Aztec/Classes/Extensions/NSAttributedString+Lists.swift b/Aztec/Classes/Extensions/NSAttributedString+Lists.swift index 475541af4..1e53dd622 100644 --- a/Aztec/Classes/Extensions/NSAttributedString+Lists.swift +++ b/Aztec/Classes/Extensions/NSAttributedString+Lists.swift @@ -18,7 +18,7 @@ extension NSAttributedString { var effectiveRange = NSRange() let targetRange = rangeOfEntireString guard - let paragraphStyle = attribute(NSParagraphStyleAttributeName, at: location, longestEffectiveRange: &effectiveRange, in: targetRange) as? ParagraphStyle, + let paragraphStyle = attribute(.paragraphStyle, at: location, longestEffectiveRange: &effectiveRange, in: targetRange) as? ParagraphStyle, let foundList = paragraphStyle.lists.last, foundList == list else { @@ -32,7 +32,7 @@ extension NSAttributedString { // so we need to expand the range to grab all the TextList coverage. while resultRange.location > 0 { guard - let paragraphStyle = attribute(NSParagraphStyleAttributeName, at: resultRange.location-1, longestEffectiveRange: &effectiveRange, in: targetRange) as? ParagraphStyle, + let paragraphStyle = attribute(.paragraphStyle, at: resultRange.location-1, longestEffectiveRange: &effectiveRange, in: targetRange) as? ParagraphStyle, let foundList = paragraphStyle.lists.last else { break; @@ -46,7 +46,7 @@ extension NSAttributedString { } while resultRange.endLocation < self.length { guard - let paragraphStyle = attribute(NSParagraphStyleAttributeName, at: resultRange.endLocation, longestEffectiveRange: &effectiveRange, in: targetRange) as? ParagraphStyle, + let paragraphStyle = attribute(.paragraphStyle, at: resultRange.endLocation, longestEffectiveRange: &effectiveRange, in: targetRange) as? ParagraphStyle, let foundList = paragraphStyle.lists.last else { break; @@ -72,7 +72,7 @@ extension NSAttributedString { /// func itemNumber(in list: TextList, at location: Int) -> Int { guard - let paragraphStyle = attribute(NSParagraphStyleAttributeName, at: location, effectiveRange: nil) as? ParagraphStyle + let paragraphStyle = attribute(.paragraphStyle, at: location, effectiveRange: nil) as? ParagraphStyle else { return NSNotFound } @@ -87,7 +87,7 @@ extension NSAttributedString { if NSLocationInRange(location, enclosingRange) { return numberInList } - if let paragraphStyle = attribute(NSParagraphStyleAttributeName, at: enclosingRange.location, effectiveRange: nil) as? ParagraphStyle, + if let paragraphStyle = attribute(.paragraphStyle, at: enclosingRange.location, effectiveRange: nil) as? ParagraphStyle, listDepth == paragraphStyle.lists.count { numberInList += 1 } @@ -108,7 +108,7 @@ extension NSAttributedString { /// - Returns: A TextList optional. /// func textListAttribute(atIndex index: Int) -> TextList? { - return (attribute(NSParagraphStyleAttributeName, at: index, effectiveRange: nil) as? ParagraphStyle)?.lists.last + return (attribute(.paragraphStyle, at: index, effectiveRange: nil) as? ParagraphStyle)?.lists.last } /// Returns the TextList attribute, assuming that there is one, spanning the specified Range. @@ -125,7 +125,7 @@ extension NSAttributedString { // var list: TextList? - enumerateAttribute(NSParagraphStyleAttributeName, in: range, options: []) { (attribute, range, stop) in + enumerateAttribute(.paragraphStyle, in: range, options: []) { (attribute, range, stop) in if let paragraphStyle = attribute as? ParagraphStyle { list = paragraphStyle.lists.last } diff --git a/Aztec/Classes/Extensions/NSAttributedString+Strip.swift b/Aztec/Classes/Extensions/NSAttributedString+Strip.swift index 169449649..00c384bc8 100644 --- a/Aztec/Classes/Extensions/NSAttributedString+Strip.swift +++ b/Aztec/Classes/Extensions/NSAttributedString+Strip.swift @@ -31,6 +31,6 @@ extension NSAttributedString { /// Returns true if a given instance's kind matches with a specified type. /// private func isObject(_ object: Any, kindOf type: T) -> Bool { - return type(of: object) is T + return Swift.type(of: object) is T } } diff --git a/Aztec/Classes/Extensions/NSAttributedStringKey+Conversion.swift b/Aztec/Classes/Extensions/NSAttributedStringKey+Conversion.swift new file mode 100644 index 000000000..524d4bb2e --- /dev/null +++ b/Aztec/Classes/Extensions/NSAttributedStringKey+Conversion.swift @@ -0,0 +1,32 @@ +import Foundation +import UIKit + + +// MARK: - NSAttributedStringKey Helpers +// +extension NSAttributedStringKey { + + /// + /// + static func convertToRaw(attributes: [NSAttributedStringKey: Any]) -> [String: Any] { + var output = [String: Any]() + for (key, value) in attributes { + output[key.rawValue] = value + } + + return output + } + + + /// + /// + static func convertFromRaw(attributes: [String: Any]) -> [NSAttributedStringKey: Any] { + var output = [NSAttributedStringKey: Any]() + for (key, value) in attributes { + let wrappedKey = NSAttributedStringKey(key) + output[wrappedKey] = value + } + + return output + } +} diff --git a/Aztec/Classes/Extensions/NSTextingResult+Helpers.swift b/Aztec/Classes/Extensions/NSTextingResult+Helpers.swift index 274cc4b50..425268b4e 100644 --- a/Aztec/Classes/Extensions/NSTextingResult+Helpers.swift +++ b/Aztec/Classes/Extensions/NSTextingResult+Helpers.swift @@ -14,7 +14,7 @@ public extension NSTextCheckingResult { return nil } - let nsrange = rangeAt(position) + let nsrange = self.range(at: position) guard nsrange.location != NSNotFound else { return nil diff --git a/Aztec/Classes/Extensions/UIPasteboard+Helpers.swift b/Aztec/Classes/Extensions/UIPasteboard+Helpers.swift index b4d33c48d..b58dad82c 100644 --- a/Aztec/Classes/Extensions/UIPasteboard+Helpers.swift +++ b/Aztec/Classes/Extensions/UIPasteboard+Helpers.swift @@ -75,9 +75,9 @@ private extension UIPasteboard { /// String Initialization Options /// private struct StringOptions { - static let RTFText = [NSDocumentTypeDocumentAttribute: NSRTFTextDocumentType] - static let RTFDText = [NSDocumentTypeDocumentAttribute: NSRTFDTextDocumentType] - static let plainText = [NSDocumentTypeDocumentAttribute: NSPlainTextDocumentType] + static let RTFText = [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.rtf] + static let RTFDText = [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.rtfd] + static let plainText = [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.plain] } /// Attempts to unarchive a Pasteboard's Entry into a NSAttributedString Instance. @@ -88,7 +88,7 @@ private extension UIPasteboard { /// /// - Returns: NSAttributed String with the contents of the specified Pasteboard entry, if any. /// - private func unarchiveAttributedString(fromPasteboardCFType type: CFString, with options: [String: Any]) -> NSAttributedString? { + private func unarchiveAttributedString(fromPasteboardCFType type: CFString, with options: [NSAttributedString.DocumentReadingOptionKey: Any]) -> NSAttributedString? { guard let data = data(forPasteboardType: String(type)) else { return nil } diff --git a/Aztec/Classes/Formatters/Base/AttributeFormatter.swift b/Aztec/Classes/Formatters/Base/AttributeFormatter.swift index 3e0e0be9d..0707942a6 100644 --- a/Aztec/Classes/Formatters/Base/AttributeFormatter.swift +++ b/Aztec/Classes/Formatters/Base/AttributeFormatter.swift @@ -11,7 +11,7 @@ protocol AttributeFormatter { /// Attributes to be used the Content Placeholder, when / if needed. /// - var placeholderAttributes: [String: Any]? { get } + var placeholderAttributes: [NSAttributedStringKey: Any]? { get } /// Toggles an attribute in the specified range of a text storage, and returns the new /// Selected Range. This is required because, in several scenarios, we may need to add a "Zero Width Space", @@ -29,7 +29,7 @@ protocol AttributeFormatter { /// /// - Parameter attributes: attributes to be checked. /// - Returns: the new attribute dictionary with the toggle applied. - @discardableResult func toggle(in attributes: [String: Any]) -> [String: Any] + @discardableResult func toggle(in attributes: [NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] /// Checks if the attribute is present in a given Attributed String at the specified index. /// @@ -40,7 +40,7 @@ protocol AttributeFormatter { /// - Parameter attributes: the original attributes to apply to /// - Returns: the resulting attributes dictionary /// - func apply(to attributes: [String: Any]) -> [String: Any] + func apply(to attributes: [NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] /// Apply the compound attributes to the provided attributes dictionary. /// @@ -51,14 +51,14 @@ protocol AttributeFormatter { /// - Returns: /// - the resulting attributes dictionary /// - func apply(to attributes: [String: Any], andStore representation: HTMLRepresentation?) -> [String: Any] + func apply(to attributes: [NSAttributedStringKey: Any], andStore representation: HTMLRepresentation?) -> [NSAttributedStringKey: Any] /// Remove the compound attributes from the provided list. /// /// - Parameter attributes: the original attributes to remove from /// - Returns: the resulting attributes dictionary /// - func remove(from attributes: [String: Any]) -> [String: Any] + func remove(from attributes: [NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] /// Applies the Formatter's Attributes into a given string, at the specified range. /// @@ -70,7 +70,7 @@ protocol AttributeFormatter { /// Checks if the attribute is present in a dictionary of attributes. /// - func present(in attributes: [String: Any]) -> Bool + func present(in attributes: [NSAttributedStringKey: Any]) -> Bool func applicationRange(for range: NSRange, in text: NSAttributedString) -> NSRange @@ -85,7 +85,7 @@ extension AttributeFormatter { /// The default implementation forwards the call. This is probably good enough for all /// classes that implement this protocol. /// - func apply(to attributes: [String : Any]) -> [String: Any] { + func apply(to attributes: [NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] { return apply(to: attributes, andStore: nil) } @@ -122,7 +122,7 @@ extension AttributeFormatter { } @discardableResult - func toggle(in attributes: [String: Any]) -> [String: Any] { + func toggle(in attributes: [NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] { if present(in: attributes) { return remove(from: attributes) } else { diff --git a/Aztec/Classes/Formatters/Base/FontFormatter.swift b/Aztec/Classes/Formatters/Base/FontFormatter.swift index 81ccda35a..55749d3dc 100644 --- a/Aztec/Classes/Formatters/Base/FontFormatter.swift +++ b/Aztec/Classes/Formatters/Base/FontFormatter.swift @@ -3,12 +3,12 @@ import UIKit class FontFormatter: AttributeFormatter { - var placeholderAttributes: [String : Any]? { return nil } + var placeholderAttributes: [NSAttributedStringKey: Any]? { return nil } - let htmlRepresentationKey: String + let htmlRepresentationKey: NSAttributedStringKey let traits: UIFontDescriptorSymbolicTraits - init(traits: UIFontDescriptorSymbolicTraits, htmlRepresentationKey: String) { + init(traits: UIFontDescriptorSymbolicTraits, htmlRepresentationKey: NSAttributedStringKey) { self.htmlRepresentationKey = htmlRepresentationKey self.traits = traits } @@ -21,9 +21,9 @@ class FontFormatter: AttributeFormatter { return false } - func apply(to attributes: [String : Any], andStore representation: HTMLRepresentation?) -> [String: Any] { + func apply(to attributes: [NSAttributedStringKey: Any], andStore representation: HTMLRepresentation?) -> [NSAttributedStringKey: Any] { - guard let font = attributes[NSFontAttributeName] as? UIFont else { + guard let font = attributes[.font] as? UIFont else { return attributes } @@ -31,28 +31,28 @@ class FontFormatter: AttributeFormatter { var resultingAttributes = attributes - resultingAttributes[NSFontAttributeName] = newFont + resultingAttributes[.font] = newFont resultingAttributes[htmlRepresentationKey] = representation return resultingAttributes } - func remove(from attributes: [String : Any]) -> [String: Any] { + func remove(from attributes: [NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] { var resultingAttributes = attributes - guard let font = attributes[NSFontAttributeName] as? UIFont else { + guard let font = attributes[.font] as? UIFont else { return attributes } let newFont = font.modifyTraits(traits, enable: false) - resultingAttributes[NSFontAttributeName] = newFont + resultingAttributes[.font] = newFont resultingAttributes.removeValue(forKey: htmlRepresentationKey) return resultingAttributes } - func present(in attributes: [String : Any]) -> Bool { - guard let font = attributes[NSFontAttributeName] as? UIFont else { + func present(in attributes: [NSAttributedStringKey : Any]) -> Bool { + guard let font = attributes[.font] as? UIFont else { return false } let enabled = font.containsTraits(traits) diff --git a/Aztec/Classes/Formatters/Base/StandardAttributeFormatter.swift b/Aztec/Classes/Formatters/Base/StandardAttributeFormatter.swift index 6bfc34f4c..c7ae2b584 100644 --- a/Aztec/Classes/Formatters/Base/StandardAttributeFormatter.swift +++ b/Aztec/Classes/Formatters/Base/StandardAttributeFormatter.swift @@ -4,16 +4,16 @@ import UIKit /// Formatter to apply simple value (NSNumber, UIColor) attributes to an attributed string. class StandardAttributeFormatter: AttributeFormatter { - var placeholderAttributes: [String : Any]? { return nil } + var placeholderAttributes: [NSAttributedStringKey: Any]? { return nil } - let attributeKey: String + let attributeKey: NSAttributedStringKey var attributeValue: Any - let htmlRepresentationKey: String + let htmlRepresentationKey: NSAttributedStringKey // MARK: - Init - init(attributeKey: String, attributeValue: Any, htmlRepresentationKey: String) { + init(attributeKey: NSAttributedStringKey, attributeValue: Any, htmlRepresentationKey: NSAttributedStringKey) { self.attributeKey = attributeKey self.attributeValue = attributeValue self.htmlRepresentationKey = htmlRepresentationKey @@ -27,7 +27,7 @@ class StandardAttributeFormatter: AttributeFormatter { return false } - func apply(to attributes: [String : Any], andStore representation: HTMLRepresentation?) -> [String: Any] { + func apply(to attributes: [NSAttributedStringKey: Any], andStore representation: HTMLRepresentation?) -> [NSAttributedStringKey: Any] { var resultingAttributes = attributes resultingAttributes[attributeKey] = attributeValue @@ -36,7 +36,7 @@ class StandardAttributeFormatter: AttributeFormatter { return resultingAttributes } - func remove(from attributes: [String : Any]) -> [String: Any] { + func remove(from attributes: [NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] { var resultingAttributes = attributes resultingAttributes.removeValue(forKey: attributeKey) @@ -45,7 +45,7 @@ class StandardAttributeFormatter: AttributeFormatter { return resultingAttributes } - func present(in attributes: [String : Any]) -> Bool { + func present(in attributes: [NSAttributedStringKey: Any]) -> Bool { let enabled = attributes[attributeKey] != nil return enabled } diff --git a/Aztec/Classes/Formatters/Implementations/BlockquoteFormatter.swift b/Aztec/Classes/Formatters/Implementations/BlockquoteFormatter.swift index 698a6983b..9810ccace 100644 --- a/Aztec/Classes/Formatters/Implementations/BlockquoteFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/BlockquoteFormatter.swift @@ -8,34 +8,34 @@ class BlockquoteFormatter: ParagraphAttributeFormatter { /// Attributes to be added by default /// - let placeholderAttributes: [String : Any]? + let placeholderAttributes: [NSAttributedStringKey: Any]? /// Designated Initializer /// - init(placeholderAttributes: [String : Any]? = nil) { + init(placeholderAttributes: [NSAttributedStringKey: Any]? = nil) { self.placeholderAttributes = placeholderAttributes } // MARK: - Overwriten Methods - func apply(to attributes: [String : Any], andStore representation: HTMLRepresentation?) -> [String: Any] { + func apply(to attributes: [NSAttributedStringKey: Any], andStore representation: HTMLRepresentation?) -> [NSAttributedStringKey: Any] { let newParagraphStyle = ParagraphStyle() - if let paragraphStyle = attributes[NSParagraphStyleAttributeName] as? NSParagraphStyle { + if let paragraphStyle = attributes[.paragraphStyle] as? NSParagraphStyle { newParagraphStyle.setParagraphStyle(paragraphStyle) } newParagraphStyle.appendProperty(Blockquote(with: representation)) var resultingAttributes = attributes - resultingAttributes[NSParagraphStyleAttributeName] = newParagraphStyle + resultingAttributes[.paragraphStyle] = newParagraphStyle return resultingAttributes } - func remove(from attributes:[String: Any]) -> [String: Any] { - guard let paragraphStyle = attributes[NSParagraphStyleAttributeName] as? ParagraphStyle, + func remove(from attributes:[NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] { + guard let paragraphStyle = attributes[.paragraphStyle] as? ParagraphStyle, !paragraphStyle.blockquotes.isEmpty else { return attributes @@ -46,15 +46,14 @@ class BlockquoteFormatter: ParagraphAttributeFormatter { newParagraphStyle.removeProperty(ofType: Blockquote.self) var resultingAttributes = attributes - resultingAttributes[NSParagraphStyleAttributeName] = newParagraphStyle + resultingAttributes[.paragraphStyle] = newParagraphStyle return resultingAttributes } - func present(in attributes: [String : Any]) -> Bool { - guard let style = attributes[NSParagraphStyleAttributeName] as? ParagraphStyle else { + func present(in attributes: [NSAttributedStringKey: Any]) -> Bool { + guard let style = attributes[.paragraphStyle] as? ParagraphStyle else { return false } return !style.blockquotes.isEmpty } } - diff --git a/Aztec/Classes/Formatters/Implementations/BoldFormatter.swift b/Aztec/Classes/Formatters/Implementations/BoldFormatter.swift index 48aa281e7..896f8b1ef 100644 --- a/Aztec/Classes/Formatters/Implementations/BoldFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/BoldFormatter.swift @@ -1,7 +1,7 @@ import UIKit class BoldFormatter: FontFormatter { - static let htmlRepresentationKey = "Bold.htmlRepresentation" + static let htmlRepresentationKey = NSAttributedStringKey("Bold.htmlRepresentation") init() { super.init(traits: .traitBold, htmlRepresentationKey: BoldFormatter.htmlRepresentationKey) diff --git a/Aztec/Classes/Formatters/Implementations/ColorFormatter.swift b/Aztec/Classes/Formatters/Implementations/ColorFormatter.swift index 5ee0c0d0d..2a81be9c5 100644 --- a/Aztec/Classes/Formatters/Implementations/ColorFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/ColorFormatter.swift @@ -1,10 +1,10 @@ import UIKit class ColorFormatter: StandardAttributeFormatter { - static let htmlRepresentationKey = "Color.htmlRepresentation" + static let htmlRepresentationKey = NSAttributedStringKey("Color.htmlRepresentation") init(color: UIColor = .black) { - super.init(attributeKey: NSForegroundColorAttributeName, + super.init(attributeKey: .foregroundColor, attributeValue: color, htmlRepresentationKey: ColorFormatter.htmlRepresentationKey) } diff --git a/Aztec/Classes/Formatters/Implementations/HRFormatter.swift b/Aztec/Classes/Formatters/Implementations/HRFormatter.swift index 5f032ccc6..5b147474b 100644 --- a/Aztec/Classes/Formatters/Implementations/HRFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/HRFormatter.swift @@ -1,10 +1,10 @@ import UIKit class HRFormatter: StandardAttributeFormatter { - static let htmlRepresentationKey = "HR.htmlRepresentation" + static let htmlRepresentationKey = NSAttributedStringKey("HR.htmlRepresentation") init() { - super.init(attributeKey: NSAttachmentAttributeName, + super.init(attributeKey: .attachment, attributeValue: LineAttachment(), htmlRepresentationKey: HRFormatter.htmlRepresentationKey) } diff --git a/Aztec/Classes/Formatters/Implementations/HTMLDivFormatter.swift b/Aztec/Classes/Formatters/Implementations/HTMLDivFormatter.swift index a4b5125fe..d65738035 100644 --- a/Aztec/Classes/Formatters/Implementations/HTMLDivFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/HTMLDivFormatter.swift @@ -8,22 +8,22 @@ class HTMLDivFormatter: ParagraphAttributeFormatter { /// Attributes to be added by default /// - let placeholderAttributes: [String: Any]? + let placeholderAttributes: [NSAttributedStringKey: Any]? /// Designated Initializer /// - init(placeholderAttributes: [String: Any]? = nil) { + init(placeholderAttributes: [NSAttributedStringKey: Any]? = nil) { self.placeholderAttributes = placeholderAttributes } // MARK: - Overwriten Methods - func apply(to attributes: [String: Any], andStore representation: HTMLRepresentation?) -> [String: Any] { + func apply(to attributes: [NSAttributedStringKey: Any], andStore representation: HTMLRepresentation?) -> [NSAttributedStringKey: Any] { let newParagraphStyle = ParagraphStyle() - if let paragraphStyle = attributes[NSParagraphStyleAttributeName] as? NSParagraphStyle { + if let paragraphStyle = attributes[.paragraphStyle] as? NSParagraphStyle { newParagraphStyle.setParagraphStyle(paragraphStyle) } @@ -31,12 +31,12 @@ class HTMLDivFormatter: ParagraphAttributeFormatter { newParagraphStyle.appendProperty(newProperty) var resultingAttributes = attributes - resultingAttributes[NSParagraphStyleAttributeName] = newParagraphStyle + resultingAttributes[.paragraphStyle] = newParagraphStyle return resultingAttributes } - func remove(from attributes:[String: Any]) -> [String: Any] { - guard let paragraphStyle = attributes[NSParagraphStyleAttributeName] as? ParagraphStyle, + func remove(from attributes: [NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] { + guard let paragraphStyle = attributes[.paragraphStyle] as? ParagraphStyle, !paragraphStyle.htmlDiv.isEmpty else { return attributes @@ -47,12 +47,12 @@ class HTMLDivFormatter: ParagraphAttributeFormatter { newParagraphStyle.removeProperty(ofType: HTMLDiv.self) var resultingAttributes = attributes - resultingAttributes[NSParagraphStyleAttributeName] = newParagraphStyle + resultingAttributes[.paragraphStyle] = newParagraphStyle return resultingAttributes } - func present(in attributes: [String: Any]) -> Bool { - let style = attributes[NSParagraphStyleAttributeName] as? ParagraphStyle + func present(in attributes: [NSAttributedStringKey: Any]) -> Bool { + let style = attributes[.paragraphStyle] as? ParagraphStyle return style?.htmlDiv.isEmpty == false } } diff --git a/Aztec/Classes/Formatters/Implementations/HTMLParagraphFormatter.swift b/Aztec/Classes/Formatters/Implementations/HTMLParagraphFormatter.swift index 53caa35c4..545a6b688 100644 --- a/Aztec/Classes/Formatters/Implementations/HTMLParagraphFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/HTMLParagraphFormatter.swift @@ -8,34 +8,34 @@ class HTMLParagraphFormatter: ParagraphAttributeFormatter { /// Attributes to be added by default /// - let placeholderAttributes: [String : Any]? + let placeholderAttributes: [NSAttributedStringKey: Any]? /// Designated Initializer /// - init(placeholderAttributes: [String : Any]? = nil) { + init(placeholderAttributes: [NSAttributedStringKey: Any]? = nil) { self.placeholderAttributes = placeholderAttributes } // MARK: - Overwriten Methods - func apply(to attributes: [String : Any], andStore representation: HTMLRepresentation?) -> [String: Any] { + func apply(to attributes: [NSAttributedStringKey: Any], andStore representation: HTMLRepresentation?) -> [NSAttributedStringKey: Any] { let newParagraphStyle = ParagraphStyle() - if let paragraphStyle = attributes[NSParagraphStyleAttributeName] as? NSParagraphStyle { + if let paragraphStyle = attributes[.paragraphStyle] as? NSParagraphStyle { newParagraphStyle.setParagraphStyle(paragraphStyle) } newParagraphStyle.appendProperty(HTMLParagraph(with: representation)) var resultingAttributes = attributes - resultingAttributes[NSParagraphStyleAttributeName] = newParagraphStyle + resultingAttributes[.paragraphStyle] = newParagraphStyle return resultingAttributes } - func remove(from attributes:[String: Any]) -> [String: Any] { - guard let paragraphStyle = attributes[NSParagraphStyleAttributeName] as? ParagraphStyle, + func remove(from attributes:[NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] { + guard let paragraphStyle = attributes[.paragraphStyle] as? ParagraphStyle, !paragraphStyle.htmlParagraph.isEmpty else { return attributes @@ -46,12 +46,12 @@ class HTMLParagraphFormatter: ParagraphAttributeFormatter { newParagraphStyle.removeProperty(ofType: HTMLParagraph.self) var resultingAttributes = attributes - resultingAttributes[NSParagraphStyleAttributeName] = newParagraphStyle + resultingAttributes[.paragraphStyle] = newParagraphStyle return resultingAttributes } - func present(in attributes: [String : Any]) -> Bool { - guard let style = attributes[NSParagraphStyleAttributeName] as? ParagraphStyle else { + func present(in attributes: [NSAttributedStringKey: Any]) -> Bool { + guard let style = attributes[.paragraphStyle] as? ParagraphStyle else { return false } return !style.htmlParagraph.isEmpty diff --git a/Aztec/Classes/Formatters/Implementations/HeaderFormatter.swift b/Aztec/Classes/Formatters/Implementations/HeaderFormatter.swift index f2f4a62fe..d2f698f26 100644 --- a/Aztec/Classes/Formatters/Implementations/HeaderFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/HeaderFormatter.swift @@ -12,12 +12,12 @@ open class HeaderFormatter: ParagraphAttributeFormatter { /// Attributes to be added by default /// - let placeholderAttributes: [String : Any]? + let placeholderAttributes: [NSAttributedStringKey: Any]? /// Designated Initializer /// - init(headerLevel: Header.HeaderType = .h1, placeholderAttributes: [String: Any]? = nil) { + init(headerLevel: Header.HeaderType = .h1, placeholderAttributes: [NSAttributedStringKey: Any]? = nil) { self.headerLevel = headerLevel self.placeholderAttributes = placeholderAttributes } @@ -25,13 +25,13 @@ open class HeaderFormatter: ParagraphAttributeFormatter { // MARK: - Overwriten Methods - func apply(to attributes: [String: Any], andStore representation: HTMLRepresentation?) -> [String: Any] { - guard let font = attributes[NSFontAttributeName] as? UIFont else { + func apply(to attributes: [NSAttributedStringKey: Any], andStore representation: HTMLRepresentation?) -> [NSAttributedStringKey: Any] { + guard let font = attributes[.font] as? UIFont else { return attributes } let newParagraphStyle = ParagraphStyle() - if let paragraphStyle = attributes[NSParagraphStyleAttributeName] as? NSParagraphStyle { + if let paragraphStyle = attributes[.paragraphStyle] as? NSParagraphStyle { newParagraphStyle.setParagraphStyle(paragraphStyle) } @@ -45,14 +45,14 @@ open class HeaderFormatter: ParagraphAttributeFormatter { let targetFontSize = headerFontSize(for: headerLevel, defaultSize: defaultSize) var resultingAttributes = attributes - resultingAttributes[NSParagraphStyleAttributeName] = newParagraphStyle - resultingAttributes[NSFontAttributeName] = font.withSize(CGFloat(targetFontSize)) + resultingAttributes[.paragraphStyle] = newParagraphStyle + resultingAttributes[.font] = font.withSize(CGFloat(targetFontSize)) return resultingAttributes } - func remove(from attributes: [String: Any]) -> [String: Any] { - guard let paragraphStyle = attributes[NSParagraphStyleAttributeName] as? ParagraphStyle, + func remove(from attributes: [NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] { + guard let paragraphStyle = attributes[.paragraphStyle] as? ParagraphStyle, let header = paragraphStyle.headers.last, header.level != .none else { @@ -64,17 +64,17 @@ open class HeaderFormatter: ParagraphAttributeFormatter { newParagraphStyle.removeProperty(ofType: Header.self) var resultingAttributes = attributes - resultingAttributes[NSParagraphStyleAttributeName] = newParagraphStyle + resultingAttributes[.paragraphStyle] = newParagraphStyle - if let font = attributes[NSFontAttributeName] as? UIFont { - resultingAttributes[NSFontAttributeName] = font.withSize(CGFloat(header.defaultFontSize)) + if let font = attributes[.font] as? UIFont { + resultingAttributes[.font] = font.withSize(CGFloat(header.defaultFontSize)) } return resultingAttributes } - func present(in attributes: [String: Any]) -> Bool { - guard let paragraphStyle = attributes[NSParagraphStyleAttributeName] as? ParagraphStyle else { + func present(in attributes: [NSAttributedStringKey: Any]) -> Bool { + guard let paragraphStyle = attributes[.paragraphStyle] as? ParagraphStyle else { return false } @@ -87,14 +87,14 @@ open class HeaderFormatter: ParagraphAttributeFormatter { // private extension HeaderFormatter { - func defaultFontSize(from attributes: [String: Any]) -> Float? { - if let paragraphStyle = attributes[NSParagraphStyleAttributeName] as? ParagraphStyle, + func defaultFontSize(from attributes: [NSAttributedStringKey: Any]) -> Float? { + if let paragraphStyle = attributes[.paragraphStyle] as? ParagraphStyle, let lastHeader = paragraphStyle.headers.last { return lastHeader.defaultFontSize } - if let font = attributes[NSFontAttributeName] as? UIFont { + if let font = attributes[.font] as? UIFont { return Float(font.pointSize) } diff --git a/Aztec/Classes/Formatters/Implementations/ImageFormatter.swift b/Aztec/Classes/Formatters/Implementations/ImageFormatter.swift index c79dab894..a0ce535d0 100644 --- a/Aztec/Classes/Formatters/Implementations/ImageFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/ImageFormatter.swift @@ -1,16 +1,16 @@ import UIKit class ImageFormatter: StandardAttributeFormatter { - static let htmlRepresentationKey = "Image.htmlRepresentation" + static let htmlRepresentationKey = NSAttributedStringKey("Image.htmlRepresentation") init() { super.init( - attributeKey: NSAttachmentAttributeName, + attributeKey: .attachment, attributeValue: ImageAttachment(identifier: NSUUID().uuidString), htmlRepresentationKey: ImageFormatter.htmlRepresentationKey) } - override func apply(to attributes: [String : Any], andStore representation: HTMLRepresentation?) -> [String: Any] { + override func apply(to attributes: [NSAttributedStringKey: Any], andStore representation: HTMLRepresentation?) -> [NSAttributedStringKey: Any] { if let representation = representation { switch representation.kind { diff --git a/Aztec/Classes/Formatters/Implementations/ItalicFormatter.swift b/Aztec/Classes/Formatters/Implementations/ItalicFormatter.swift index 735d2e39d..464321f06 100644 --- a/Aztec/Classes/Formatters/Implementations/ItalicFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/ItalicFormatter.swift @@ -1,7 +1,7 @@ import UIKit class ItalicFormatter: FontFormatter { - static let htmlRepresentationKey = "Italic.htmlRepresentation" + static let htmlRepresentationKey = NSAttributedStringKey("Italic.htmlRepresentation") init() { super.init(traits: .traitItalic, htmlRepresentationKey: ItalicFormatter.htmlRepresentationKey) diff --git a/Aztec/Classes/Formatters/Implementations/LinkFormatter.swift b/Aztec/Classes/Formatters/Implementations/LinkFormatter.swift index 0774c1992..82d5780b7 100644 --- a/Aztec/Classes/Formatters/Implementations/LinkFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/LinkFormatter.swift @@ -1,15 +1,15 @@ import UIKit class LinkFormatter: StandardAttributeFormatter { - static let htmlRepresentationKey = "Link.htmlRepresentation" + static let htmlRepresentationKey = NSAttributedStringKey("Link.htmlRepresentation") init() { - super.init(attributeKey: NSLinkAttributeName, + super.init(attributeKey: .link, attributeValue: NSURL(string:"")!, htmlRepresentationKey: LinkFormatter.htmlRepresentationKey) } - override func apply(to attributes: [String : Any], andStore representation: HTMLRepresentation?) -> [String: Any] { + override func apply(to attributes: [NSAttributedStringKey: Any], andStore representation: HTMLRepresentation?) -> [NSAttributedStringKey: Any] { if let representation = representation, case let .element(element) = representation.kind { diff --git a/Aztec/Classes/Formatters/Implementations/PreFormatter.swift b/Aztec/Classes/Formatters/Implementations/PreFormatter.swift index ad718ba72..532653cc8 100644 --- a/Aztec/Classes/Formatters/Implementations/PreFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/PreFormatter.swift @@ -12,12 +12,12 @@ open class PreFormatter: ParagraphAttributeFormatter { /// Attributes to be added by default /// - let placeholderAttributes: [String : Any]? + let placeholderAttributes: [NSAttributedStringKey: Any]? /// Designated Initializer /// - init(monospaceFont: UIFont = UIFont(descriptor:UIFontDescriptor(name: "Courier", size: 12), size:12), placeholderAttributes: [String : Any]? = nil) { + init(monospaceFont: UIFont = UIFont(descriptor:UIFontDescriptor(name: "Courier", size: 12), size:12), placeholderAttributes: [NSAttributedStringKey : Any]? = nil) { self.monospaceFont = monospaceFont self.placeholderAttributes = placeholderAttributes } @@ -25,19 +25,19 @@ open class PreFormatter: ParagraphAttributeFormatter { // MARK: - Overwriten Methods - func apply(to attributes: [String : Any], andStore representation: HTMLRepresentation?) -> [String: Any] { + func apply(to attributes: [NSAttributedStringKey: Any], andStore representation: HTMLRepresentation?) -> [NSAttributedStringKey: Any] { var resultingAttributes = attributes let newParagraphStyle = ParagraphStyle() newParagraphStyle.appendProperty(HTMLPre(with: representation)) - resultingAttributes[NSParagraphStyleAttributeName] = newParagraphStyle - resultingAttributes[NSFontAttributeName] = monospaceFont + resultingAttributes[.paragraphStyle] = newParagraphStyle + resultingAttributes[.font] = monospaceFont return resultingAttributes } - func remove(from attributes: [String: Any]) -> [String: Any] { + func remove(from attributes: [NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] { guard let placeholderAttributes = placeholderAttributes else { return attributes } @@ -50,8 +50,8 @@ open class PreFormatter: ParagraphAttributeFormatter { return resultingAttributes } - func present(in attributes: [String : Any]) -> Bool { - let font = attributes[NSFontAttributeName] as? UIFont + func present(in attributes: [NSAttributedStringKey : Any]) -> Bool { + let font = attributes[.font] as? UIFont return font == monospaceFont } } diff --git a/Aztec/Classes/Formatters/Implementations/StrikethroughFormatter.swift b/Aztec/Classes/Formatters/Implementations/StrikethroughFormatter.swift index 9ea58fdaa..402cf0780 100644 --- a/Aztec/Classes/Formatters/Implementations/StrikethroughFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/StrikethroughFormatter.swift @@ -1,10 +1,10 @@ import UIKit class StrikethroughFormatter: StandardAttributeFormatter { - static let htmlRepresentationKey = "Strike.htmlRepresentation" + static let htmlRepresentationKey = NSAttributedStringKey("Strike.htmlRepresentation") init() { - super.init(attributeKey: NSStrikethroughStyleAttributeName, + super.init(attributeKey: .strikethroughStyle, attributeValue: NSUnderlineStyle.styleSingle.rawValue, htmlRepresentationKey: StrikethroughFormatter.htmlRepresentationKey) } diff --git a/Aztec/Classes/Formatters/Implementations/TextListFormatter.swift b/Aztec/Classes/Formatters/Implementations/TextListFormatter.swift index 90f954280..bfd7ae0e0 100644 --- a/Aztec/Classes/Formatters/Implementations/TextListFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/TextListFormatter.swift @@ -12,14 +12,14 @@ class TextListFormatter: ParagraphAttributeFormatter { /// Attributes to be added by default /// - let placeholderAttributes: [String: Any]? + let placeholderAttributes: [NSAttributedStringKey: 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, increaseDepth: Bool = false) { + init(style: TextList.Style, placeholderAttributes: [NSAttributedStringKey: Any]? = nil, increaseDepth: Bool = false) { self.listStyle = style self.placeholderAttributes = placeholderAttributes self.increaseDepth = increaseDepth @@ -28,9 +28,9 @@ class TextListFormatter: ParagraphAttributeFormatter { // MARK: - Overwriten Methods - func apply(to attributes: [String : Any], andStore representation: HTMLRepresentation?) -> [String: Any] { + func apply(to attributes: [NSAttributedStringKey: Any], andStore representation: HTMLRepresentation?) -> [NSAttributedStringKey: Any] { let newParagraphStyle = ParagraphStyle() - if let paragraphStyle = attributes[NSParagraphStyleAttributeName] as? NSParagraphStyle { + if let paragraphStyle = attributes[.paragraphStyle] as? NSParagraphStyle { newParagraphStyle.setParagraphStyle(paragraphStyle) } @@ -42,13 +42,13 @@ class TextListFormatter: ParagraphAttributeFormatter { } var resultingAttributes = attributes - resultingAttributes[NSParagraphStyleAttributeName] = newParagraphStyle + resultingAttributes[.paragraphStyle] = newParagraphStyle return resultingAttributes } - func remove(from attributes: [String: Any]) -> [String: Any] { - guard let paragraphStyle = attributes[NSParagraphStyleAttributeName] as? ParagraphStyle, + func remove(from attributes: [NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] { + guard let paragraphStyle = attributes[.paragraphStyle] as? ParagraphStyle, let currentList = paragraphStyle.lists.last, currentList.style == self.listStyle else { @@ -60,24 +60,24 @@ class TextListFormatter: ParagraphAttributeFormatter { newParagraphStyle.removeProperty(ofType: TextList.self) var resultingAttributes = attributes - resultingAttributes[NSParagraphStyleAttributeName] = newParagraphStyle + resultingAttributes[.paragraphStyle] = newParagraphStyle return resultingAttributes } - func present(in attributes: [String: Any]) -> Bool { + func present(in attributes: [NSAttributedStringKey: Any]) -> Bool { return TextListFormatter.lists(in: attributes).last?.style == listStyle } // MARK: - Static Helpers - static func listsOfAnyKindPresent(in attributes: [String: Any]) -> Bool { + static func listsOfAnyKindPresent(in attributes: [NSAttributedStringKey: Any]) -> Bool { return lists(in: attributes).isEmpty == false } - static func lists(in attributes: [String: Any]) -> [TextList] { - let style = attributes[NSParagraphStyleAttributeName] as? ParagraphStyle + static func lists(in attributes: [NSAttributedStringKey: Any]) -> [TextList] { + let style = attributes[.paragraphStyle] as? ParagraphStyle return style?.lists ?? [] } } diff --git a/Aztec/Classes/Formatters/Implementations/UnderlineFormatter.swift b/Aztec/Classes/Formatters/Implementations/UnderlineFormatter.swift index 33efc6838..99078fd2d 100644 --- a/Aztec/Classes/Formatters/Implementations/UnderlineFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/UnderlineFormatter.swift @@ -1,10 +1,10 @@ import UIKit class UnderlineFormatter: StandardAttributeFormatter { - static let htmlRepresentationKey = "Underline.htmlRepresentation" + static let htmlRepresentationKey = NSAttributedStringKey("Underline.htmlRepresentation") init() { - super.init(attributeKey: NSUnderlineStyleAttributeName, + super.init(attributeKey: .underlineStyle, attributeValue: NSUnderlineStyle.styleSingle.rawValue, htmlRepresentationKey: UnderlineFormatter.htmlRepresentationKey) } diff --git a/Aztec/Classes/Formatters/Implementations/VideoFormatter.swift b/Aztec/Classes/Formatters/Implementations/VideoFormatter.swift index 7959d58b8..e9428c63f 100644 --- a/Aztec/Classes/Formatters/Implementations/VideoFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/VideoFormatter.swift @@ -1,15 +1,15 @@ import UIKit class VideoFormatter: StandardAttributeFormatter { - static let htmlRepresentationKey = "Video.htmlRepresentation" + static let htmlRepresentationKey = NSAttributedStringKey("Video.htmlRepresentation") init() { - super.init(attributeKey: NSAttachmentAttributeName, + super.init(attributeKey: .attachment, attributeValue: VideoAttachment(identifier: NSUUID().uuidString), htmlRepresentationKey: VideoFormatter.htmlRepresentationKey) } - override func apply(to attributes: [String : Any], andStore representation: HTMLRepresentation?) -> [String: Any] { + override func apply(to attributes: [NSAttributedStringKey: Any], andStore representation: HTMLRepresentation?) -> [NSAttributedStringKey: Any] { if let representation = representation, case let .element(element) = representation.kind { diff --git a/Aztec/Classes/GUI/FormatBar/FormatBar.swift b/Aztec/Classes/GUI/FormatBar/FormatBar.swift index cb1df87af..2626c6a5c 100644 --- a/Aztec/Classes/GUI/FormatBar/FormatBar.swift +++ b/Aztec/Classes/GUI/FormatBar/FormatBar.swift @@ -655,10 +655,10 @@ private extension FormatBar { } let overflowTrailingConstraint = overflowToggleItem.trailingAnchor.constraint(equalTo: trailingAnchor) - overflowTrailingConstraint.priority = UILayoutPriorityDefaultLow + overflowTrailingConstraint.priority = .defaultLow let trailingItemTrailingConstraint = trailingItemContainer.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -Constants.trailingButtonMargin) - trailingItemTrailingConstraint.priority = UILayoutPriorityDefaultLow + trailingItemTrailingConstraint.priority = .defaultLow NSLayoutConstraint.activate([ overflowToggleItem.topAnchor.constraint(equalTo: topAnchor), diff --git a/Aztec/Classes/NSAttributedString/Attributes/HTMLRepresentation.swift b/Aztec/Classes/NSAttributedString/Attributes/HTMLRepresentation.swift index 62085a6a9..745f9f90d 100644 --- a/Aztec/Classes/NSAttributedString/Attributes/HTMLRepresentation.swift +++ b/Aztec/Classes/NSAttributedString/Attributes/HTMLRepresentation.swift @@ -59,8 +59,8 @@ class HTMLRepresentation: NSObject, NSCoding { // MARK: - HTMLElementRepresentation // class HTMLElementRepresentation: NSObject, CustomReflectable, NSCoding { - let name: String - let attributes: [Attribute] + @objc let name: String + @objc let attributes: [Attribute] init(name: String, attributes: [Attribute]) { self.name = name diff --git a/Aztec/Classes/NSAttributedString/Attributes/UnsupportedHTML.swift b/Aztec/Classes/NSAttributedString/Attributes/UnsupportedHTML.swift index 8cf59fd76..a22d6e0ee 100644 --- a/Aztec/Classes/NSAttributedString/Attributes/UnsupportedHTML.swift +++ b/Aztec/Classes/NSAttributedString/Attributes/UnsupportedHTML.swift @@ -3,7 +3,7 @@ import Foundation // MARK: - UnsupportedHTML NSAttributedString Attribute Name // -let UnsupportedHTMLAttributeName = "UnsupportedHTMLAttributeName" +let UnsupportedHTMLAttributeName = NSAttributedStringKey("UnsupportedHTMLAttributeName") // MARK: - UnsupportedHTML diff --git a/Aztec/Classes/NSAttributedString/Conversions/AttributedStringParser.swift b/Aztec/Classes/NSAttributedString/Conversions/AttributedStringParser.swift index 5d78cbf64..0139022d9 100644 --- a/Aztec/Classes/NSAttributedString/Conversions/AttributedStringParser.swift +++ b/Aztec/Classes/NSAttributedString/Conversions/AttributedStringParser.swift @@ -98,7 +98,7 @@ class AttributedStringParser { /// /// - Returns: Array of Node instances. /// - private func createNodes(from attributes: [String: Any]) -> [Node] { + private func createNodes(from attributes: [NSAttributedStringKey: Any]) -> [Node] { let nodes = createParagraphNodes(from: attributes) + createStyleNodes(from: attributes) return nodes.reversed().reduce([]) { (result, node) in @@ -439,7 +439,7 @@ private extension AttributedStringParser { // See here for more info: // https://github.com/wordpress-mobile/AztecEditor-iOS/issues/667 // - guard let paragraphStyle = paragraph.attribute(NSParagraphStyleAttributeName, at: 0, effectiveRange: nil) as? ParagraphStyle, + guard let paragraphStyle = paragraph.attribute(.paragraphStyle, at: 0, effectiveRange: nil) as? ParagraphStyle, paragraphStyle.properties.count > 0 else { return [ElementNode(type: .p)] @@ -456,8 +456,8 @@ private extension AttributedStringParser { /// /// - Returns: ElementNode representing the specified Paragraph. /// - func createParagraphNodes(from attributes: [String: Any]) -> [ElementNode] { - guard let paragraphStyle = attributes[NSParagraphStyleAttributeName] as? ParagraphStyle, + func createParagraphNodes(from attributes: [NSAttributedStringKey: Any]) -> [ElementNode] { + guard let paragraphStyle = attributes[.paragraphStyle] as? ParagraphStyle, paragraphStyle.properties.count > 0 else { return [ElementNode(type: .p)] } @@ -627,7 +627,7 @@ private extension AttributedStringParser { /// /// - Returns: Style Nodes contained within the specified collection of attributes /// - func createStyleNodes(from attributes: [String: Any]) -> [ElementNode] { + func createStyleNodes(from attributes: [NSAttributedStringKey: Any]) -> [ElementNode] { var nodes = [ElementNode]() if let element = processBold(in: attributes) { @@ -655,8 +655,8 @@ private extension AttributedStringParser { return nodes } - private func processBold(in attributes: [String: Any]) -> ElementNode? { - guard let font = attributes[NSFontAttributeName] as? UIFont, + private func processBold(in attributes: [NSAttributedStringKey: Any]) -> ElementNode? { + guard let font = attributes[.font] as? UIFont, font.containsTraits(.traitBold) else { return nil } @@ -675,8 +675,8 @@ private extension AttributedStringParser { } - private func processItalic(in attributes: [String: Any]) -> ElementNode? { - guard let font = attributes[NSFontAttributeName] as? UIFont, + private func processItalic(in attributes: [NSAttributedStringKey: Any]) -> ElementNode? { + guard let font = attributes[.font] as? UIFont, font.containsTraits(.traitItalic) else { return nil } @@ -696,11 +696,11 @@ private extension AttributedStringParser { /// Extracts all of the Link Elements contained within a collection of Attributes. /// - private func processLinkStyle(in attributes: [String: Any]) -> ElementNode? { + private func processLinkStyle(in attributes: [NSAttributedStringKey: Any]) -> ElementNode? { var urlString = "" - if let url = attributes[NSLinkAttributeName] as? URL { + if let url = attributes[.link] as? URL { urlString = url.absoluteString - } else if let link = attributes[NSLinkAttributeName] as? String { + } else if let link = attributes[.link] as? String { urlString = link } else { return nil @@ -724,8 +724,8 @@ private extension AttributedStringParser { /// Extracts all of the Strike Elements contained within a collection of Attributes. /// - private func processStrikethruStyle(in attributes: [String: Any]) -> ElementNode? { - guard attributes[NSStrikethroughStyleAttributeName] != nil else { + private func processStrikethruStyle(in attributes: [NSAttributedStringKey: Any]) -> ElementNode? { + guard attributes[.strikethroughStyle] != nil else { return nil } @@ -741,8 +741,8 @@ private extension AttributedStringParser { /// Extracts all of the Underline Elements contained within a collection of Attributes. /// - private func processUnderlineStyle(in attributes: [String: Any]) -> ElementNode? { - guard attributes[NSUnderlineStyleAttributeName] != nil else { + private func processUnderlineStyle(in attributes: [NSAttributedStringKey: Any]) -> ElementNode? { + guard attributes[.underlineStyle] != nil else { return nil } @@ -758,7 +758,7 @@ private extension AttributedStringParser { /// Extracts all of the Unsupported HTML Snippets contained within a collection of Attributes. /// - private func processUnsupportedHTML(in attributes: [String: Any]) -> [ElementNode] { + private func processUnsupportedHTML(in attributes: [NSAttributedStringKey: Any]) -> [ElementNode] { guard let unsupportedHTML = attributes[UnsupportedHTMLAttributeName] as? UnsupportedHTML else { return [] } @@ -808,7 +808,7 @@ private extension AttributedStringParser { /// Converts a Line Attachment into it's representing nodes. /// private func processLineAttachment(from attrString: NSAttributedString) -> ElementNode? { - guard attrString.attribute(NSAttachmentAttributeName, at: 0, effectiveRange: nil) is LineAttachment else { + guard attrString.attribute(.attachment, at: 0, effectiveRange: nil) is LineAttachment else { return nil } @@ -830,7 +830,7 @@ private extension AttributedStringParser { /// Converts a Comment Attachment into it's representing nodes. /// private func processCommentAttachment(from attrString: NSAttributedString) -> Node? { - guard let attachment = attrString.attribute(NSAttachmentAttributeName, at: 0, effectiveRange: nil) as? CommentAttachment else { + guard let attachment = attrString.attribute(.attachment, at: 0, effectiveRange: nil) as? CommentAttachment else { return nil } @@ -842,7 +842,7 @@ private extension AttributedStringParser { /// Converts an HTML Attachment into it's representing nodes. /// private func processHtmlAttachment(from attrString: NSAttributedString) -> [Node] { - guard let attachment = attrString.attribute(NSAttachmentAttributeName, at: 0, effectiveRange: nil) as? HTMLAttachment else { + guard let attachment = attrString.attribute(.attachment, at: 0, effectiveRange: nil) as? HTMLAttachment else { return [] } @@ -866,7 +866,7 @@ private extension AttributedStringParser { /// Converts an Image Attachment into it's representing nodes. /// private func processImageAttachment(from attrString: NSAttributedString) -> ElementNode? { - guard let attachment = attrString.attribute(NSAttachmentAttributeName, at: 0, effectiveRange: nil) as? ImageAttachment else { + guard let attachment = attrString.attribute(.attachment, at: 0, effectiveRange: nil) as? ImageAttachment else { return nil } @@ -913,7 +913,7 @@ private extension AttributedStringParser { /// Converts an Video Attachment into it's representing nodes. /// private func processVideoAttachment(from attrString: NSAttributedString) -> ElementNode? { - guard let attachment = attrString.attribute(NSAttachmentAttributeName, at: 0, effectiveRange: nil) as? VideoAttachment else { + guard let attachment = attrString.attribute(.attachment, at: 0, effectiveRange: nil) as? VideoAttachment else { return nil } diff --git a/Aztec/Classes/NSAttributedString/Conversions/AttributedStringSerializer.swift b/Aztec/Classes/NSAttributedString/Conversions/AttributedStringSerializer.swift index 1968a3741..23082e2a2 100644 --- a/Aztec/Classes/NSAttributedString/Conversions/AttributedStringSerializer.swift +++ b/Aztec/Classes/NSAttributedString/Conversions/AttributedStringSerializer.swift @@ -5,11 +5,11 @@ import UIKit /// class AttributedStringSerializer { - private let defaultAttributes: [String: Any] + private let defaultAttributes: [NSAttributedStringKey: Any] // MARK: - Initializers - required init(defaultAttributes: [String: Any]) { + required init(defaultAttributes: [NSAttributedStringKey: Any]) { self.defaultAttributes = defaultAttributes } @@ -35,7 +35,7 @@ class AttributedStringSerializer { /// /// - Returns: the converted node as an `NSAttributedString`. /// - fileprivate func serialize(_ node: Node, inheriting attributes: [String:Any]) -> NSAttributedString { + fileprivate func serialize(_ node: Node, inheriting attributes: [NSAttributedStringKey:Any]) -> NSAttributedString { switch node { case let textNode as TextNode: return serialize(textNode, inheriting: attributes) @@ -56,7 +56,7 @@ class AttributedStringSerializer { /// /// - Returns: the converted node as an `NSAttributedString`. /// - fileprivate func serialize(_ node: TextNode, inheriting attributes: [String:Any]) -> NSAttributedString { + fileprivate func serialize(_ node: TextNode, inheriting attributes: [NSAttributedStringKey: Any]) -> NSAttributedString { let text = sanitizeText(from: node) @@ -81,7 +81,7 @@ class AttributedStringSerializer { /// /// - Returns: the converted node as an `NSAttributedString`. /// - fileprivate func serialize(_ node: CommentNode, inheriting attributes: [String:Any]) -> NSAttributedString { + fileprivate func serialize(_ node: CommentNode, inheriting attributes: [NSAttributedStringKey: Any]) -> NSAttributedString { let attachment = CommentAttachment() attachment.text = node.comment @@ -96,7 +96,7 @@ class AttributedStringSerializer { /// /// - Returns: the converted node as an `NSAttributedString`. /// - fileprivate func serialize(_ element: ElementNode, inheriting attributes: [String: Any]) -> NSAttributedString { + fileprivate func serialize(_ element: ElementNode, inheriting attributes: [NSAttributedStringKey: Any]) -> NSAttributedString { guard element.isSupportedByEditor() else { return serialize(unsupported: element, inheriting: attributes) @@ -127,7 +127,7 @@ class AttributedStringSerializer { /// /// - Returns: the converted node as an `NSAttributedString`. /// - fileprivate func serialize(unsupported element: ElementNode, inheriting attributes: [String: Any]) -> NSAttributedString { + fileprivate func serialize(unsupported element: ElementNode, inheriting attributes: [NSAttributedStringKey: Any]) -> NSAttributedString { let serializer = DefaultHTMLSerializer() let attachment = HTMLAttachment() @@ -139,7 +139,7 @@ class AttributedStringSerializer { // MARK: - Paragraph Separator - private func appendParagraphSeparator(to string: NSAttributedString, inheriting inheritedAttributes: [String: Any]) -> NSAttributedString { + private func appendParagraphSeparator(to string: NSAttributedString, inheriting inheritedAttributes: [NSAttributedStringKey: Any]) -> NSAttributedString { let stringWithSeparator = NSMutableAttributedString(attributedString: string) @@ -238,7 +238,7 @@ private extension AttributedStringSerializer { /// /// - Returns: an attributes dictionary, for use in an NSAttributedString. /// - func attributes(for element: ElementNode, inheriting inheritedAttributes: [String: Any]) -> [String: Any] { + func attributes(for element: ElementNode, inheriting inheritedAttributes: [NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] { guard !(element is RootNode) else { return inheritedAttributes @@ -271,9 +271,9 @@ private extension AttributedStringSerializer { /// /// - Returns: an attributes dictionary, for use in an NSAttributedString. /// - private func attributes(for htmlAttributes: [Attribute], inheriting inheritedAttributes: [String: Any]) -> [String: Any] { + private func attributes(for htmlAttributes: [Attribute], inheriting inheritedAttributes: [NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] { - let finalAttributes = htmlAttributes.reduce(inheritedAttributes) { (previousAttributes, htmlAttribute) -> [String: Any] in + let finalAttributes = htmlAttributes.reduce(inheritedAttributes) { (previousAttributes, htmlAttribute) -> [NSAttributedStringKey: Any] in return attributes(for: htmlAttribute, inheriting: previousAttributes) } @@ -290,9 +290,9 @@ private extension AttributedStringSerializer { /// /// - Returns: an attributes dictionary, for use in an NSAttributedString. /// - private func attributes(for attribute: Attribute, inheriting inheritedAttributes: [String: Any]) -> [String: Any] { + private func attributes(for attribute: Attribute, inheriting inheritedAttributes: [NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] { - let attributes: [String:Any] + let attributes: [NSAttributedStringKey: Any] if let attributeFormatter = formatter(for: attribute) { let attributeHTMLRepresentation = HTMLRepresentation(for: .attribute(attribute)) @@ -314,7 +314,7 @@ private extension AttributedStringSerializer { /// /// - Returns: A collection of NSAttributedString Attributes, including the specified HTMLElementRepresentation. /// - private func attributes(storing representation: HTMLElementRepresentation, in attributes: [String: Any]) -> [String: Any] { + private func attributes(storing representation: HTMLElementRepresentation, in attributes: [NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] { let unsupportedHTML = attributes[UnsupportedHTMLAttributeName] as? UnsupportedHTML var representations = unsupportedHTML?.representations ?? [] representations.append(representation) @@ -371,7 +371,7 @@ private extension AttributedStringSerializer { /// /// - Returns: the requested implicit representation, if one exists, or `nil`. /// - func implicitRepresentation(for element: ElementNode, inheriting attributes: [String:Any]) -> NSAttributedString? { + func implicitRepresentation(for element: ElementNode, inheriting attributes: [NSAttributedStringKey: Any]) -> NSAttributedString? { guard let elementType = element.standardName else { return nil @@ -379,11 +379,11 @@ private extension AttributedStringSerializer { if let imgElement = linkedImageElement(for: element) { var attributesWithoutLink = attributes - attributesWithoutLink[NSLinkAttributeName] = nil + attributesWithoutLink[.link] = nil attributesWithoutLink[LinkFormatter.htmlRepresentationKey] = nil let imgAttributes = self.attributes(for: imgElement, inheriting: attributesWithoutLink) - let attachment = imgAttributes[NSAttachmentAttributeName] as! ImageAttachment + let attachment = imgAttributes[.attachment] as! ImageAttachment let linkText = element.stringValueForAttribute(named: HTMLLinkAttribute.Href.rawValue) ?? "" attachment.linkURL = URL(string: linkText) @@ -402,7 +402,7 @@ private extension AttributedStringSerializer { /// /// - Returns: the requested implicit representation, if one exists, or `nil`. /// - private func implicitRepresentation(for elementType: StandardElementType, inheriting attributes: [String:Any]) -> NSAttributedString? { + private func implicitRepresentation(for elementType: StandardElementType, inheriting attributes: [NSAttributedStringKey: Any]) -> NSAttributedString? { switch elementType { case .hr, .img, .video: diff --git a/Aztec/Classes/TextKit/HTMLStorage.swift b/Aztec/Classes/TextKit/HTMLStorage.swift index 0ec8f8d33..2f758d95c 100644 --- a/Aztec/Classes/TextKit/HTMLStorage.swift +++ b/Aztec/Classes/TextKit/HTMLStorage.swift @@ -66,7 +66,7 @@ open class HTMLStorage: NSTextStorage { return textStore.string } - override open func attributes(at location: Int, effectiveRange range: NSRangePointer?) -> [String : Any] { + override open func attributes(at location: Int, effectiveRange range: NSRangePointer?) -> [NSAttributedStringKey : Any] { guard textStore.length != 0 else { return [:] } @@ -74,7 +74,7 @@ open class HTMLStorage: NSTextStorage { return textStore.attributes(at: location, effectiveRange: range) } - override open func setAttributes(_ attrs: [String : Any]?, range: NSRange) { + override open func setAttributes(_ attrs: [NSAttributedStringKey : Any]?, range: NSRange) { beginEditing() textStore.setAttributes(attrs, range: range) @@ -83,11 +83,11 @@ open class HTMLStorage: NSTextStorage { endEditing() } - override open func addAttribute(_ name: String, value: Any, range: NSRange) { + override open func addAttribute(_ name: NSAttributedStringKey, value: Any, range: NSRange) { textStore.addAttribute(name, value: value, range: range) } - override open func removeAttribute(_ name: String, range: NSRange) { + override open func removeAttribute(_ name: NSAttributedStringKey, range: NSRange) { textStore.removeAttribute(name, range: range) } @@ -125,22 +125,22 @@ private extension HTMLStorage { func colorizeHTML() { let fullStringRange = rangeOfEntireString - removeAttribute(NSForegroundColorAttributeName, range: fullStringRange) - addAttribute(NSFontAttributeName, value: font, range: fullStringRange) + removeAttribute(.foregroundColor, range: fullStringRange) + addAttribute(.font, value: font, range: fullStringRange) let tags = RegExes.html.matches(in: string, options: [], range: fullStringRange) for tag in tags { - addAttribute(NSForegroundColorAttributeName, value: tagColor, range: tag.range) + addAttribute(.foregroundColor, value: tagColor, range: tag.range) let quotes = RegExes.quotes.matches(in: string, options: [], range: tag.range) for quote in quotes { - addAttribute(NSForegroundColorAttributeName, value: quotedColor, range: quote.range) + addAttribute(.foregroundColor, value: quotedColor, range: quote.range) } } let comments = RegExes.comments.matches(in: string, options: [], range: fullStringRange) for comment in comments { - addAttribute(NSForegroundColorAttributeName, value: commentColor, range: comment.range) + addAttribute(.foregroundColor, value: commentColor, range: comment.range) } } } diff --git a/Aztec/Classes/TextKit/LayoutManager.swift b/Aztec/Classes/TextKit/LayoutManager.swift index 1602eb121..096861f80 100644 --- a/Aztec/Classes/TextKit/LayoutManager.swift +++ b/Aztec/Classes/TextKit/LayoutManager.swift @@ -21,7 +21,7 @@ class LayoutManager: NSLayoutManager { /// Closure that is expected to return the TypingAttributes associated to the Extra Line Fragment /// - var extraLineFragmentTypingAttributes: (() -> [String: Any])? + var extraLineFragmentTypingAttributes: (() -> [NSAttributedStringKey: Any])? /// Blockquote's Left Border width /// @@ -58,7 +58,7 @@ private extension LayoutManager { let characterRange = self.characterRange(forGlyphRange: glyphsToShow, actualGlyphRange: nil) // Draw: Blockquotes - textStorage.enumerateAttribute(NSParagraphStyleAttributeName, in: characterRange, options: []) { (object, range, stop) in + textStorage.enumerateAttribute(.paragraphStyle, in: characterRange, options: []) { (object, range, stop) in guard let paragraphStyle = object as? ParagraphStyle, !paragraphStyle.blockquotes.isEmpty else { return } @@ -82,7 +82,7 @@ private extension LayoutManager { return } - guard let paragraphStyle = typingAttributes[NSParagraphStyleAttributeName] as? ParagraphStyle, + guard let paragraphStyle = typingAttributes[.paragraphStyle] as? ParagraphStyle, !paragraphStyle.blockquotes.isEmpty else { return } @@ -153,7 +153,7 @@ private extension LayoutManager { let characterRange = self.characterRange(forGlyphRange: glyphsToShow, actualGlyphRange: nil) //draw html pre paragraphs - textStorage.enumerateAttribute(NSParagraphStyleAttributeName, in: characterRange, options: []){ (object, range, stop) in + textStorage.enumerateAttribute(.paragraphStyle, in: characterRange, options: []){ (object, range, stop) in guard let paragraphStyle = object as? ParagraphStyle, paragraphStyle.htmlPre != nil else { return } @@ -194,7 +194,7 @@ private extension LayoutManager { textStorage.enumerateParagraphRanges(spanning: characterRange) { (range, enclosingRange) in guard textStorage.string.isStartOfNewLine(atUTF16Offset: enclosingRange.location), - let paragraphStyle = textStorage.attribute(NSParagraphStyleAttributeName, at: enclosingRange.location, effectiveRange: nil) as? ParagraphStyle, + let paragraphStyle = textStorage.attribute(.paragraphStyle, at: enclosingRange.location, effectiveRange: nil) as? ParagraphStyle, let list = paragraphStyle.lists.last else { return @@ -271,20 +271,20 @@ private extension LayoutManager { /// Returns the Marker Text Attributes, based on a collection that defines Regular Text Attributes. /// - private func markerAttributesBasedOnParagraph(attributes: [String: Any]) -> [String: Any] { + private func markerAttributesBasedOnParagraph(attributes: [NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] { var resultAttributes = attributes var indent: CGFloat = 0 - if let style = attributes[NSParagraphStyleAttributeName] as? ParagraphStyle { + if let style = attributes[.paragraphStyle] as? ParagraphStyle { indent = style.listIndent + Metrics.listTextIndentation } - resultAttributes[NSParagraphStyleAttributeName] = markerParagraphStyle(indent: indent) - resultAttributes.removeValue(forKey: NSUnderlineStyleAttributeName) - resultAttributes.removeValue(forKey: NSStrikethroughStyleAttributeName) - resultAttributes.removeValue(forKey: NSLinkAttributeName) + resultAttributes[.paragraphStyle] = markerParagraphStyle(indent: indent) + resultAttributes.removeValue(forKey: .underlineStyle) + resultAttributes.removeValue(forKey: .strikethroughStyle) + resultAttributes.removeValue(forKey: .link) - if let font = resultAttributes[NSFontAttributeName] as? UIFont { - resultAttributes[NSFontAttributeName] = fixFontForMarkerAttributes(font: font) + if let font = resultAttributes[.font] as? UIFont { + resultAttributes[.font] = fixFontForMarkerAttributes(font: font) } return resultAttributes diff --git a/Aztec/Classes/TextKit/MediaAttachment.swift b/Aztec/Classes/TextKit/MediaAttachment.swift index ae76c23b0..fd2057de7 100644 --- a/Aztec/Classes/TextKit/MediaAttachment.swift +++ b/Aztec/Classes/TextKit/MediaAttachment.swift @@ -307,7 +307,7 @@ open class MediaAttachment: NSTextAttachment { var padding = (textContainer?.lineFragmentPadding ?? 0) if let storage = textContainer?.layoutManager?.textStorage, - let paragraphStyle = storage.attribute(NSParagraphStyleAttributeName, at: charIndex, effectiveRange: nil) as? NSParagraphStyle { + let paragraphStyle = storage.attribute(.paragraphStyle, at: charIndex, effectiveRange: nil) as? NSParagraphStyle { padding += paragraphStyle.firstLineHeadIndent + paragraphStyle.tailIndent } let width = floor(lineFrag.width - (padding * 2)) @@ -360,7 +360,7 @@ private extension MediaAttachment { self.isFetchingImage = false self.invalidateLayout(in: textContainer) - }, onFailure: { [weak self] _ in + }, onFailure: { [weak self] () in self?.isFetchingImage = false }) diff --git a/Aztec/Classes/TextKit/ParagraphStyle.swift b/Aztec/Classes/TextKit/ParagraphStyle.swift index 42b89abd1..91a43d4af 100644 --- a/Aztec/Classes/TextKit/ParagraphStyle.swift +++ b/Aztec/Classes/TextKit/ParagraphStyle.swift @@ -347,7 +347,7 @@ extension ParagraphStyle { /// clustered at the 'Right Hand Side' of the currently existant list. /// func insertProperty(_ property: ParagraphProperty, afterLastOfType type: AnyClass) { - guard let targetIndex = properties.lastIndex(where: { type(of: $0) == type }) else { + guard let targetIndex = properties.lastIndex(where: { Swift.type(of: $0) == type }) else { properties.append(property) return } @@ -359,7 +359,7 @@ extension ParagraphStyle { /// func removeProperty(ofType type: AnyClass) { for index in (0.. [String : Any] { + override open func attributes(at location: Int, effectiveRange range: NSRangePointer?) -> [NSAttributedStringKey : Any] { guard textStore.length > 0 else { return [:] @@ -257,7 +257,7 @@ open class TextStorage: NSTextStorage { endEditing() } - override open func setAttributes(_ attrs: [String: Any]?, range: NSRange) { + override open func setAttributes(_ attrs: [NSAttributedStringKey: Any]?, range: NSRange) { beginEditing() let fixedAttributes = ensureMatchingFontAndParagraphHeaderStyles(beforeApplying: attrs ?? [:], at: range) @@ -341,7 +341,7 @@ open class TextStorage: NSTextStorage { } func setHTML(_ html: String, - defaultAttributes: [String: Any], + defaultAttributes: [NSAttributedStringKey: Any], postProcessingHTMLWith postProcessHTML: HTMLTreeProcessor? = nil) { let originalLength = textStore.length @@ -380,9 +380,9 @@ private extension TextStorage { /// /// - Returns: Collection of attributes with the Font Attribute corrected, if needed. /// - func ensureMatchingFontAndParagraphHeaderStyles(beforeApplying attrs: [String: Any], at range: NSRange) -> [String: Any] { - let newStyle = attrs[NSParagraphStyleAttributeName] as? ParagraphStyle - let oldStyle = textStore.attribute(NSParagraphStyleAttributeName, at: range.location, effectiveRange: nil) as? ParagraphStyle + func ensureMatchingFontAndParagraphHeaderStyles(beforeApplying attrs: [NSAttributedStringKey: Any], at range: NSRange) -> [NSAttributedStringKey: Any] { + let newStyle = attrs[.paragraphStyle] as? ParagraphStyle + let oldStyle = textStore.attribute(.paragraphStyle, at: range.location, effectiveRange: nil) as? ParagraphStyle let newLevel = newStyle?.headers.last?.level ?? .none let oldLevel = oldStyle?.headers.last?.level ?? .none @@ -403,7 +403,7 @@ private extension TextStorage { /// /// - Returns: Collection of attributes with the Font Attribute corrected, so that it matches the specified HeaderLevel. /// - private func fixFontAttribute(in attrs: [String: Any], headerLevel: Header.HeaderType) -> [String: Any] { + private func fixFontAttribute(in attrs: [NSAttributedStringKey: Any], headerLevel: Header.HeaderType) -> [NSAttributedStringKey: Any] { let formatter = HeaderFormatter(headerLevel: headerLevel) return formatter.apply(to: attrs) } diff --git a/Aztec/Classes/TextKit/TextView.swift b/Aztec/Classes/TextKit/TextView.swift index 3dba7f759..ba7757c2f 100644 --- a/Aztec/Classes/TextKit/TextView.swift +++ b/Aztec/Classes/TextKit/TextView.swift @@ -151,9 +151,9 @@ open class TextView: UITextView { open let defaultParagraphStyle: ParagraphStyle var defaultMissingImage: UIImage - fileprivate var defaultAttributes: [String: Any] { - return [NSFontAttributeName: defaultFont, - NSParagraphStyleAttributeName: defaultParagraphStyle] + fileprivate var defaultAttributes: [NSAttributedStringKey: Any] { + return [.font: defaultFont, + .paragraphStyle: defaultParagraphStyle] } @@ -188,7 +188,7 @@ open class TextView: UITextView { /// Blockquote Blocks Border COlor. /// - dynamic public var blockquoteBorderColor: UIColor { + @objc dynamic public var blockquoteBorderColor: UIColor { get { return layout.blockquoteBorderColor } @@ -199,7 +199,7 @@ open class TextView: UITextView { /// Blockquote Blocks Background Color. /// - dynamic public var blockquoteBackgroundColor: UIColor { + @objc dynamic public var blockquoteBackgroundColor: UIColor { get { return layout.blockquoteBackgroundColor } @@ -211,7 +211,7 @@ open class TextView: UITextView { /// Blockquote Blocks Background Width. /// - dynamic public var blockquoteBorderWidth: CGFloat { + @objc dynamic public var blockquoteBorderWidth: CGFloat { get { return layout.blockquoteBorderWidth } @@ -222,7 +222,7 @@ open class TextView: UITextView { /// Pre Blocks Background Color. /// - dynamic public var preBackgroundColor: UIColor { + @objc dynamic public var preBackgroundColor: UIColor { get { return layout.preBackgroundColor } @@ -248,11 +248,24 @@ open class TextView: UITextView { } } + + /// + /// + open var typingAttributesSwifted: [NSAttributedStringKey: Any] { + get { + return NSAttributedStringKey.convertFromRaw(attributes: typingAttributes) + } + set { + typingAttributes = NSAttributedStringKey.convertToRaw(attributes: newValue) + } + } + + /// This property returns the Attributes associated to the Extra Line Fragment. /// - public var extraLineFragmentTypingAttributes: [String: Any] { + public var extraLineFragmentTypingAttributes: [NSAttributedStringKey: Any] { guard selectedTextRange?.start != endOfDocument else { - return typingAttributes + return typingAttributesSwifted } let string = textStorage.string @@ -304,8 +317,9 @@ open class TextView: UITextView { allowsEditingTextAttributes = true storage.attachmentsDelegate = self font = defaultFont - linkTextAttributes = [NSUnderlineStyleAttributeName: NSNumber(value:NSUnderlineStyle.styleSingle.rawValue), NSForegroundColorAttributeName: self.tintColor] - typingAttributes = defaultAttributes + linkTextAttributes = [NSAttributedStringKey.underlineStyle.rawValue: NSNumber(value:NSUnderlineStyle.styleSingle.rawValue), + NSAttributedStringKey.foregroundColor.rawValue: self.tintColor] + typingAttributesSwifted = defaultAttributes setupMenuController() setupAttachmentTouchDetection() setupLayoutManager() @@ -344,7 +358,7 @@ open class TextView: UITextView { aztecLayoutManager.extraLineFragmentTypingAttributes = { [weak self] in return self?.extraLineFragmentTypingAttributes ?? [:] - } + } } // MARK: - Intercept copy paste operations @@ -383,14 +397,14 @@ open class TextView: UITextView { selectedRange = NSRange(location: selectedRange.location + string.length, length: 0) } - open func pasteAndMatchStyle(_ sender: Any?) { + @objc open func pasteAndMatchStyle(_ sender: Any?) { guard let string = UIPasteboard.general.loadAttributedString()?.mutableCopy() as? NSMutableAttributedString else { super.paste(sender) return } let range = string.rangeOfEntireString - string.addAttributes(typingAttributes, range: range) + string.addAttributes(typingAttributesSwifted, range: range) string.loadLazyAttachments() storage.replaceCharacters(in: selectedRange, with: string) @@ -413,12 +427,12 @@ open class TextView: UITextView { } } - func handleShiftEnter(command: UIKeyCommand) { + @objc func handleShiftEnter(command: UIKeyCommand) { insertText(String(.lineSeparator)) } - func handleShiftTab(command: UIKeyCommand) { - guard let list = TextListFormatter.lists(in: typingAttributes).last else { + @objc func handleShiftTab(command: UIKeyCommand) { + guard let list = TextListFormatter.lists(in: typingAttributesSwifted).last else { return } @@ -427,13 +441,13 @@ open class TextView: UITextView { performUndoable(at: targetRange) { let finalRange = formatter.removeAttributes(from: storage, at: targetRange) - typingAttributes = textStorage.attributes(at: targetRange.location, effectiveRange: nil) + typingAttributesSwifted = textStorage.attributes(at: targetRange.location, effectiveRange: nil) return finalRange } } - func handleTab(command: UIKeyCommand) { - let lists = TextListFormatter.lists(in: typingAttributes) + @objc func handleTab(command: UIKeyCommand) { + let lists = TextListFormatter.lists(in: typingAttributesSwifted) guard let list = lists.last, lists.count < maximumListIndentationLevels else { insertText(String(.tab)) return @@ -444,7 +458,7 @@ open class TextView: UITextView { performUndoable(at: targetRange) { let finalRange = formatter.applyAttributes(to: storage, at: targetRange) - typingAttributes = textStorage.attributes(at: targetRange.location, effectiveRange: nil) + typingAttributesSwifted = textStorage.attributes(at: targetRange.location, effectiveRange: nil) return finalRange } } @@ -472,7 +486,7 @@ open class TextView: UITextView { // This was causing the following issue: // https://github.com/wordpress-mobile/AztecEditor-iOS/issues/462 // - typingAttributes[NSAttachmentAttributeName] = nil + typingAttributesSwifted[.attachment] = nil guard !ensureRemovalOfParagraphAttributesWhenPressingEnterInAnEmptyParagraph(input: text) else { return @@ -607,7 +621,7 @@ open class TextView: UITextView { postProcessingHTMLWith: inputTreeProcessor) if storage.length > 0 && selectedRange.location < storage.length { - typingAttributes = storage.attributes(at: selectedRange.location, effectiveRange: nil) + typingAttributesSwifted = storage.attributes(at: selectedRange.location, effectiveRange: nil) } notifyTextViewDidChange() @@ -700,7 +714,7 @@ open class TextView: UITextView { var identifiers = [FormattingIdentifier]() for (key, formatter) in formatterIdentifiersMap { - if formatter.present(in: typingAttributes) { + if formatter.present(in: typingAttributesSwifted) { identifiers.append(key) } } @@ -751,13 +765,13 @@ open class TextView: UITextView { }) if applicationRange.length == 0 { - typingAttributes = formatter.toggle(in: typingAttributes) + typingAttributesSwifted = formatter.toggle(in: typingAttributesSwifted) } else { // NOTE: We are making sure that the selectedRange location is inside the string // The selected range can be out of the string when you are adding content to the end of the string. // In those cases we check the atributes of the previous caracter let location = max(0,min(selectedRange.location, textStorage.length-1)) - typingAttributes = textStorage.attributes(at: location, effectiveRange: nil) + typingAttributesSwifted = textStorage.attributes(at: location, effectiveRange: nil) } notifyTextViewDidChange() } @@ -812,7 +826,7 @@ open class TextView: UITextView { open func togglePre(range: NSRange) { ensureInsertionOfEndOfLineForEmptyParagraphAtEndOfFile(forApplicationRange: range) - let formatter = PreFormatter(placeholderAttributes: typingAttributes) + let formatter = PreFormatter(placeholderAttributes: typingAttributesSwifted) toggle(formatter: formatter, atRange: range) forceRedrawCursorAfterDelay() @@ -829,7 +843,7 @@ open class TextView: UITextView { open func toggleBlockquote(range: NSRange) { ensureInsertionOfEndOfLineForEmptyParagraphAtEndOfFile(forApplicationRange: range) - let formatter = BlockquoteFormatter(placeholderAttributes: typingAttributes) + let formatter = BlockquoteFormatter(placeholderAttributes: typingAttributesSwifted) toggle(formatter: formatter, atRange: range) forceRedrawCursorAfterDelay() @@ -842,7 +856,7 @@ open class TextView: UITextView { open func toggleOrderedList(range: NSRange) { ensureInsertionOfEndOfLineForEmptyParagraphAtEndOfFile(forApplicationRange: range) - let formatter = TextListFormatter(style: .ordered, placeholderAttributes: typingAttributes) + let formatter = TextListFormatter(style: .ordered, placeholderAttributes: typingAttributesSwifted) toggle(formatter: formatter, atRange: range) forceRedrawCursorAfterDelay() @@ -856,7 +870,7 @@ open class TextView: UITextView { open func toggleUnorderedList(range: NSRange) { ensureInsertionOfEndOfLineForEmptyParagraphAtEndOfFile(forApplicationRange: range) - let formatter = TextListFormatter(style: .unordered, placeholderAttributes: typingAttributes) + let formatter = TextListFormatter(style: .unordered, placeholderAttributes: typingAttributesSwifted) toggle(formatter: formatter, atRange: range) forceRedrawCursorAfterDelay() @@ -868,7 +882,7 @@ open class TextView: UITextView { /// - Parameter range: The NSRange to edit. /// open func toggleHeader(_ headerType: Header.HeaderType, range: NSRange) { - let formatter = HeaderFormatter(headerLevel: headerType, placeholderAttributes: typingAttributes) + let formatter = HeaderFormatter(headerLevel: headerType, placeholderAttributes: typingAttributesSwifted) toggle(formatter: formatter, atRange: range) forceRedrawCursorAfterDelay() } @@ -898,11 +912,11 @@ open class TextView: UITextView { /// This is meant as a workaround for the "Emojis Mixing Up Font's" glitch. /// private func restoreDefaultFontIfNeeded() { - guard let activeFont = typingAttributes[NSFontAttributeName] as? UIFont, activeFont.isAppleEmojiFont else { + guard let activeFont = typingAttributesSwifted[.font] as? UIFont, activeFont.isAppleEmojiFont else { return } - typingAttributes[NSFontAttributeName] = defaultFont.withSize(activeFont.pointSize) + typingAttributesSwifted[.font] = defaultFont.withSize(activeFont.pointSize) } @@ -953,7 +967,7 @@ open class TextView: UITextView { ] let found = formatters.first { formatter in - return formatter.present(in: typingAttributes) + return formatter.present(in: typingAttributesSwifted) } guard found != nil else { @@ -986,7 +1000,7 @@ open class TextView: UITextView { /// - Parameter range: Range in which new text will be inserted. /// private func ensureRemovalOfLinkTypingAttribute(at range: NSRange) { - guard typingAttributes[NSLinkAttributeName] != nil else { + guard typingAttributes[NSAttributedStringKey.link.rawValue] != nil else { return } @@ -996,7 +1010,7 @@ open class TextView: UITextView { return } - typingAttributes.removeValue(forKey: NSLinkAttributeName) + typingAttributes.removeValue(forKey: NSAttributedStringKey.link.rawValue) } @@ -1139,7 +1153,7 @@ open class TextView: UITextView { block() - typingAttributes = previousAttributes + typingAttributesSwifted = previousAttributes } @@ -1164,7 +1178,7 @@ open class TextView: UITextView { let formatter = LinkFormatter() formatter.attributeValue = url - let attributes = formatter.apply(to: typingAttributes) + let attributes = formatter.apply(to: typingAttributesSwifted) storage.replaceCharacters(in: range, with: NSAttributedString(string: title, attributes: attributes)) @@ -1205,7 +1219,7 @@ open class TextView: UITextView { undoManager?.registerUndo(withTarget: self, handler: { [weak self] target in self?.undoTextReplacement(of: originalText, finalRange: finalRange) }) - let attachmentString = NSAttributedString(attachment: attachment, attributes: typingAttributes) + let attachmentString = NSAttributedString(attachment: attachment, attributes: typingAttributesSwifted) storage.replaceCharacters(in: range, with: attachmentString) selectedRange = NSMakeRange(range.location + NSAttributedString.lengthOfTextAttachment, 0) notifyTextViewDidChange() @@ -1254,7 +1268,7 @@ open class TextView: UITextView { self?.undoTextReplacement(of: originalText, finalRange: finalRange) }) - storage.replaceCharacters(in: range, with: NSAttributedString(string: "", attributes: typingAttributes)) + storage.replaceCharacters(in: range, with: NSAttributedString(string: "", attributes: typingAttributesSwifted)) notifyTextViewDidChange() } @@ -1298,7 +1312,7 @@ open class TextView: UITextView { } var effectiveRange = NSRange() - guard let attachment = textStorage.attribute(NSAttachmentAttributeName, at: index, effectiveRange: &effectiveRange) as? NSTextAttachment else { + guard let attachment = textStorage.attribute(.attachment, at: index, effectiveRange: &effectiveRange) as? NSTextAttachment else { return nil } @@ -1375,7 +1389,7 @@ open class TextView: UITextView { let index = maxIndex(range.location) var effectiveRange = NSRange() guard index < storage.length, - let attr = storage.attribute(NSLinkAttributeName, at: index, effectiveRange: &effectiveRange) + let attr = storage.attribute(.link, at: index, effectiveRange: &effectiveRange) else { return nil } @@ -1402,7 +1416,7 @@ open class TextView: UITextView { let index = maxIndex(range.location) var effectiveRange = NSRange() guard index < storage.length, - storage.attribute(NSLinkAttributeName, at: index, effectiveRange: &effectiveRange) != nil + storage.attribute(.link, at: index, effectiveRange: &effectiveRange) != nil else { return nil } @@ -1480,7 +1494,7 @@ open class TextView: UITextView { block(copy) performUndoable(at: range) { - storage.setAttributes([NSAttachmentAttributeName: copy], range: range) + storage.setAttributes([.attachment: copy], range: range) return range } } @@ -1577,8 +1591,8 @@ private extension TextView { HeaderFormatter(headerLevel: .h6, placeholderAttributes: [:]) ] - for formatter in formatters where formatter.present(in: typingAttributes) { - typingAttributes = formatter.remove(from: typingAttributes) + for formatter in formatters where formatter.present(in: typingAttributesSwifted) { + typingAttributesSwifted = formatter.remove(from: typingAttributesSwifted) let applicationRange = formatter.applicationRange(for: selectedRange, in: textStorage) formatter.removeAttributes(from: textStorage, at: applicationRange) @@ -1607,11 +1621,13 @@ private extension TextView { /// - Returns: `true` if we should remove paragraph attributes, otherwise it returns `false`. /// private func mustRemoveParagraphAttributesWhenPressingEnterInAnEmptyParagraph(input: String) -> Bool { + let activeTypingAttributes = typingAttributesSwifted + return input.isEndOfLine() && storage.string.isEmptyLine(at: selectedRange.location) - && (BlockquoteFormatter().present(in: typingAttributes) - || TextListFormatter.listsOfAnyKindPresent(in: typingAttributes) - || PreFormatter().present(in: typingAttributes)) + && (BlockquoteFormatter().present(in: activeTypingAttributes) + || TextListFormatter.listsOfAnyKindPresent(in: activeTypingAttributes) + || PreFormatter().present(in: activeTypingAttributes)) } @@ -1665,7 +1681,7 @@ private extension TextView { private func removeParagraphAttributes(at range: NSRange) { let formatters: [AttributeFormatter] = [ BlockquoteFormatter(), - PreFormatter(placeholderAttributes: defaultAttributes), + PreFormatter(placeholderAttributes: typingAttributesSwifted), TextListFormatter(style: .ordered), TextListFormatter(style: .unordered) ] @@ -1792,7 +1808,7 @@ extension TextView: TextStorageAttachmentsDelegate { return true } - func richTextViewWasPressed(_ recognizer: UIGestureRecognizer) { + @objc func richTextViewWasPressed(_ recognizer: UIGestureRecognizer) { guard let textView = textView, recognizer.state == .recognized else { return } diff --git a/AztecTests/Extensions/NSAttributedStringAnalyzerTests.swift b/AztecTests/Extensions/NSAttributedStringAnalyzerTests.swift index 0e6712b29..b2b044672 100644 --- a/AztecTests/Extensions/NSAttributedStringAnalyzerTests.swift +++ b/AztecTests/Extensions/NSAttributedStringAnalyzerTests.swift @@ -20,8 +20,8 @@ class NSAttributedStringAnalyzerTests: XCTestCase { /// Linkified String /// static let linkifiedString = { _ -> NSAttributedString in - return NSAttributedString(string: "WordPress iOS + Aztec", attributes: [NSLinkAttributeName: wordpressURL]) - }() + return NSAttributedString(string: "WordPress iOS + Aztec", attributes: [.link: wordpressURL]) + }(()) /// Plain Tail String /// @@ -35,13 +35,13 @@ class NSAttributedStringAnalyzerTests: XCTestCase { fullString.append(linkifiedString) fullString.append(tailString) return fullString - }() + }(()) /// NSRange indicating the linkified segment /// static let linkifiedRange = { _ -> NSRange in return fullString.foundationString.range(of: linkifiedString.string) - }() + }(()) /// Initial Link Location /// diff --git a/AztecTests/Extensions/NSAttributedStringHTMLInitializerTests.swift b/AztecTests/Extensions/NSAttributedStringHTMLInitializerTests.swift index bbb19e463..f2594a488 100644 --- a/AztecTests/Extensions/NSAttributedStringHTMLInitializerTests.swift +++ b/AztecTests/Extensions/NSAttributedStringHTMLInitializerTests.swift @@ -13,8 +13,8 @@ class NSAttributedStringHTMLInitializerTests: XCTestCase { let html = "" - let defaultAttributes = [NSFontAttributeName: UIFont.systemFont(ofSize: 14), - NSParagraphStyleAttributeName: ParagraphStyle.default] + let defaultAttributes: [NSAttributedStringKey: Any] = [.font: UIFont.systemFont(ofSize: 14), + .paragraphStyle: ParagraphStyle.default] XCTAssertNoThrow(NSAttributedString(withHTML: html, defaultAttributes: defaultAttributes)) } diff --git a/AztecTests/Extensions/NSAttributedStringListsTests.swift b/AztecTests/Extensions/NSAttributedStringListsTests.swift index ab131715c..a0e51c1b9 100644 --- a/AztecTests/Extensions/NSAttributedStringListsTests.swift +++ b/AztecTests/Extensions/NSAttributedStringListsTests.swift @@ -255,7 +255,7 @@ extension NSAttributedStringListsTests let range = (sample.string as NSString).range(of: sampleListContents) let listParagraphStyle = ParagraphStyle() listParagraphStyle.appendProperty(TextList(style: .ordered)) - let attributes = [NSParagraphStyleAttributeName: listParagraphStyle] + let attributes = [.paragraphStyle: listParagraphStyle] sample.addAttributes(attributes, range: range) return sample diff --git a/AztecTests/Formatters/BlockquoteFormatterTests.swift b/AztecTests/Formatters/BlockquoteFormatterTests.swift index 53ec108b8..be74c1a5a 100644 --- a/AztecTests/Formatters/BlockquoteFormatterTests.swift +++ b/AztecTests/Formatters/BlockquoteFormatterTests.swift @@ -63,7 +63,7 @@ class BlockquoteFormatterTests: XCTestCase { func testToggleBlockquoteTwiceLeavesReturnsIdenticalString() { let textView = testTextView let storage = textView.storage - textView.storage.setAttributes([NSParagraphStyleAttributeName: ParagraphStyle.default], range: textView.storage.rangeOfEntireString) + textView.storage.setAttributes([.paragraphStyle: ParagraphStyle.default], range: textView.storage.rangeOfEntireString) let paragraphs = paragraphRanges(inString: storage) let formatter = BlockquoteFormatter() @@ -118,7 +118,7 @@ private extension BlockquoteFormatterTests { func existsBlockquote(for string: NSMutableAttributedString, in range: NSRange) -> Bool { var effectiveRange = NSRange() - guard let paragraphStyle = string.attribute(NSParagraphStyleAttributeName, at: range.location, effectiveRange: &effectiveRange) as? ParagraphStyle, + guard let paragraphStyle = string.attribute(.paragraphStyle, at: range.location, effectiveRange: &effectiveRange) as? ParagraphStyle, !paragraphStyle.blockquotes.isEmpty else { return false } diff --git a/AztecTests/Formatters/FontFormatterTests.swift b/AztecTests/Formatters/FontFormatterTests.swift index 4cbd5d209..d812739d9 100644 --- a/AztecTests/Formatters/FontFormatterTests.swift +++ b/AztecTests/Formatters/FontFormatterTests.swift @@ -10,44 +10,45 @@ class FontFormatterTests: XCTestCase let italicFormatter = ItalicFormatter() func testApplyAttribute() { - var attributes: [String : Any] = [NSFontAttributeName: UIFont.systemFont(ofSize: UIFont.systemFontSize)] + var attributes: [NSAttributedStringKey : Any] = [.font.rawValue: UIFont.systemFont(ofSize: UIFont.systemFontSize)] var font: UIFont? //test adding a non-existent testApplyAttribute attributes = boldFormatter.apply(to: attributes) //this should add a new attribute to it - font = attributes[NSFontAttributeName] as? UIFont + font = attributes[.font] as? UIFont XCTAssertNotNil(font) XCTAssertTrue(font!.containsTraits(.traitBold)) //test addding a existent attribute attributes = boldFormatter.apply(to: attributes) // this shouldn't change anything in the attributes - font = attributes[NSFontAttributeName] as? UIFont + font = attributes[.font] as? UIFont XCTAssertNotNil(font) XCTAssertTrue(font!.containsTraits(.traitBold)) } func testRemoveAttributes() { - var attributes: [String : Any] = [NSFontAttributeName: UIFont.boldSystemFont(ofSize: UIFont.systemFontSize)] + var attributes: [NSAttributedStringKey : Any] = [.font.rawValue: UIFont.boldSystemFont(ofSize: UIFont.systemFontSize)] var font: UIFont? //test removing a existent attribute attributes = boldFormatter.remove(from: attributes) - font = attributes[NSFontAttributeName] as? UIFont + font = attributes[.font] as? UIFont XCTAssertNotNil(font) XCTAssertFalse(font!.containsTraits(.traitBold)) - attributes = [NSFontAttributeName: UIFont.boldSystemFont(ofSize: UIFont.systemFontSize)] + attributes = [.font: UIFont.boldSystemFont(ofSize: UIFont.systemFontSize)] //test removing a non-existent testApplyAttribute attributes = italicFormatter.remove(from: attributes) - font = attributes[NSFontAttributeName] as? UIFont + font = attributes[.font] as? UIFont XCTAssertNotNil(font) XCTAssertTrue(font!.containsTraits(.traitBold)) } func testPresentAttributes() { - var attributes: [String : Any] = [NSFontAttributeName: UIFont.boldSystemFont(ofSize: UIFont.systemFontSize)] + var attributes: [NSAttributedStringKey : Any] = [.font: UIFont.boldSystemFont(ofSize: UIFont.systemFontSize)] + //test when attribute is present XCTAssertTrue(boldFormatter.present(in: attributes)) //test when attributes is not present diff --git a/AztecTests/Formatters/HeaderFormatterTests.swift b/AztecTests/Formatters/HeaderFormatterTests.swift index 5e6a06b0e..aa08a6076 100644 --- a/AztecTests/Formatters/HeaderFormatterTests.swift +++ b/AztecTests/Formatters/HeaderFormatterTests.swift @@ -13,7 +13,7 @@ class HeaderFormatterTests: XCTestCase { /// Sample Attributes /// private lazy var attributes: [String: Any] = { - return [NSFontAttributeName: UIFont.systemFont(ofSize: self.defaultFontSize)] + return [.font: UIFont.systemFont(ofSize: self.defaultFontSize)] }() @@ -23,11 +23,11 @@ class HeaderFormatterTests: XCTestCase { let formatter = HeaderFormatter(headerLevel: .h1, placeholderAttributes: nil) let updatedAttrs = formatter.apply(to: attributes, andStore: nil) - let updatedFont = updatedAttrs[NSFontAttributeName] as! UIFont + let updatedFont = updatedAttrs[.font] as! UIFont XCTAssert(updatedFont.pointSize == CGFloat(formatter.headerLevel.fontSize)) let removedAttrs = formatter.remove(from: updatedAttrs) - let removedFont = removedAttrs[NSFontAttributeName] as! UIFont + let removedFont = removedAttrs[.font] as! UIFont XCTAssert(removedFont.pointSize == defaultFontSize) } @@ -36,16 +36,16 @@ class HeaderFormatterTests: XCTestCase { func testDefaultFontIsPreservedWheneverTheHeaderLevelIsUpdated() { let formatterH1 = HeaderFormatter(headerLevel: .h1, placeholderAttributes: nil) let updatedH1Attrs = formatterH1.apply(to: attributes, andStore: nil) - let updatedH1Font = updatedH1Attrs[NSFontAttributeName] as! UIFont + let updatedH1Font = updatedH1Attrs[.font] as! UIFont XCTAssert(updatedH1Font.pointSize == CGFloat(formatterH1.headerLevel.fontSize)) let formatterH2 = HeaderFormatter(headerLevel: .h2, placeholderAttributes: nil) let updatedH2Attrs = formatterH2.apply(to: attributes, andStore: nil) - let updatedH2Font = updatedH2Attrs[NSFontAttributeName] as! UIFont + let updatedH2Font = updatedH2Attrs[.font] as! UIFont XCTAssert(updatedH2Font.pointSize == CGFloat(formatterH2.headerLevel.fontSize)) let removedAttrs = formatterH2.remove(from: updatedH2Attrs) - let removedFont = removedAttrs[NSFontAttributeName] as! UIFont + let removedFont = removedAttrs[.font] as! UIFont XCTAssert(removedFont.pointSize == defaultFontSize) } } diff --git a/AztecTests/Formatters/PreFormaterTests.swift b/AztecTests/Formatters/PreFormaterTests.swift index fdde9e477..ada22f5e3 100644 --- a/AztecTests/Formatters/PreFormaterTests.swift +++ b/AztecTests/Formatters/PreFormaterTests.swift @@ -10,20 +10,20 @@ class PreFormatterTests: XCTestCase { /// to the formatter's behavior. /// func testPreFormatterDoesNotLooseAttachmentAttribuesOnRemove() { - let placeholderAttributes: [String: Any] = [ - NSFontAttributeName: "Value", - NSParagraphStyleAttributeName: NSParagraphStyle() + let placeholderAttributes: [NSAttributedStringKey: Any] = [ + .font: "Value", + .paragraphStyle: NSParagraphStyle() ] - let stringAttributes: [String: Any] = [ - NSAttachmentAttributeName: NSTextAttachment(), + let stringAttributes: [NSAttributedStringKey: Any] = [ + .attachment: NSTextAttachment(), ] let formatter = PreFormatter(placeholderAttributes: placeholderAttributes) let updated = formatter.remove(from: stringAttributes) - let expectedValue = stringAttributes[NSAttachmentAttributeName] as! NSTextAttachment - let updatedValue = updated[NSAttachmentAttributeName] as! NSTextAttachment + let expectedValue = stringAttributes[.attachment] as! NSTextAttachment + let updatedValue = updated[.attachment] as! NSTextAttachment XCTAssert(updatedValue == expectedValue) } diff --git a/AztecTests/NSAttributedString/Conversions/AttributedStringParserTests.swift b/AztecTests/NSAttributedString/Conversions/AttributedStringParserTests.swift index 0df0248c8..7821ae21a 100644 --- a/AztecTests/NSAttributedString/Conversions/AttributedStringParserTests.swift +++ b/AztecTests/NSAttributedString/Conversions/AttributedStringParserTests.swift @@ -847,9 +847,9 @@ private extension AttributedStringParserTests { /// Constants /// struct Constants { - static let sampleAttributes: [String : Any] = [ - NSFontAttributeName: UIFont.systemFont(ofSize: UIFont.systemFontSize), - NSParagraphStyleAttributeName: NSParagraphStyle() + static let sampleAttributes: [NSAttributedStringKey : Any] = [ + .font: UIFont.systemFont(ofSize: UIFont.systemFontSize), + .paragraphStyle: NSParagraphStyle() ] } } diff --git a/AztecTests/NSAttributedString/Conversions/AttributedStringSerializerTests.swift b/AztecTests/NSAttributedString/Conversions/AttributedStringSerializerTests.swift index 81bcb6186..bdcb36553 100644 --- a/AztecTests/NSAttributedString/Conversions/AttributedStringSerializerTests.swift +++ b/AztecTests/NSAttributedString/Conversions/AttributedStringSerializerTests.swift @@ -70,7 +70,7 @@ class AttributedStringSerializerTests: XCTestCase { // Test! var range = NSRange() - guard let paragraphStyle = output.attribute(NSParagraphStyleAttributeName, at: 0, effectiveRange: &range) as? ParagraphStyle else { + guard let paragraphStyle = output.attribute(.paragraphStyle, at: 0, effectiveRange: &range) as? ParagraphStyle else { XCTFail() return } @@ -172,8 +172,8 @@ class AttributedStringSerializerTests: XCTestCase { extension AttributedStringSerializerTests { func attributedString(from node: Node) -> NSAttributedString { - let defaultAttributes = [NSFontAttributeName: UIFont.systemFont(ofSize: 14), - NSParagraphStyleAttributeName: ParagraphStyle.default] + let defaultAttributes: [NSAttributedStringKey: Any] = [.font: UIFont.systemFont(ofSize: 14), + .paragraphStyle: ParagraphStyle.default] let serializer = AttributedStringSerializer(defaultAttributes: defaultAttributes) diff --git a/AztecTests/TextKit/TextStorageTests.swift b/AztecTests/TextKit/TextStorageTests.swift index def69ec9d..637eb4d73 100644 --- a/AztecTests/TextKit/TextStorageTests.swift +++ b/AztecTests/TextKit/TextStorageTests.swift @@ -31,7 +31,7 @@ class TextStorageTests: XCTestCase { func testFontTraitExistsAtIndex() { let attributes = [ - NSFontAttributeName: UIFont.boldSystemFont(ofSize: 10) + NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 10) ] storage.append(NSAttributedString(string: "foo")) @@ -52,7 +52,7 @@ class TextStorageTests: XCTestCase { func testFontTraitSpansRange() { let attributes = [ - NSFontAttributeName: UIFont.boldSystemFont(ofSize: 10) + NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 10) ] storage.append(NSAttributedString(string: "foo")) @@ -66,7 +66,7 @@ class TextStorageTests: XCTestCase { func testToggleTraitInRange() { let attributes = [ - NSFontAttributeName: UIFont.boldSystemFont(ofSize: 10) + NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 10) ] storage.append(NSAttributedString(string: "foo")) @@ -165,8 +165,8 @@ class TextStorageTests: XCTestCase { let finalHTML = "

\(updatedHTML)

" // Setup - let defaultAttributes = [NSFontAttributeName: UIFont.systemFont(ofSize: 14), - NSParagraphStyleAttributeName: ParagraphStyle.default] + let defaultAttributes = [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 14), + NSAttributedStringKey.paragraphStyle: ParagraphStyle.default] storage.setHTML(initialHTML, defaultAttributes: defaultAttributes) @@ -285,7 +285,7 @@ class TextStorageTests: XCTestCase { var oldFont: UIFont? for i in 0 ..< storage.length { - let currentFont = storage.attribute(NSFontAttributeName, at: i, effectiveRange: nil) as? UIFont + let currentFont = storage.attribute(.font, at: i, effectiveRange: nil) as? UIFont XCTAssert(oldFont == nil || oldFont == currentFont) oldFont = currentFont } @@ -381,8 +381,8 @@ class TextStorageTests: XCTestCase { let commentString = "This is a comment" let html = "" - let defaultAttributes = [NSFontAttributeName: UIFont.systemFont(ofSize: 14), - NSParagraphStyleAttributeName: ParagraphStyle.default] + let defaultAttributes: [NSAttributedStringKey: Any] = [.font: UIFont.systemFont(ofSize: 14), + .paragraphStyle: ParagraphStyle.default] storage.setHTML(html, defaultAttributes: defaultAttributes) storage.replaceCharacters(in: NSRange(location: 0, length: 1), with: NSAttributedString(string: "")) diff --git a/AztecTests/TextKit/TextViewTests.swift b/AztecTests/TextKit/TextViewTests.swift index 5314da98d..e89ff0ac0 100644 --- a/AztecTests/TextKit/TextViewTests.swift +++ b/AztecTests/TextKit/TextViewTests.swift @@ -55,7 +55,7 @@ class TextViewTests: XCTestCase { let paragraph = "Lorem ipsum dolar sit amet.\n" let richTextView = Aztec.TextView(defaultFont: UIFont.systemFont(ofSize: 14), defaultMissingImage: UIImage()) richTextView.textAttachmentDelegate = attachmentDelegate - let attributes = [NSParagraphStyleAttributeName : NSParagraphStyle()] + let attributes = [NSAttributedStringKey.paragraphStyle : NSParagraphStyle()] let templateString = NSMutableAttributedString(string: paragraph, attributes: attributes) let attrStr = NSMutableAttributedString() @@ -1526,7 +1526,7 @@ class TextViewTests: XCTestCase { XCTAssertEqual(html, "

") textView.selectedRange = NSRange(location: NSAttributedString.lengthOfTextAttachment, length: 1) - guard let font = textView.typingAttributes[NSFontAttributeName] as? UIFont else { + guard let font = textView.typingAttributesSwifted[.font] as? UIFont else { XCTFail("Font should be set") return } @@ -1537,7 +1537,7 @@ class TextViewTests: XCTestCase { let textView = createEmptyTextViewWithNonStandardSystemFont() textView.insertText("😘") - let currentTypingFont = textView.typingAttributes[NSFontAttributeName] as! UIFont + let currentTypingFont = textView.typingAttributesSwifted[.font] as! UIFont XCTAssertEqual(currentTypingFont, nonStandardSystemFont, "Font should be set to default") } diff --git a/Example/AztecExample.xcodeproj/project.pbxproj b/Example/AztecExample.xcodeproj/project.pbxproj index 7540e5942..770c5d0d2 100644 --- a/Example/AztecExample.xcodeproj/project.pbxproj +++ b/Example/AztecExample.xcodeproj/project.pbxproj @@ -367,12 +367,12 @@ 607FACCF1AFB9204008FA782 = { CreatedOnToolsVersion = 6.3.1; DevelopmentTeam = PZYM8XX95Q; - LastSwiftMigration = 0800; + LastSwiftMigration = 0910; ProvisioningStyle = Manual; }; 607FACE41AFB9204008FA782 = { CreatedOnToolsVersion = 6.3.1; - LastSwiftMigration = 0830; + LastSwiftMigration = 0910; ProvisioningStyle = Manual; TestTargetID = 607FACCF1AFB9204008FA782; }; @@ -656,7 +656,8 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = "Aztec Example Development"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -678,7 +679,8 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = "Aztec Example Ad Hoc"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; @@ -698,7 +700,8 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.wordpress.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AztecExample.app/AztecExample"; }; name = Debug; @@ -713,7 +716,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.wordpress.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AztecExample.app/AztecExample"; }; name = Release; @@ -850,7 +854,8 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = "Aztec Example Development"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Profiling; @@ -865,7 +870,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.wordpress.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AztecExample.app/AztecExample"; }; name = Profiling; @@ -942,7 +948,8 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = "Aztec Example Alpha Distribution"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = "Release-Alpha"; @@ -962,7 +969,8 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.wordpress.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AztecExample.app/AztecExample"; }; name = "Release-Alpha"; diff --git a/Example/Example/CommentAttachmentRenderer.swift b/Example/Example/CommentAttachmentRenderer.swift index 3edfe5e9b..32abd324a 100644 --- a/Example/Example/CommentAttachmentRenderer.swift +++ b/Example/Example/CommentAttachmentRenderer.swift @@ -74,9 +74,9 @@ private extension CommentAttachmentRenderer { } func messageAttributedString() -> NSAttributedString { - let attributes: [String: Any] = [ - NSForegroundColorAttributeName: textColor, - NSFontAttributeName: textFont + let attributes: [NSAttributedStringKey: Any] = [ + .foregroundColor: textColor, + .font: textFont ] return NSAttributedString(string: defaultText, attributes: attributes) diff --git a/Example/Example/EditorDemoController.swift b/Example/Example/EditorDemoController.swift index 53954e908..9466ea063 100644 --- a/Example/Example/EditorDemoController.swift +++ b/Example/Example/EditorDemoController.swift @@ -98,7 +98,8 @@ class EditorDemoController: UIViewController { let textField = UILabel() textField.attributedText = NSAttributedString(string: placeholderText, - attributes: [NSForegroundColorAttributeName: UIColor.lightGray, NSFontAttributeName: UIFont.preferredFont(forTextStyle: UIFontTextStyle.headline)]) + attributes: [.foregroundColor: UIColor.lightGray, + .font: UIFont.preferredFont(forTextStyle: UIFontTextStyle.headline)]) textField.sizeToFit() textField.translatesAutoresizingMaskIntoConstraints = false @@ -342,7 +343,7 @@ class EditorDemoController: UIViewController { // MARK: - Keyboard Handling - func keyboardWillShow(_ notification: Notification) { + @objc func keyboardWillShow(_ notification: Notification) { guard let userInfo = notification.userInfo as? [String: AnyObject], let keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue @@ -353,7 +354,7 @@ class EditorDemoController: UIViewController { refreshInsets(forKeyboardFrame: keyboardFrame) } - func keyboardWillHide(_ notification: Notification) { + @objc func keyboardWillHide(_ notification: Notification) { guard let userInfo = notification.userInfo as? [String: AnyObject], let keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue @@ -558,12 +559,12 @@ extension EditorDemoController { updateFormatBar() } - func toggleBold() { + @objc func toggleBold() { richTextView.toggleBold(range: richTextView.selectedRange) } - func toggleItalic() { + @objc func toggleItalic() { richTextView.toggleItalic(range: richTextView.selectedRange) } @@ -573,11 +574,11 @@ extension EditorDemoController { } - func toggleStrikethrough() { + @objc func toggleStrikethrough() { richTextView.toggleStrikethrough(range: richTextView.selectedRange) } - func toggleBlockquote() { + @objc func toggleBlockquote() { richTextView.toggleBlockquote(range: richTextView.selectedRange) } @@ -588,7 +589,7 @@ extension EditorDemoController { func toggleHeader(fromItem item: FormatBarItem) { let headerOptions = Constants.headers.map { headerType -> OptionsTableViewOption in let attributes = [ - NSFontAttributeName: UIFont.systemFont(ofSize: CGFloat(headerType.fontSize)) + .font: UIFont.systemFont(ofSize: CGFloat(headerType.fontSize)) ] let title = NSAttributedString(string: headerType.description, attributes: attributes) @@ -639,11 +640,11 @@ extension EditorDemoController { }) } - func toggleUnorderedList() { + @objc func toggleUnorderedList() { richTextView.toggleUnorderedList(range: richTextView.selectedRange) } - func toggleOrderedList() { + @objc func toggleOrderedList() { richTextView.toggleOrderedList(range: richTextView.selectedRange) } @@ -767,7 +768,7 @@ extension EditorDemoController { return nil } - func toggleLink() { + @objc func toggleLink() { var linkTitle = "" var linkURL: URL? = nil var linkRange = richTextView.selectedRange @@ -884,7 +885,7 @@ extension EditorDemoController { self.present(alertController, animated:true, completion:nil) } - func alertTextFieldDidChange(_ textField: UITextField) { + @objc func alertTextFieldDidChange(_ textField: UITextField) { guard let alertController = presentedViewController as? UIAlertController, let urlFieldText = alertController.textFields?.first?.text, @@ -897,7 +898,7 @@ extension EditorDemoController { } - func showImagePicker() { + @objc func showImagePicker() { let picker = UIImagePickerController() picker.sourceType = .photoLibrary picker.mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary) ?? [] @@ -1281,10 +1282,10 @@ private extension EditorDemoController let shadow = NSShadow() shadow.shadowOffset = CGSize(width: 1, height: 1) shadow.shadowColor = UIColor(white: 0, alpha: 0.6) - let attributes: [String:Any] = [NSFontAttributeName: UIFont.boldSystemFont(ofSize: 16), - NSParagraphStyleAttributeName: paragraphStyle, - NSForegroundColorAttributeName: UIColor.white, - NSShadowAttributeName: shadow] + let attributes: [NSAttributedStringKey: Any] = [.font: UIFont.boldSystemFont(ofSize: 16), + .paragraphStyle: paragraphStyle, + .foregroundColor: UIColor.white, + .shadow: shadow] return attributes } diff --git a/Example/Example/HTMLAttachmentRenderer.swift b/Example/Example/HTMLAttachmentRenderer.swift index 1caf62c4f..d55276d6d 100644 --- a/Example/Example/HTMLAttachmentRenderer.swift +++ b/Example/Example/HTMLAttachmentRenderer.swift @@ -74,9 +74,9 @@ private extension HTMLAttachmentRenderer { } func messageAttributedString(with attachment: NSTextAttachment) -> NSAttributedString { - let attributes: [String: Any] = [ - NSForegroundColorAttributeName: textColor, - NSFontAttributeName: textFont + let attributes: [NSAttributedStringKey: Any] = [ + .foregroundColor: textColor, + .font: textFont ] let htmlAttachment = attachment as? HTMLAttachment diff --git a/Example/Example/SpecialTagAttachmentRenderer.swift b/Example/Example/SpecialTagAttachmentRenderer.swift index 2d300dab9..4fc7e6820 100644 --- a/Example/Example/SpecialTagAttachmentRenderer.swift +++ b/Example/Example/SpecialTagAttachmentRenderer.swift @@ -36,7 +36,7 @@ extension SpecialTagAttachmentRenderer: TextViewAttachmentImageProvider { let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.baseWritingDirection = .leftToRight - let attributes: [String: Any] = [NSForegroundColorAttributeName: textColor, NSParagraphStyleAttributeName: paragraphStyle] + let attributes: [NSAttributedStringKey: Any] = [.foregroundColor: textColor, .paragraphStyle: paragraphStyle] let colorMessage = NSAttributedString(string: label, attributes: attributes) From 37e62a95912c2d61ac3d30691dc2eb8ed8eb0099 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 6 Nov 2017 15:02:34 -0300 Subject: [PATCH 02/20] Aztec is now Swift 4 Friendly. Mark II --- .../Extensions/String+RangeConversion.swift | 17 +++++++++++++---- Aztec/Classes/TextKit/TextView.swift | 10 ++++++++-- Example/Example/EditorDemoController.swift | 4 ++-- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Aztec/Classes/Extensions/String+RangeConversion.swift b/Aztec/Classes/Extensions/String+RangeConversion.swift index 243674f37..0e2bdf185 100644 --- a/Aztec/Classes/Extensions/String+RangeConversion.swift +++ b/Aztec/Classes/Extensions/String+RangeConversion.swift @@ -113,8 +113,11 @@ public extension String { /// func utf16NSRange(from range: Range) -> NSRange { - let lowerBound = range.lowerBound.samePosition(in: utf16) - let upperBound = range.upperBound.samePosition(in: utf16) + guard let lowerBound = range.lowerBound.samePosition(in: utf16), + let upperBound = range.upperBound.samePosition(in: utf16) else + { + return .zero + } let location = utf16.distance(from: utf16.startIndex, to: lowerBound) let length = utf16.distance(from: lowerBound, to: upperBound) @@ -150,7 +153,10 @@ public extension String { return nil } let afterIndex = index(after: currentIndex) - let after16 = afterIndex.samePosition(in: utf16) + guard let after16 = afterIndex.samePosition(in: utf16) else { + return nil + } + return utf16.distance(from: utf16.startIndex, to: after16) } @@ -160,7 +166,10 @@ public extension String { } let beforeIndex = index(before: currentIndex) - let before16 = beforeIndex.samePosition(in: utf16) + guard let before16 = beforeIndex.samePosition(in: utf16) else { + return nil + } + return utf16.distance(from: utf16.startIndex, to: before16) } diff --git a/Aztec/Classes/TextKit/TextView.swift b/Aztec/Classes/TextKit/TextView.swift index ba7757c2f..bfc801573 100644 --- a/Aztec/Classes/TextKit/TextView.swift +++ b/Aztec/Classes/TextKit/TextView.swift @@ -1686,8 +1686,14 @@ private extension TextView { TextListFormatter(style: .unordered) ] - for formatter in formatters where formatter.present(in: super.typingAttributes) { - super.typingAttributes = formatter.remove(from: super.typingAttributes) + for formatter in formatters { + let activeTypingAttributes = NSAttributedStringKey.convertFromRaw(attributes: super.typingAttributes) + guard formatter.present(in: activeTypingAttributes) else { + continue + } + + let updatedTypingAttributes = formatter.remove(from: activeTypingAttributes) + super.typingAttributes = NSAttributedStringKey.convertToRaw(attributes: updatedTypingAttributes) let applicationRange = formatter.applicationRange(for: selectedRange, in: textStorage) formatter.removeAttributes(from: textStorage, at: applicationRange) diff --git a/Example/Example/EditorDemoController.swift b/Example/Example/EditorDemoController.swift index 9466ea063..555536770 100644 --- a/Example/Example/EditorDemoController.swift +++ b/Example/Example/EditorDemoController.swift @@ -589,7 +589,7 @@ extension EditorDemoController { func toggleHeader(fromItem item: FormatBarItem) { let headerOptions = Constants.headers.map { headerType -> OptionsTableViewOption in let attributes = [ - .font: UIFont.systemFont(ofSize: CGFloat(headerType.fontSize)) + NSAttributedStringKey.font: UIFont.systemFont(ofSize: CGFloat(headerType.fontSize)) ] let title = NSAttributedString(string: headerType.description, attributes: attributes) @@ -1276,7 +1276,7 @@ private extension EditorDemoController richTextView.refresh(attachment) } - var mediaMessageAttributes: [String: Any] { + var mediaMessageAttributes: [NSAttributedStringKey: Any] { let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = .center let shadow = NSShadow() From b73664da742dfdc916f9646e121c2d68dc9de40c Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 6 Nov 2017 15:04:01 -0300 Subject: [PATCH 03/20] Disabling Swift3 ObjC Inference --- Aztec.xcodeproj/project.pbxproj | 8 ++++---- Example/AztecExample.xcodeproj/project.pbxproj | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Aztec.xcodeproj/project.pbxproj b/Aztec.xcodeproj/project.pbxproj index e004ccb1f..560ddb566 100644 --- a/Aztec.xcodeproj/project.pbxproj +++ b/Aztec.xcodeproj/project.pbxproj @@ -1267,7 +1267,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/Aztec/Modulemaps/libxml2"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 1; }; @@ -1296,7 +1296,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/Aztec/Modulemaps/libxml2"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 1; }; @@ -1466,7 +1466,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/Aztec/Modulemaps/libxml2"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 1; }; @@ -1575,7 +1575,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/Aztec/Modulemaps/libxml2"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 1; }; diff --git a/Example/AztecExample.xcodeproj/project.pbxproj b/Example/AztecExample.xcodeproj/project.pbxproj index 770c5d0d2..7c680f17e 100644 --- a/Example/AztecExample.xcodeproj/project.pbxproj +++ b/Example/AztecExample.xcodeproj/project.pbxproj @@ -656,7 +656,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = "Aztec Example Development"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -679,7 +679,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = "Aztec Example Ad Hoc"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -854,7 +854,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = "Aztec Example Development"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -948,7 +948,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = "Aztec Example Alpha Distribution"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; From 70b8314bcdda10adab01374ed4f5e48364b3dd1e Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 6 Nov 2017 15:08:02 -0300 Subject: [PATCH 04/20] Aztec is now Swift 4 Friendly. Mark III --- Aztec/Classes/TextKit/TextView.swift | 4 +++- .../NSAttributedStringListsTests.swift | 2 +- .../Formatters/BlockquoteFormatterTests.swift | 6 +++--- .../Formatters/FontFormatterTests.swift | 4 ++-- .../Formatters/HeaderFormatterTests.swift | 2 +- AztecTests/TextKit/TextViewTests.swift | 20 +++++++++---------- 6 files changed, 20 insertions(+), 18 deletions(-) diff --git a/Aztec/Classes/TextKit/TextView.swift b/Aztec/Classes/TextKit/TextView.swift index bfc801573..22e7b73f8 100644 --- a/Aztec/Classes/TextKit/TextView.swift +++ b/Aztec/Classes/TextKit/TextView.swift @@ -1679,9 +1679,11 @@ private extension TextView { /// is beyond the storage's contents, the typingAttributes will be modified. /// private func removeParagraphAttributes(at range: NSRange) { + let placeholderAttributes = NSAttributedStringKey.convertFromRaw(attributes: super.typingAttributes) + let formatters: [AttributeFormatter] = [ BlockquoteFormatter(), - PreFormatter(placeholderAttributes: typingAttributesSwifted), + PreFormatter(placeholderAttributes: placeholderAttributes), TextListFormatter(style: .ordered), TextListFormatter(style: .unordered) ] diff --git a/AztecTests/Extensions/NSAttributedStringListsTests.swift b/AztecTests/Extensions/NSAttributedStringListsTests.swift index a0e51c1b9..d26c56298 100644 --- a/AztecTests/Extensions/NSAttributedStringListsTests.swift +++ b/AztecTests/Extensions/NSAttributedStringListsTests.swift @@ -255,7 +255,7 @@ extension NSAttributedStringListsTests let range = (sample.string as NSString).range(of: sampleListContents) let listParagraphStyle = ParagraphStyle() listParagraphStyle.appendProperty(TextList(style: .ordered)) - let attributes = [.paragraphStyle: listParagraphStyle] + let attributes = [NSAttributedStringKey.paragraphStyle: listParagraphStyle] sample.addAttributes(attributes, range: range) return sample diff --git a/AztecTests/Formatters/BlockquoteFormatterTests.swift b/AztecTests/Formatters/BlockquoteFormatterTests.swift index be74c1a5a..6c257fdd0 100644 --- a/AztecTests/Formatters/BlockquoteFormatterTests.swift +++ b/AztecTests/Formatters/BlockquoteFormatterTests.swift @@ -22,7 +22,7 @@ class BlockquoteFormatterTests: XCTestCase { let paragraphs = paragraphRanges(inString: storage) let formatter = BlockquoteFormatter() - var attributes = [String:Any]() + var attributes = [NSAttributedStringKey: Any]() attributes = formatter.apply(to: attributes) textView.storage.setAttributes(attributes, range: paragraphs[0]) formatter.toggle(in: storage, at: NSRange(location: 1, length: 1)) @@ -36,7 +36,7 @@ class BlockquoteFormatterTests: XCTestCase { let paragraphs = paragraphRanges(inString: storage) let formatter = BlockquoteFormatter() - var attributes = [String:Any]() + var attributes = [NSAttributedStringKey: Any]() attributes = formatter.apply(to: attributes) textView.storage.setAttributes(attributes, range: paragraphs[1]) formatter.toggle(in: storage, at: NSUnionRange(paragraphs[0], paragraphs[1])) @@ -51,7 +51,7 @@ class BlockquoteFormatterTests: XCTestCase { let paragraphs = paragraphRanges(inString: storage) let formatter = BlockquoteFormatter() - var attributes = [String:Any]() + var attributes = [NSAttributedStringKey: Any]() attributes = formatter.apply(to: attributes) textView.storage.setAttributes(attributes, range: paragraphs[0]) formatter.toggle(in: storage, at: NSUnionRange(paragraphs[0], paragraphs[1])) diff --git a/AztecTests/Formatters/FontFormatterTests.swift b/AztecTests/Formatters/FontFormatterTests.swift index d812739d9..1e48ee681 100644 --- a/AztecTests/Formatters/FontFormatterTests.swift +++ b/AztecTests/Formatters/FontFormatterTests.swift @@ -10,7 +10,7 @@ class FontFormatterTests: XCTestCase let italicFormatter = ItalicFormatter() func testApplyAttribute() { - var attributes: [NSAttributedStringKey : Any] = [.font.rawValue: UIFont.systemFont(ofSize: UIFont.systemFontSize)] + var attributes: [NSAttributedStringKey : Any] = [.font: UIFont.systemFont(ofSize: UIFont.systemFontSize)] var font: UIFont? //test adding a non-existent testApplyAttribute attributes = boldFormatter.apply(to: attributes) @@ -29,7 +29,7 @@ class FontFormatterTests: XCTestCase } func testRemoveAttributes() { - var attributes: [NSAttributedStringKey : Any] = [.font.rawValue: UIFont.boldSystemFont(ofSize: UIFont.systemFontSize)] + var attributes: [NSAttributedStringKey : Any] = [.font: UIFont.boldSystemFont(ofSize: UIFont.systemFontSize)] var font: UIFont? //test removing a existent attribute diff --git a/AztecTests/Formatters/HeaderFormatterTests.swift b/AztecTests/Formatters/HeaderFormatterTests.swift index aa08a6076..b78eda259 100644 --- a/AztecTests/Formatters/HeaderFormatterTests.swift +++ b/AztecTests/Formatters/HeaderFormatterTests.swift @@ -12,7 +12,7 @@ class HeaderFormatterTests: XCTestCase { /// Sample Attributes /// - private lazy var attributes: [String: Any] = { + private lazy var attributes: [NSAttributedStringKey: Any] = { return [.font: UIFont.systemFont(ofSize: self.defaultFontSize)] }() diff --git a/AztecTests/TextKit/TextViewTests.swift b/AztecTests/TextKit/TextViewTests.swift index e89ff0ac0..73f98e880 100644 --- a/AztecTests/TextKit/TextViewTests.swift +++ b/AztecTests/TextKit/TextViewTests.swift @@ -816,7 +816,7 @@ class TextViewTests: XCTestCase { textView.selectedRange = textView.text.endOfStringNSRange() textView.deleteBackward() - XCTAssertFalse(TextListFormatter.listsOfAnyKindPresent(in: textView.typingAttributes)) + XCTAssertFalse(TextListFormatter.listsOfAnyKindPresent(in: textView.typingAttributesSwifted)) XCTAssert(textView.storage.length == 0) } @@ -896,7 +896,7 @@ class TextViewTests: XCTestCase { textView.toggleOrderedList(range: .zero) textView.selectedTextRange = textView.textRange(from: textView.endOfDocument, to: textView.endOfDocument) - XCTAssertFalse(TextListFormatter.listsOfAnyKindPresent(in: textView.typingAttributes)) + XCTAssertFalse(TextListFormatter.listsOfAnyKindPresent(in: textView.typingAttributesSwifted)) } /// Verifies that a Text List gets removed, whenever the user types `\n` in an empty line. @@ -920,7 +920,7 @@ class TextViewTests: XCTestCase { XCTAssertFalse(formatter.present(in: attributedText, at: location)) } - XCTAssertFalse(TextListFormatter.listsOfAnyKindPresent(in: textView.typingAttributes)) + XCTAssertFalse(TextListFormatter.listsOfAnyKindPresent(in: textView.typingAttributesSwifted)) } /// Verifies that toggling an Unordered List, when editing an empty document, inserts a Newline. @@ -1016,7 +1016,7 @@ class TextViewTests: XCTestCase { textView.toggleUnorderedList(range: textView.selectedRange) textView.deleteBackward() - XCTAssertFalse(TextListFormatter.listsOfAnyKindPresent(in: textView.typingAttributes)) + XCTAssertFalse(TextListFormatter.listsOfAnyKindPresent(in: textView.typingAttributesSwifted)) } /// When the caret is positioned at both EoF and EoL, inserting a line separator (in most @@ -1081,7 +1081,7 @@ class TextViewTests: XCTestCase { let formatter = BlockquoteFormatter() - XCTAssertFalse(formatter.present(in: textView.typingAttributes)) + XCTAssertFalse(formatter.present(in: textView.typingAttributesSwifted)) XCTAssert(textView.storage.length == 0) } @@ -1157,7 +1157,7 @@ class TextViewTests: XCTestCase { textView.toggleBlockquote(range: .zero) textView.selectedTextRange = textView.textRange(from: textView.endOfDocument, to: textView.endOfDocument) - XCTAssertFalse(BlockquoteFormatter().present(in: textView.typingAttributes)) + XCTAssertFalse(BlockquoteFormatter().present(in: textView.typingAttributesSwifted)) } /// Verifies that Blockquotes get removed whenever the user types `\n` in an empty line. @@ -1181,7 +1181,7 @@ class TextViewTests: XCTestCase { XCTAssertFalse(formatter.present(in: attributedText, at: location)) } - XCTAssertFalse(formatter.present(in: textView.typingAttributes)) + XCTAssertFalse(formatter.present(in: textView.typingAttributesSwifted)) } /// Verifies that toggling a Blockquote, when editing an empty document, inserts a Newline. @@ -1267,7 +1267,7 @@ class TextViewTests: XCTestCase { let formatter = PreFormatter() - XCTAssertFalse(formatter.present(in: textView.typingAttributes)) + XCTAssertFalse(formatter.present(in: textView.typingAttributesSwifted)) XCTAssert(textView.storage.length == 0) } @@ -1343,7 +1343,7 @@ class TextViewTests: XCTestCase { textView.togglePre(range: .zero) textView.selectedTextRange = textView.textRange(from: textView.endOfDocument, to: textView.endOfDocument) - XCTAssertFalse(PreFormatter().present(in: textView.typingAttributes)) + XCTAssertFalse(PreFormatter().present(in: textView.typingAttributesSwifted)) } /// Verifies that Pre get removed whenever the user types `\n` in an empty line. @@ -1367,7 +1367,7 @@ class TextViewTests: XCTestCase { XCTAssertFalse(formatter.present(in: attributedText, at: location)) } - XCTAssertFalse(formatter.present(in: textView.typingAttributes)) + XCTAssertFalse(formatter.present(in: textView.typingAttributesSwifted)) } /// Verifies that toggling a Pre, when editing an empty document, inserts a Newline. From 5964f32f17e9a7b1a165d269c6746f4ff4d60509 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 6 Nov 2017 15:10:44 -0300 Subject: [PATCH 05/20] EditorDemoController: Fixing Font Weight --- Example/Example/EditorDemoController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Example/Example/EditorDemoController.swift b/Example/Example/EditorDemoController.swift index 136bdf7b1..871db39cf 100644 --- a/Example/Example/EditorDemoController.swift +++ b/Example/Example/EditorDemoController.swift @@ -1284,7 +1284,7 @@ private extension EditorDemoController let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = .center - let attributes: [NSAttributedStringKey: Any] = [.font: UIFont.systemFont(ofSize: 15, weight: UIFontWeightSemibold), + let attributes: [NSAttributedStringKey: Any] = [.font: UIFont.systemFont(ofSize: 15, weight: .semibold), .paragraphStyle: paragraphStyle, .foregroundColor: UIColor.white] return attributes From 3707f9f1bf5398a90c109ccd0ae1c2ec02b6aa05 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 6 Nov 2017 15:37:09 -0300 Subject: [PATCH 06/20] TextView: @diegoreymendez is a genius --- Aztec/Classes/TextKit/TextView.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Aztec/Classes/TextKit/TextView.swift b/Aztec/Classes/TextKit/TextView.swift index 22e7b73f8..9a6098ca5 100644 --- a/Aztec/Classes/TextKit/TextView.swift +++ b/Aztec/Classes/TextKit/TextView.swift @@ -1679,11 +1679,9 @@ private extension TextView { /// is beyond the storage's contents, the typingAttributes will be modified. /// private func removeParagraphAttributes(at range: NSRange) { - let placeholderAttributes = NSAttributedStringKey.convertFromRaw(attributes: super.typingAttributes) - let formatters: [AttributeFormatter] = [ BlockquoteFormatter(), - PreFormatter(placeholderAttributes: placeholderAttributes), + PreFormatter(placeholderAttributes: defaultAttributes), TextListFormatter(style: .ordered), TextListFormatter(style: .unordered) ] From 4971cc78f748fe93a86ffe14f72688bea5f32278 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 6 Nov 2017 15:37:58 -0300 Subject: [PATCH 07/20] Disabling Swift3 ObjC Inference / Testing Target --- Aztec.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Aztec.xcodeproj/project.pbxproj b/Aztec.xcodeproj/project.pbxproj index b9a228a02..8fdae46b3 100644 --- a/Aztec.xcodeproj/project.pbxproj +++ b/Aztec.xcodeproj/project.pbxproj @@ -1321,7 +1321,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.wordpress.AztecTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.0; }; name = Debug; @@ -1340,7 +1340,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.wordpress.AztecTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.0; }; name = Release; @@ -1490,7 +1490,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.wordpress.AztecTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.0; }; name = Profiling; @@ -1600,7 +1600,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.wordpress.AztecTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.0; }; name = "Release-Alpha"; From f418fd08f7e55b61bc00ca6d7eb70749e99d30bc Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 6 Nov 2017 15:39:55 -0300 Subject: [PATCH 08/20] Disabling Swift3 ObjC Inference / Example Target --- Example/AztecExample.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Example/AztecExample.xcodeproj/project.pbxproj b/Example/AztecExample.xcodeproj/project.pbxproj index 7c680f17e..81d308e02 100644 --- a/Example/AztecExample.xcodeproj/project.pbxproj +++ b/Example/AztecExample.xcodeproj/project.pbxproj @@ -700,7 +700,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.wordpress.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AztecExample.app/AztecExample"; }; @@ -716,7 +716,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.wordpress.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AztecExample.app/AztecExample"; }; @@ -870,7 +870,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.wordpress.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AztecExample.app/AztecExample"; }; @@ -969,7 +969,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.wordpress.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AztecExample.app/AztecExample"; }; From 523ba08d8a04f1d4cd9b24d564842adaac2e1343 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 6 Nov 2017 17:18:24 -0300 Subject: [PATCH 09/20] Swift 4: replacing substring(to:) with prefix(upTo:) --- Aztec/Classes/Libxml2/Converters/In/CSSParser.swift | 2 +- AztecTests/StringRangeConversionTests.swift | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Aztec/Classes/Libxml2/Converters/In/CSSParser.swift b/Aztec/Classes/Libxml2/Converters/In/CSSParser.swift index 60556a666..8e92668cd 100644 --- a/Aztec/Classes/Libxml2/Converters/In/CSSParser.swift +++ b/Aztec/Classes/Libxml2/Converters/In/CSSParser.swift @@ -59,7 +59,7 @@ class CSSParser { return CSSAttribute(name: cssAttribute) } - let name = cssAttribute.substring(to: keyValueSeparatorRange.lowerBound) + let name = cssAttribute.prefix(upTo: keyValueSeparatorRange.lowerBound) .trimmingCharacters(in: .whitespacesAndNewlines) guard keyValueSeparatorRange.upperBound != cssAttribute.endIndex else { diff --git a/AztecTests/StringRangeConversionTests.swift b/AztecTests/StringRangeConversionTests.swift index 615481d6e..baf3c6897 100644 --- a/AztecTests/StringRangeConversionTests.swift +++ b/AztecTests/StringRangeConversionTests.swift @@ -75,7 +75,7 @@ class StringRangeConversionTests: XCTestCase { let nsRange = nsString.range(of: wordToCapture) let index = string.indexFromLocation(nsRange.location)! - let wordCaptured = string.substring(to: index) + let wordCaptured = string.prefix(upTo: index) XCTAssertEqual("Hello ", wordCaptured) } @@ -88,7 +88,7 @@ class StringRangeConversionTests: XCTestCase { let nsRange = nsString.range(of: wordToCapture) let index = string.indexFromLocation(nsRange.location)! - let wordCaptured = string.substring(to: index) + let wordCaptured = string.prefix(upTo: index) XCTAssertEqual("Hello ", wordCaptured) } @@ -101,7 +101,7 @@ class StringRangeConversionTests: XCTestCase { let nsRange = nsString.range(of: wordToCapture) let index = string.indexFromLocation(nsRange.location)! - let wordCaptured = string.substring(to: index) + let wordCaptured = string.prefix(upTo: index) XCTAssertEqual("Hello ", wordCaptured) } @@ -114,7 +114,7 @@ class StringRangeConversionTests: XCTestCase { let nsRange = nsString.range(of: wordToCapture) let index = string.indexFromLocation(nsRange.location)! - let wordCaptured = string.substring(to: index) + let wordCaptured = string.prefix(upTo: index) XCTAssertEqual("Hello 🇮🇳 ", wordCaptured) } @@ -127,7 +127,7 @@ class StringRangeConversionTests: XCTestCase { let nsRange = nsString.range(of: wordToCapture) let location = string.location(before: nsRange.location)! let index = string.indexFromLocation(location)! - let wordCaptured = string.substring(to: index) + let wordCaptured = string.prefix(upTo: index) XCTAssertEqual("Hello", wordCaptured) } @@ -140,7 +140,7 @@ class StringRangeConversionTests: XCTestCase { let nsRange = nsString.range(of: wordToCapture) let location = string.location(before: nsRange.endLocation)! let index = string.indexFromLocation(location)! - let wordCaptured = string.substring(to: index) + let wordCaptured = string.prefix(upTo: index) XCTAssertEqual("Hello ", wordCaptured) } From c1dc7d26cb05a74e12882ed4431f33099c84499a Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 6 Nov 2017 17:27:21 -0300 Subject: [PATCH 10/20] Swift 4: replacing .substring(with:) with subscript operators --- Aztec/Classes/Extensions/NSTextingResult+Helpers.swift | 2 +- Aztec/Classes/Extensions/String+EndOfLine.swift | 9 ++++++++- Aztec/Classes/Extensions/String+Paragraph.swift | 3 ++- AztecTests/StringRangeConversionTests.swift | 8 ++++---- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Aztec/Classes/Extensions/NSTextingResult+Helpers.swift b/Aztec/Classes/Extensions/NSTextingResult+Helpers.swift index 425268b4e..6d665136d 100644 --- a/Aztec/Classes/Extensions/NSTextingResult+Helpers.swift +++ b/Aztec/Classes/Extensions/NSTextingResult+Helpers.swift @@ -21,7 +21,7 @@ public extension NSTextCheckingResult { } let range = text.range(from: nsrange) - let captureGroup = text.substring(with: range) + let captureGroup = String(text[range]) return captureGroup } } diff --git a/Aztec/Classes/Extensions/String+EndOfLine.swift b/Aztec/Classes/Extensions/String+EndOfLine.swift index 6dfeaae32..a197ea823 100644 --- a/Aztec/Classes/Extensions/String+EndOfLine.swift +++ b/Aztec/Classes/Extensions/String+EndOfLine.swift @@ -68,7 +68,14 @@ extension String { } func isEndOfLine(at index: String.Index) -> Bool { - return index == endIndex || substring(with: index ..< self.index(after: index)).isEndOfLine() + guard index != endIndex else { + return true + } + + let range = index ..< self.index(after: index) + let slice = String(self[range]) + + return slice.isEndOfLine() } func isEndOfLine(atUTF16Offset utf16Offset: Int) -> Bool { diff --git a/Aztec/Classes/Extensions/String+Paragraph.swift b/Aztec/Classes/Extensions/String+Paragraph.swift index 64bb0370a..ac2969cfe 100644 --- a/Aztec/Classes/Extensions/String+Paragraph.swift +++ b/Aztec/Classes/Extensions/String+Paragraph.swift @@ -31,7 +31,8 @@ extension String { return true } - let endingString = substring(with: index ..< self.index(after: index)) + let endingRange = index ..< self.index(after: index) + let endingString = String(self[endingRange]) let paragraphSeparators = [String(.carriageReturn), String(.lineFeed), String(.paragraphSeparator)] return paragraphSeparators.contains(endingString) diff --git a/AztecTests/StringRangeConversionTests.swift b/AztecTests/StringRangeConversionTests.swift index baf3c6897..36350c18c 100644 --- a/AztecTests/StringRangeConversionTests.swift +++ b/AztecTests/StringRangeConversionTests.swift @@ -22,7 +22,7 @@ class StringRangeConversionTests: XCTestCase { let nsRange = nsString.range(of: wordToCapture) let range = string.range(from: nsRange) - let wordCaptured = string.substring(with: range) + let wordCaptured = String(string[range]) XCTAssertEqual(wordToCapture, wordCaptured) } @@ -35,7 +35,7 @@ class StringRangeConversionTests: XCTestCase { let nsRange = string.nsRange(fromUTF16NSRange: utf16NSRange)! let range = string.range(from: nsRange) - let wordCaptured = string.substring(with: range) + let wordCaptured = String(string[range]) XCTAssertEqual(wordToCapture, wordCaptured) } @@ -48,7 +48,7 @@ class StringRangeConversionTests: XCTestCase { let nsRange = string.nsRange(fromUTF16NSRange: utf16NSRange)! let range = string.range(from: nsRange) - let wordCaptured = string.substring(with: range) + let wordCaptured = String(string[range]) XCTAssertEqual(wordToCapture, wordCaptured) } @@ -61,7 +61,7 @@ class StringRangeConversionTests: XCTestCase { let nsRange = string.nsRange(fromUTF16NSRange: utf16NSRange)! let range = string.range(from: nsRange) - let wordCaptured = string.substring(with: range) + let wordCaptured = String(string[range]) XCTAssertEqual(wordToCapture, wordCaptured) } From cca5084b8c5d18c0d4e91658454f4b8fd7532ff1 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 6 Nov 2017 17:29:52 -0300 Subject: [PATCH 11/20] Swift 4: replacing substring(from:) with subscript operators --- Aztec/Classes/Libxml2/Converters/In/CSSParser.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Aztec/Classes/Libxml2/Converters/In/CSSParser.swift b/Aztec/Classes/Libxml2/Converters/In/CSSParser.swift index 8e92668cd..ad3d00018 100644 --- a/Aztec/Classes/Libxml2/Converters/In/CSSParser.swift +++ b/Aztec/Classes/Libxml2/Converters/In/CSSParser.swift @@ -66,7 +66,7 @@ class CSSParser { return CSSAttribute(name: name) } - let value = cssAttribute.substring(from: keyValueSeparatorRange.upperBound) + let value = cssAttribute[keyValueSeparatorRange.upperBound...] .trimmingCharacters(in: .whitespacesAndNewlines) return CSSAttribute(name: name, value: value) From e0cb3930d0de9dd439d1ee9dadd5ab2f75ef687e Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 6 Nov 2017 17:57:47 -0300 Subject: [PATCH 12/20] Implements NSAttributedStringKey+Aztec --- Aztec.xcodeproj/project.pbxproj | 4 ++ .../NSAttributedStringKey+Aztec.swift | 48 +++++++++++++++++++ .../Extensions/UIPasteboard+Helpers.swift | 6 +-- .../Implementations/BoldFormatter.swift | 4 +- .../Implementations/ColorFormatter.swift | 3 +- .../Implementations/HRFormatter.swift | 4 +- .../Implementations/ImageFormatter.swift | 3 +- .../Implementations/ItalicFormatter.swift | 3 +- .../Implementations/LinkFormatter.swift | 3 +- .../StrikethroughFormatter.swift | 3 +- .../Implementations/UnderlineFormatter.swift | 3 +- .../Implementations/VideoFormatter.swift | 3 +- .../Attributes/UnsupportedHTML.swift | 5 -- .../Conversions/AttributedStringParser.swift | 18 +++---- .../AttributedStringSerializer.swift | 6 +-- .../AttributedStringParserTests.swift | 2 +- .../AttributedStringSerializerTests.swift | 2 +- 17 files changed, 79 insertions(+), 41 deletions(-) create mode 100644 Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift diff --git a/Aztec.xcodeproj/project.pbxproj b/Aztec.xcodeproj/project.pbxproj index 8fdae46b3..7c990ea8f 100644 --- a/Aztec.xcodeproj/project.pbxproj +++ b/Aztec.xcodeproj/project.pbxproj @@ -42,6 +42,7 @@ B551A4A01E770B3800EE3A7F /* UIFont+Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = B551A49F1E770B3800EE3A7F /* UIFont+Emoji.swift */; }; B572AC281E817CFE008948C2 /* CommentAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = B572AC271E817CFE008948C2 /* CommentAttachment.swift */; }; B574F4A41FB0CF3B0048F355 /* NSAttributedStringKey+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B574F4A31FB0CF3A0048F355 /* NSAttributedStringKey+Conversion.swift */; }; + B574F4AD1FB103430048F355 /* NSAttributedStringKey+Aztec.swift in Sources */ = {isa = PBXBuildFile; fileRef = B574F4AC1FB103430048F355 /* NSAttributedStringKey+Aztec.swift */; }; B57534501F267D0B009D4904 /* Array+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B575344F1F267D0B009D4904 /* Array+Helpers.swift */; }; B57534521F267D63009D4904 /* ArrayHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57534511F267D63009D4904 /* ArrayHelperTests.swift */; }; B57D1C3D1E92C38000EA4B16 /* HTMLAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D1C3C1E92C38000EA4B16 /* HTMLAttachment.swift */; }; @@ -221,6 +222,7 @@ B551A49F1E770B3800EE3A7F /* UIFont+Emoji.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIFont+Emoji.swift"; sourceTree = ""; }; B572AC271E817CFE008948C2 /* CommentAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommentAttachment.swift; sourceTree = ""; }; B574F4A31FB0CF3A0048F355 /* NSAttributedStringKey+Conversion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedStringKey+Conversion.swift"; sourceTree = ""; }; + B574F4AC1FB103430048F355 /* NSAttributedStringKey+Aztec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAttributedStringKey+Aztec.swift"; sourceTree = ""; }; B575344F1F267D0B009D4904 /* Array+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+Helpers.swift"; sourceTree = ""; }; B57534511F267D63009D4904 /* ArrayHelperTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ArrayHelperTests.swift; path = Extensions/ArrayHelperTests.swift; sourceTree = ""; }; B57D1C3C1E92C38000EA4B16 /* HTMLAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTMLAttachment.swift; sourceTree = ""; }; @@ -486,6 +488,7 @@ children = ( 599F25201D8BC9A1002871D6 /* HTMLConstants.swift */, 599F25211D8BC9A1002871D6 /* Metrics.swift */, + B574F4AC1FB103430048F355 /* NSAttributedStringKey+Aztec.swift */, ); path = Constants; sourceTree = ""; @@ -998,6 +1001,7 @@ B5C99D3F1E72E2E700335355 /* UIStackView+Helpers.swift in Sources */, F1C05B991E37F99D007510EA /* Character+Name.swift in Sources */, FF20D6421EDC389A00294B78 /* Processor.swift in Sources */, + B574F4AD1FB103430048F355 /* NSAttributedStringKey+Aztec.swift in Sources */, 599F253B1D8BC9A1002871D6 /* InNodesConverter.swift in Sources */, F18B81EB1EA5601000885F43 /* StringUnicodeScalarView+RangeConversion.swift in Sources */, F127F7141F0591AD008A00D7 /* CSSAttribute.swift in Sources */, diff --git a/Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift b/Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift new file mode 100644 index 000000000..0dc508ca8 --- /dev/null +++ b/Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift @@ -0,0 +1,48 @@ +import Foundation + + +// MARK: - Aztec NSAttributedString Keys +// +public extension NSAttributedStringKey { + + /// Key used to store Bold Tag Metadata, by our BoldFormatter. + /// + public static let boldHtmlRepresentation = NSAttributedStringKey("Bold.htmlRepresentation") + + /// Key used to store Color Tags Metadata, by our ColorFormatter. + /// + public static let colorHtmlRepresentation = NSAttributedStringKey("Color.htmlRepresentation") + + /// Key used to store HR Tag Metadata, by our HRFormatter. + /// + public static let hrHtmlRepresentation = NSAttributedStringKey("HR.htmlRepresentation") + + /// Key used to store Image Tag Metadata, by our ImageFormatter. + /// + public static let imageHtmlRepresentation = NSAttributedStringKey("Image.htmlRepresentation") + + /// Key used to store Italics Tag Metadata, by our ItalicFormatter. + /// + public static let italicHtmlRepresentation = NSAttributedStringKey("Italic.htmlRepresentation") + + /// Key used to store Link Tag Metadata, by our LinkFormatter. + /// + public static let linkHtmlRepresentation = NSAttributedStringKey("Link.htmlRepresentation") + + /// Key used to store Strike Tag Metadata, by our StrikeFormatter. + /// + public static let strikeHtmlRepresentation = NSAttributedStringKey("Strike.htmlRepresentation") + + /// Key used to store UnderlineHTMLRepresentations, by our UnderlineFormatter. + /// + public static let underlineHtmlRepresentation = NSAttributedStringKey("Underline.htmlRepresentation") + + /// Key used to store UnsupportedHTML Snippets, by our HTML Parser. + /// + public static let unsupportedHtml = NSAttributedStringKey("UnsupportedHTMLAttributeName") + + /// Key used to store VideoHTMLRepresentations, by our VideoFormatter. + /// + public static let videoHtmlRepresentation = NSAttributedStringKey("Video.htmlRepresentation") +} + diff --git a/Aztec/Classes/Extensions/UIPasteboard+Helpers.swift b/Aztec/Classes/Extensions/UIPasteboard+Helpers.swift index b58dad82c..7805dd1a0 100644 --- a/Aztec/Classes/Extensions/UIPasteboard+Helpers.swift +++ b/Aztec/Classes/Extensions/UIPasteboard+Helpers.swift @@ -75,9 +75,9 @@ private extension UIPasteboard { /// String Initialization Options /// private struct StringOptions { - static let RTFText = [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.rtf] - static let RTFDText = [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.rtfd] - static let plainText = [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.plain] + static let RTFText: [NSAttributedString.DocumentReadingOptionKey: NSAttributedString.DocumentType] = [.documentType: .rtf] + static let RTFDText: [NSAttributedString.DocumentReadingOptionKey: NSAttributedString.DocumentType] = [.documentType: .rtfd] + static let plainText: [NSAttributedString.DocumentReadingOptionKey: NSAttributedString.DocumentType] = [.documentType: .plain] } /// Attempts to unarchive a Pasteboard's Entry into a NSAttributedString Instance. diff --git a/Aztec/Classes/Formatters/Implementations/BoldFormatter.swift b/Aztec/Classes/Formatters/Implementations/BoldFormatter.swift index 896f8b1ef..78214a8d7 100644 --- a/Aztec/Classes/Formatters/Implementations/BoldFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/BoldFormatter.swift @@ -1,9 +1,7 @@ import UIKit class BoldFormatter: FontFormatter { - static let htmlRepresentationKey = NSAttributedStringKey("Bold.htmlRepresentation") - init() { - super.init(traits: .traitBold, htmlRepresentationKey: BoldFormatter.htmlRepresentationKey) + super.init(traits: .traitBold, htmlRepresentationKey: .boldHtmlRepresentation) } } diff --git a/Aztec/Classes/Formatters/Implementations/ColorFormatter.swift b/Aztec/Classes/Formatters/Implementations/ColorFormatter.swift index 2a81be9c5..9216f162b 100644 --- a/Aztec/Classes/Formatters/Implementations/ColorFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/ColorFormatter.swift @@ -1,11 +1,10 @@ import UIKit class ColorFormatter: StandardAttributeFormatter { - static let htmlRepresentationKey = NSAttributedStringKey("Color.htmlRepresentation") init(color: UIColor = .black) { super.init(attributeKey: .foregroundColor, attributeValue: color, - htmlRepresentationKey: ColorFormatter.htmlRepresentationKey) + htmlRepresentationKey: .colorHtmlRepresentation) } } diff --git a/Aztec/Classes/Formatters/Implementations/HRFormatter.swift b/Aztec/Classes/Formatters/Implementations/HRFormatter.swift index 5b147474b..660211fb4 100644 --- a/Aztec/Classes/Formatters/Implementations/HRFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/HRFormatter.swift @@ -1,11 +1,11 @@ import UIKit + class HRFormatter: StandardAttributeFormatter { - static let htmlRepresentationKey = NSAttributedStringKey("HR.htmlRepresentation") init() { super.init(attributeKey: .attachment, attributeValue: LineAttachment(), - htmlRepresentationKey: HRFormatter.htmlRepresentationKey) + htmlRepresentationKey: .hrHtmlRepresentation) } } diff --git a/Aztec/Classes/Formatters/Implementations/ImageFormatter.swift b/Aztec/Classes/Formatters/Implementations/ImageFormatter.swift index a0ce535d0..0db7c6b3b 100644 --- a/Aztec/Classes/Formatters/Implementations/ImageFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/ImageFormatter.swift @@ -1,13 +1,12 @@ import UIKit class ImageFormatter: StandardAttributeFormatter { - static let htmlRepresentationKey = NSAttributedStringKey("Image.htmlRepresentation") init() { super.init( attributeKey: .attachment, attributeValue: ImageAttachment(identifier: NSUUID().uuidString), - htmlRepresentationKey: ImageFormatter.htmlRepresentationKey) + htmlRepresentationKey: .imageHtmlRepresentation) } override func apply(to attributes: [NSAttributedStringKey: Any], andStore representation: HTMLRepresentation?) -> [NSAttributedStringKey: Any] { diff --git a/Aztec/Classes/Formatters/Implementations/ItalicFormatter.swift b/Aztec/Classes/Formatters/Implementations/ItalicFormatter.swift index 464321f06..ea886ea37 100644 --- a/Aztec/Classes/Formatters/Implementations/ItalicFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/ItalicFormatter.swift @@ -1,9 +1,8 @@ import UIKit class ItalicFormatter: FontFormatter { - static let htmlRepresentationKey = NSAttributedStringKey("Italic.htmlRepresentation") init() { - super.init(traits: .traitItalic, htmlRepresentationKey: ItalicFormatter.htmlRepresentationKey) + super.init(traits: .traitItalic, htmlRepresentationKey: .italicHtmlRepresentation) } } diff --git a/Aztec/Classes/Formatters/Implementations/LinkFormatter.swift b/Aztec/Classes/Formatters/Implementations/LinkFormatter.swift index 82d5780b7..1a9469b3b 100644 --- a/Aztec/Classes/Formatters/Implementations/LinkFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/LinkFormatter.swift @@ -1,12 +1,11 @@ import UIKit class LinkFormatter: StandardAttributeFormatter { - static let htmlRepresentationKey = NSAttributedStringKey("Link.htmlRepresentation") init() { super.init(attributeKey: .link, attributeValue: NSURL(string:"")!, - htmlRepresentationKey: LinkFormatter.htmlRepresentationKey) + htmlRepresentationKey: .linkHtmlRepresentation) } override func apply(to attributes: [NSAttributedStringKey: Any], andStore representation: HTMLRepresentation?) -> [NSAttributedStringKey: Any] { diff --git a/Aztec/Classes/Formatters/Implementations/StrikethroughFormatter.swift b/Aztec/Classes/Formatters/Implementations/StrikethroughFormatter.swift index 402cf0780..855106790 100644 --- a/Aztec/Classes/Formatters/Implementations/StrikethroughFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/StrikethroughFormatter.swift @@ -1,11 +1,10 @@ import UIKit class StrikethroughFormatter: StandardAttributeFormatter { - static let htmlRepresentationKey = NSAttributedStringKey("Strike.htmlRepresentation") init() { super.init(attributeKey: .strikethroughStyle, attributeValue: NSUnderlineStyle.styleSingle.rawValue, - htmlRepresentationKey: StrikethroughFormatter.htmlRepresentationKey) + htmlRepresentationKey: .strikeHtmlRepresentation) } } diff --git a/Aztec/Classes/Formatters/Implementations/UnderlineFormatter.swift b/Aztec/Classes/Formatters/Implementations/UnderlineFormatter.swift index 99078fd2d..10dd3a27a 100644 --- a/Aztec/Classes/Formatters/Implementations/UnderlineFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/UnderlineFormatter.swift @@ -1,11 +1,10 @@ import UIKit class UnderlineFormatter: StandardAttributeFormatter { - static let htmlRepresentationKey = NSAttributedStringKey("Underline.htmlRepresentation") init() { super.init(attributeKey: .underlineStyle, attributeValue: NSUnderlineStyle.styleSingle.rawValue, - htmlRepresentationKey: UnderlineFormatter.htmlRepresentationKey) + htmlRepresentationKey: .underlineHtmlRepresentation) } } diff --git a/Aztec/Classes/Formatters/Implementations/VideoFormatter.swift b/Aztec/Classes/Formatters/Implementations/VideoFormatter.swift index e9428c63f..6c79f376d 100644 --- a/Aztec/Classes/Formatters/Implementations/VideoFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/VideoFormatter.swift @@ -1,12 +1,11 @@ import UIKit class VideoFormatter: StandardAttributeFormatter { - static let htmlRepresentationKey = NSAttributedStringKey("Video.htmlRepresentation") init() { super.init(attributeKey: .attachment, attributeValue: VideoAttachment(identifier: NSUUID().uuidString), - htmlRepresentationKey: VideoFormatter.htmlRepresentationKey) + htmlRepresentationKey: .videoHtmlRepresentation) } override func apply(to attributes: [NSAttributedStringKey: Any], andStore representation: HTMLRepresentation?) -> [NSAttributedStringKey: Any] { diff --git a/Aztec/Classes/NSAttributedString/Attributes/UnsupportedHTML.swift b/Aztec/Classes/NSAttributedString/Attributes/UnsupportedHTML.swift index a22d6e0ee..946b0a2e2 100644 --- a/Aztec/Classes/NSAttributedString/Attributes/UnsupportedHTML.swift +++ b/Aztec/Classes/NSAttributedString/Attributes/UnsupportedHTML.swift @@ -1,11 +1,6 @@ import Foundation -// MARK: - UnsupportedHTML NSAttributedString Attribute Name -// -let UnsupportedHTMLAttributeName = NSAttributedStringKey("UnsupportedHTMLAttributeName") - - // MARK: - UnsupportedHTML // class UnsupportedHTML: NSObject { diff --git a/Aztec/Classes/NSAttributedString/Conversions/AttributedStringParser.swift b/Aztec/Classes/NSAttributedString/Conversions/AttributedStringParser.swift index 0139022d9..c1438c6bd 100644 --- a/Aztec/Classes/NSAttributedString/Conversions/AttributedStringParser.swift +++ b/Aztec/Classes/NSAttributedString/Conversions/AttributedStringParser.swift @@ -663,7 +663,7 @@ private extension AttributedStringParser { let element: ElementNode - if let representation = attributes[BoldFormatter.htmlRepresentationKey] as? HTMLRepresentation, + if let representation = attributes[.boldHtmlRepresentation] as? HTMLRepresentation, case let .element(representationElement) = representation.kind { element = representationElement.toElementNode() @@ -683,7 +683,7 @@ private extension AttributedStringParser { let element: ElementNode - if let representation = attributes[ItalicFormatter.htmlRepresentationKey] as? HTMLRepresentation, + if let representation = attributes[.italicHtmlRepresentation] as? HTMLRepresentation, case let .element(representationElement) = representation.kind { element = representationElement.toElementNode() @@ -708,7 +708,7 @@ private extension AttributedStringParser { let element: ElementNode - if let representation = attributes[LinkFormatter.htmlRepresentationKey] as? HTMLRepresentation, + if let representation = attributes[.linkHtmlRepresentation] as? HTMLRepresentation, case let .element(representationElement) = representation.kind { element = representationElement.toElementNode() @@ -729,7 +729,7 @@ private extension AttributedStringParser { return nil } - if let representation = attributes[StrikethroughFormatter.htmlRepresentationKey] as? HTMLRepresentation, + if let representation = attributes[.strikeHtmlRepresentation] as? HTMLRepresentation, case let .element(representationElement) = representation.kind { return representationElement.toElementNode() @@ -746,7 +746,7 @@ private extension AttributedStringParser { return nil } - if let representation = attributes[UnderlineFormatter.htmlRepresentationKey] as? HTMLRepresentation, + if let representation = attributes[.underlineHtmlRepresentation] as? HTMLRepresentation, case let .element(representationElement) = representation.kind { return representationElement.toElementNode() @@ -759,7 +759,7 @@ private extension AttributedStringParser { /// Extracts all of the Unsupported HTML Snippets contained within a collection of Attributes. /// private func processUnsupportedHTML(in attributes: [NSAttributedStringKey: Any]) -> [ElementNode] { - guard let unsupportedHTML = attributes[UnsupportedHTMLAttributeName] as? UnsupportedHTML else { + guard let unsupportedHTML = attributes[.unsupportedHtml] as? UnsupportedHTML else { return [] } @@ -815,7 +815,7 @@ private extension AttributedStringParser { let element: ElementNode let range = attrString.rangeOfEntireString - if let representation = attrString.attribute(HRFormatter.htmlRepresentationKey, at: 0, longestEffectiveRange: nil, in: range) as? HTMLRepresentation, + if let representation = attrString.attribute(.hrHtmlRepresentation, at: 0, longestEffectiveRange: nil, in: range) as? HTMLRepresentation, case let .element(representationElement) = representation.kind { element = representationElement.toElementNode() @@ -873,7 +873,7 @@ private extension AttributedStringParser { let element: ElementNode let range = attrString.rangeOfEntireString - if let representation = attrString.attribute(ImageFormatter.htmlRepresentationKey, at: 0, longestEffectiveRange: nil, in: range) as? HTMLRepresentation, + if let representation = attrString.attribute(.imageHtmlRepresentation, at: 0, longestEffectiveRange: nil, in: range) as? HTMLRepresentation, case let .element(representationElement) = representation.kind { element = representationElement.toElementNode() @@ -920,7 +920,7 @@ private extension AttributedStringParser { let element: ElementNode let range = attrString.rangeOfEntireString - if let representation = attrString.attribute(VideoFormatter.htmlRepresentationKey, at: 0, longestEffectiveRange: nil, in: range) as? HTMLRepresentation, + if let representation = attrString.attribute(.videoHtmlRepresentation, at: 0, longestEffectiveRange: nil, in: range) as? HTMLRepresentation, case let .element(representationElement) = representation.kind { element = representationElement.toElementNode() diff --git a/Aztec/Classes/NSAttributedString/Conversions/AttributedStringSerializer.swift b/Aztec/Classes/NSAttributedString/Conversions/AttributedStringSerializer.swift index 23082e2a2..656db5d6d 100644 --- a/Aztec/Classes/NSAttributedString/Conversions/AttributedStringSerializer.swift +++ b/Aztec/Classes/NSAttributedString/Conversions/AttributedStringSerializer.swift @@ -315,7 +315,7 @@ private extension AttributedStringSerializer { /// - Returns: A collection of NSAttributedString Attributes, including the specified HTMLElementRepresentation. /// private func attributes(storing representation: HTMLElementRepresentation, in attributes: [NSAttributedStringKey: Any]) -> [NSAttributedStringKey: Any] { - let unsupportedHTML = attributes[UnsupportedHTMLAttributeName] as? UnsupportedHTML + let unsupportedHTML = attributes[.unsupportedHtml] as? UnsupportedHTML var representations = unsupportedHTML?.representations ?? [] representations.append(representation) @@ -324,7 +324,7 @@ private extension AttributedStringSerializer { // would mean affecting a range that may fall beyond what we expected! // var updated = attributes - updated[UnsupportedHTMLAttributeName] = UnsupportedHTML(representations: representations) + updated[.unsupportedHtml] = UnsupportedHTML(representations: representations) return updated } @@ -380,7 +380,7 @@ private extension AttributedStringSerializer { if let imgElement = linkedImageElement(for: element) { var attributesWithoutLink = attributes attributesWithoutLink[.link] = nil - attributesWithoutLink[LinkFormatter.htmlRepresentationKey] = nil + attributesWithoutLink[.linkHtmlRepresentation] = nil let imgAttributes = self.attributes(for: imgElement, inheriting: attributesWithoutLink) let attachment = imgAttributes[.attachment] as! ImageAttachment diff --git a/AztecTests/NSAttributedString/Conversions/AttributedStringParserTests.swift b/AztecTests/NSAttributedString/Conversions/AttributedStringParserTests.swift index 7821ae21a..3c5d2d6be 100644 --- a/AztecTests/NSAttributedString/Conversions/AttributedStringParserTests.swift +++ b/AztecTests/NSAttributedString/Conversions/AttributedStringParserTests.swift @@ -717,7 +717,7 @@ class AttributedStringParserTests: XCTestCase { // Store let unsupportedHTML = UnsupportedHTML(representations: [representation]) - testingString.addAttribute(UnsupportedHTMLAttributeName, value: unsupportedHTML, range: testingString.rangeOfEntireString) + testingString.addAttribute(.unsupportedHtml, value: unsupportedHTML, range: testingString.rangeOfEntireString) // Convert + Verify let node = AttributedStringParser().parse(testingString) diff --git a/AztecTests/NSAttributedString/Conversions/AttributedStringSerializerTests.swift b/AztecTests/NSAttributedString/Conversions/AttributedStringSerializerTests.swift index bdcb36553..f4599cb87 100644 --- a/AztecTests/NSAttributedString/Conversions/AttributedStringSerializerTests.swift +++ b/AztecTests/NSAttributedString/Conversions/AttributedStringSerializerTests.swift @@ -26,7 +26,7 @@ class AttributedStringSerializerTests: XCTestCase { // Test var range = NSRange() - guard let unsupportedHTML = output.attribute(UnsupportedHTMLAttributeName, at: 0, effectiveRange: &range) as? UnsupportedHTML else { + guard let unsupportedHTML = output.attribute(.unsupportedHtml, at: 0, effectiveRange: &range) as? UnsupportedHTML else { XCTFail() return } From 12aaa5b2f44ee3fd27d37903604b7b4e9e905370 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 6 Nov 2017 18:49:13 -0300 Subject: [PATCH 13/20] TextView: Cleanup --- Aztec/Classes/TextKit/TextView.swift | 34 ++++++++++++++++++---------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/Aztec/Classes/TextKit/TextView.swift b/Aztec/Classes/TextKit/TextView.swift index 9a6098ca5..7759fea03 100644 --- a/Aztec/Classes/TextKit/TextView.swift +++ b/Aztec/Classes/TextKit/TextView.swift @@ -186,7 +186,7 @@ open class TextView: UITextView { // MARK: - Apparance Properties - /// Blockquote Blocks Border COlor. + /// Blockquote Blocks Border Color. /// @objc dynamic public var blockquoteBorderColor: UIColor { get { @@ -249,7 +249,8 @@ open class TextView: UITextView { } - /// + /// Returns the collection of Typing Attributes, with all of the available 'String' keys properly converted into + /// NSAttributedStringKey. Also known as: what you would expect from the SDK. /// open var typingAttributesSwifted: [NSAttributedStringKey: Any] { get { @@ -358,7 +359,7 @@ open class TextView: UITextView { aztecLayoutManager.extraLineFragmentTypingAttributes = { [weak self] in return self?.extraLineFragmentTypingAttributes ?? [:] - } + } } // MARK: - Intercept copy paste operations @@ -711,12 +712,11 @@ open class TextView: UITextView { /// - Returns: A list of Formatting Identifiers. /// open func formatIdentifiersForTypingAttributes() -> [FormattingIdentifier] { + let activeAttributes = typingAttributesSwifted var identifiers = [FormattingIdentifier]() - for (key, formatter) in formatterIdentifiersMap { - if formatter.present(in: typingAttributesSwifted) { - identifiers.append(key) - } + for (key, formatter) in formatterIdentifiersMap where formatter.present(in: activeAttributes) { + identifiers.append(key) } return identifiers @@ -966,8 +966,9 @@ open class TextView: UITextView { TextListFormatter(style: .unordered) ] + let activeTypingAttributes = typingAttributesSwifted let found = formatters.first { formatter in - return formatter.present(in: typingAttributesSwifted) + return formatter.present(in: activeTypingAttributes) } guard found != nil else { @@ -1177,9 +1178,9 @@ open class TextView: UITextView { }) let formatter = LinkFormatter() - formatter.attributeValue = url - let attributes = formatter.apply(to: typingAttributesSwifted) + formatter.attributeValue = url + let attributes = formatter.apply(to: typingAttributesSwifted) storage.replaceCharacters(in: range, with: NSAttributedString(string: title, attributes: attributes)) selectedRange = NSRange(location: finalRange.location + finalRange.length, length: 0) @@ -1219,6 +1220,7 @@ open class TextView: UITextView { undoManager?.registerUndo(withTarget: self, handler: { [weak self] target in self?.undoTextReplacement(of: originalText, finalRange: finalRange) }) + let attachmentString = NSAttributedString(attachment: attachment, attributes: typingAttributesSwifted) storage.replaceCharacters(in: range, with: attachmentString) selectedRange = NSMakeRange(range.location + NSAttributedString.lengthOfTextAttachment, 0) @@ -1591,12 +1593,20 @@ private extension TextView { HeaderFormatter(headerLevel: .h6, placeholderAttributes: [:]) ] - for formatter in formatters where formatter.present(in: typingAttributesSwifted) { - typingAttributesSwifted = formatter.remove(from: typingAttributesSwifted) + var updatedTypingAttributes = typingAttributesSwifted + var needsRefresh = false + + for formatter in formatters where formatter.present(in: updatedTypingAttributes) { + updatedTypingAttributes = formatter.remove(from: updatedTypingAttributes) + needsRefresh = true let applicationRange = formatter.applicationRange(for: selectedRange, in: textStorage) formatter.removeAttributes(from: textStorage, at: applicationRange) } + + if needsRefresh { + typingAttributesSwifted = updatedTypingAttributes + } } // MARK: - WORKAROUND: Removing paragraph styles when pressing enter in an empty paragraph From cd449e5345a29093bca5438b4d86633a8684aeb5 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Tue, 7 Nov 2017 14:22:07 -0300 Subject: [PATCH 14/20] NSAttributedStringKey: Renames constant --- Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift | 2 +- .../Formatters/Implementations/StrikethroughFormatter.swift | 2 +- .../NSAttributedString/Conversions/AttributedStringParser.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift b/Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift index 0dc508ca8..aced1dbdc 100644 --- a/Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift +++ b/Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift @@ -31,7 +31,7 @@ public extension NSAttributedStringKey { /// Key used to store Strike Tag Metadata, by our StrikeFormatter. /// - public static let strikeHtmlRepresentation = NSAttributedStringKey("Strike.htmlRepresentation") + public static let strikethroughHtmlRepresentation = NSAttributedStringKey("Strike.htmlRepresentation") /// Key used to store UnderlineHTMLRepresentations, by our UnderlineFormatter. /// diff --git a/Aztec/Classes/Formatters/Implementations/StrikethroughFormatter.swift b/Aztec/Classes/Formatters/Implementations/StrikethroughFormatter.swift index 855106790..b67ba1189 100644 --- a/Aztec/Classes/Formatters/Implementations/StrikethroughFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/StrikethroughFormatter.swift @@ -5,6 +5,6 @@ class StrikethroughFormatter: StandardAttributeFormatter { init() { super.init(attributeKey: .strikethroughStyle, attributeValue: NSUnderlineStyle.styleSingle.rawValue, - htmlRepresentationKey: .strikeHtmlRepresentation) + htmlRepresentationKey: .strikethroughHtmlRepresentation) } } diff --git a/Aztec/Classes/NSAttributedString/Conversions/AttributedStringParser.swift b/Aztec/Classes/NSAttributedString/Conversions/AttributedStringParser.swift index c1438c6bd..3be764244 100644 --- a/Aztec/Classes/NSAttributedString/Conversions/AttributedStringParser.swift +++ b/Aztec/Classes/NSAttributedString/Conversions/AttributedStringParser.swift @@ -729,7 +729,7 @@ private extension AttributedStringParser { return nil } - if let representation = attributes[.strikeHtmlRepresentation] as? HTMLRepresentation, + if let representation = attributes[.strikethroughHtmlRepresentation] as? HTMLRepresentation, case let .element(representationElement) = representation.kind { return representationElement.toElementNode() From 23969868677e4c4392194dbc76e5df02b0b064ef Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Tue, 7 Nov 2017 14:22:19 -0300 Subject: [PATCH 15/20] NSAttributedStringKey+Conversion: Documenting Methods --- .../Extensions/NSAttributedStringKey+Conversion.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Aztec/Classes/Extensions/NSAttributedStringKey+Conversion.swift b/Aztec/Classes/Extensions/NSAttributedStringKey+Conversion.swift index 524d4bb2e..c2318b520 100644 --- a/Aztec/Classes/Extensions/NSAttributedStringKey+Conversion.swift +++ b/Aztec/Classes/Extensions/NSAttributedStringKey+Conversion.swift @@ -6,7 +6,8 @@ import UIKit // extension NSAttributedStringKey { - /// + /// Converts a collection of NSAttributedString Attributes, with 'NSAttributedStringKey' instances as 'Keys', into an + /// equivalent collection that uses regular 'String' instances as keys. /// static func convertToRaw(attributes: [NSAttributedStringKey: Any]) -> [String: Any] { var output = [String: Any]() @@ -18,7 +19,8 @@ extension NSAttributedStringKey { } - /// + /// Converts a collection of NSAttributedString Attributes, with 'String' instances as 'Keys', into an equivalent + /// collection that uses the new 'NSAttributedStringKey' enum as keys. /// static func convertFromRaw(attributes: [String: Any]) -> [NSAttributedStringKey: Any] { var output = [NSAttributedStringKey: Any]() From 0b51beec475e4ff97f59948b1d5750602c6c458a Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Tue, 7 Nov 2017 14:37:42 -0300 Subject: [PATCH 16/20] Implements NSAttributedStringKeyHelperTests --- Aztec.xcodeproj/project.pbxproj | 4 ++ .../NSAttributedStringKeyHelperTests.swift | 40 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 AztecTests/Extensions/NSAttributedStringKeyHelperTests.swift diff --git a/Aztec.xcodeproj/project.pbxproj b/Aztec.xcodeproj/project.pbxproj index 7c990ea8f..33e04db18 100644 --- a/Aztec.xcodeproj/project.pbxproj +++ b/Aztec.xcodeproj/project.pbxproj @@ -43,6 +43,7 @@ B572AC281E817CFE008948C2 /* CommentAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = B572AC271E817CFE008948C2 /* CommentAttachment.swift */; }; B574F4A41FB0CF3B0048F355 /* NSAttributedStringKey+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B574F4A31FB0CF3A0048F355 /* NSAttributedStringKey+Conversion.swift */; }; B574F4AD1FB103430048F355 /* NSAttributedStringKey+Aztec.swift in Sources */ = {isa = PBXBuildFile; fileRef = B574F4AC1FB103430048F355 /* NSAttributedStringKey+Aztec.swift */; }; + B574F4AF1FB110850048F355 /* NSAttributedStringKeyHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B574F4AE1FB110850048F355 /* NSAttributedStringKeyHelperTests.swift */; }; B57534501F267D0B009D4904 /* Array+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B575344F1F267D0B009D4904 /* Array+Helpers.swift */; }; B57534521F267D63009D4904 /* ArrayHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57534511F267D63009D4904 /* ArrayHelperTests.swift */; }; B57D1C3D1E92C38000EA4B16 /* HTMLAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D1C3C1E92C38000EA4B16 /* HTMLAttachment.swift */; }; @@ -223,6 +224,7 @@ B572AC271E817CFE008948C2 /* CommentAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommentAttachment.swift; sourceTree = ""; }; B574F4A31FB0CF3A0048F355 /* NSAttributedStringKey+Conversion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedStringKey+Conversion.swift"; sourceTree = ""; }; B574F4AC1FB103430048F355 /* NSAttributedStringKey+Aztec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAttributedStringKey+Aztec.swift"; sourceTree = ""; }; + B574F4AE1FB110850048F355 /* NSAttributedStringKeyHelperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = NSAttributedStringKeyHelperTests.swift; path = Extensions/NSAttributedStringKeyHelperTests.swift; sourceTree = ""; }; B575344F1F267D0B009D4904 /* Array+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+Helpers.swift"; sourceTree = ""; }; B57534511F267D63009D4904 /* ArrayHelperTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ArrayHelperTests.swift; path = Extensions/ArrayHelperTests.swift; sourceTree = ""; }; B57D1C3C1E92C38000EA4B16 /* HTMLAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTMLAttachment.swift; sourceTree = ""; }; @@ -780,6 +782,7 @@ B5BC4FF11DA2D17000614582 /* NSAttributedStringListsTests.swift */, F10BE61B1EA7B1DB002E4625 /* NSAttributedStringReplaceOcurrencesTests.swift */, F17BC8741F4E48FF00398E2B /* NSAttributedStringHTMLInitializerTests.swift */, + B574F4AE1FB110850048F355 /* NSAttributedStringKeyHelperTests.swift */, F14665441EA7C230008DE2B8 /* NSMutableAttributedStringReplaceOcurrencesTests.swift */, F18733C71DA09737005AEB80 /* NSRangeComparisonTests.swift */, F1000CE81EAA5C720000B15B /* StringEndOfLineTests.swift */, @@ -1111,6 +1114,7 @@ F1953E251F4E544A00C717C9 /* HTMLParserTests.swift in Sources */, B5C16A631F4DF77300B113CF /* HeaderFormatterTests.swift in Sources */, B5D575881F2288E2003A62F6 /* TextViewStubAttachmentDelegate.swift in Sources */, + B574F4AF1FB110850048F355 /* NSAttributedStringKeyHelperTests.swift in Sources */, F168DB861F6381A00009BD0E /* CSSParserTests.swift in Sources */, F1000CE91EAA5C720000B15B /* StringEndOfLineTests.swift in Sources */, F17BC8751F4E48FF00398E2B /* NSAttributedStringHTMLInitializerTests.swift in Sources */, diff --git a/AztecTests/Extensions/NSAttributedStringKeyHelperTests.swift b/AztecTests/Extensions/NSAttributedStringKeyHelperTests.swift new file mode 100644 index 000000000..212f74aec --- /dev/null +++ b/AztecTests/Extensions/NSAttributedStringKeyHelperTests.swift @@ -0,0 +1,40 @@ +import XCTest +@testable import Aztec + +class NSAttributedStringKeyHelperTests: XCTestCase { + + /// Verifies that, given a collection of [NSAttributedStringKey: Any], `NSAttributedStringKey.convertToRaw(:)` effectively converts + /// all of the keys into Strings. + /// + func testConvertToRawReturnsANewCollectionContainingAllOfTheStringValues() { + let input: [NSAttributedStringKey: Any] = [ + .strikethroughStyle: NSUnderlineStyle.styleSingle, + .attachment: 222, + NSAttributedStringKey("Custom"): 111 + ] + + let output = NSAttributedStringKey.convertToRaw(attributes: input) + + XCTAssertEqual(output[NSAttributedStringKey.strikethroughStyle.rawValue] as! NSUnderlineStyle, .styleSingle) + XCTAssertEqual(output[NSAttributedStringKey.attachment.rawValue] as! Int, 222) + XCTAssertEqual(output["Custom"] as! Int, 111) + } + + + /// Verifies that, given a collection of [String: Any], `NSAttributedStringKey.convertFromRaw(:)` effectively converts + /// all of the keys into NSAttributedStringKey instances. + /// + func testConvertFromRawReturnsANewCollectionContainingAttributedStringKeyInstances() { + let input: [String: Any] = [ + NSAttributedStringKey.strikethroughStyle.rawValue: NSUnderlineStyle.styleSingle, + NSAttributedStringKey.attachment.rawValue: 222, + "Custom": 111 + ] + + let output = NSAttributedStringKey.convertFromRaw(attributes: input) + + XCTAssertEqual(output[.strikethroughStyle] as! NSUnderlineStyle, NSUnderlineStyle.styleSingle) + XCTAssertEqual(output[.attachment] as! Int, 222) + XCTAssertEqual(output[NSAttributedStringKey("Custom")] as! Int, 111) + } +} From 09c7973cd0bf215091787d84d5a9e3fd61e00a5a Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Tue, 7 Nov 2017 15:41:11 -0300 Subject: [PATCH 17/20] Cocoapods Swift Version: Mark 4.0 --- .swift-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.swift-version b/.swift-version index a3ec5a4bd..5186d0706 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -3.2 +4.0 From 8eaf6bc3c4c7653cf2ae579343c4a0a52624b78e Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Tue, 7 Nov 2017 15:42:15 -0300 Subject: [PATCH 18/20] NSAttributedStringKey+Aztec: Removing 1 line here --- Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift b/Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift index aced1dbdc..19fb22fe3 100644 --- a/Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift +++ b/Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift @@ -45,4 +45,3 @@ public extension NSAttributedStringKey { /// public static let videoHtmlRepresentation = NSAttributedStringKey("Video.htmlRepresentation") } - From 02bea211dc2c5af06859a22f4a8f835f699097c7 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Tue, 7 Nov 2017 15:54:50 -0300 Subject: [PATCH 19/20] NSAttributedStringKey+Aztec: Removing another line here --- Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift b/Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift index 19fb22fe3..261e9cb5d 100644 --- a/Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift +++ b/Aztec/Classes/Constants/NSAttributedStringKey+Aztec.swift @@ -1,6 +1,5 @@ import Foundation - // MARK: - Aztec NSAttributedString Keys // public extension NSAttributedStringKey { From afd7e3be77e328611935ee1825606c8560edb2f6 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Tue, 7 Nov 2017 17:05:45 -0300 Subject: [PATCH 20/20] String+RangeConversion: fatalError FTW --- Aztec/Classes/Extensions/String+RangeConversion.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Aztec/Classes/Extensions/String+RangeConversion.swift b/Aztec/Classes/Extensions/String+RangeConversion.swift index 0e2bdf185..85a85e4e3 100644 --- a/Aztec/Classes/Extensions/String+RangeConversion.swift +++ b/Aztec/Classes/Extensions/String+RangeConversion.swift @@ -116,7 +116,7 @@ public extension String { guard let lowerBound = range.lowerBound.samePosition(in: utf16), let upperBound = range.upperBound.samePosition(in: utf16) else { - return .zero + fatalError() } let location = utf16.distance(from: utf16.startIndex, to: lowerBound)