diff --git a/.circleci/config.yml b/.circleci/config.yml index aa058ec4b..bf7ef87f7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,7 +2,7 @@ version: 2.1 orbs: # This uses the iOS Orb located at https://github.com/wordpress-mobile/circleci-orbs - ios: wordpress-mobile/ios@0.0.32 + ios: wordpress-mobile/ios@0.0.36 workflows: test_and_validate: @@ -28,5 +28,28 @@ workflows: name: Validate WordPress-Editor-iOS.podspec xcode-version: "11.0" podspec-path: WordPress-Editor-iOS.podspec - # Updating specs is needed since WordPress-Editor-iOS depends on WordPress-Aztec-iOS - update-specs-repo: true + # Reference WordPress-Aztec-iOS.podspec locally so we don't have to get it from the specs repo + additional-parameters: --include-podspecs=WordPress-Aztec-iOS.podspec + + - ios/publish-podspec: + name: Publish WordPress-Aztec-iOS to Trunk + xcode-version: "11.0" + podspec-path: WordPress-Aztec-iOS.podspec + post-to-slack: true + filters: + tags: + only: /.*/ + branches: + ignore: /.*/ + + - ios/publish-podspec: + name: Publish WordPress-Editor-iOS to Trunk + requires: [ "Publish WordPress-Aztec-iOS to Trunk" ] + xcode-version: "11.0" + podspec-path: WordPress-Editor-iOS.podspec + post-to-slack: true + filters: + tags: + only: /.*/ + branches: + ignore: /.*/ diff --git a/Aztec.xcodeproj/project.pbxproj b/Aztec.xcodeproj/project.pbxproj index 826034637..9b480a079 100644 --- a/Aztec.xcodeproj/project.pbxproj +++ b/Aztec.xcodeproj/project.pbxproj @@ -231,14 +231,18 @@ FF24AC991F0146AF003CA91D /* Assets.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF24AC981F0146AF003CA91D /* Assets.swift */; }; FF437B6420D7CB2D000D9666 /* HTMLLi.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF437B6320D7CB2D000D9666 /* HTMLLi.swift */; }; FF437B6620D7CB83000D9666 /* LiFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF437B6520D7CB83000D9666 /* LiFormatter.swift */; }; + FF48CAC8234DD5D3007FFC79 /* NSMutableAttributedString+ReplaceAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF48CAC7234DD5D3007FFC79 /* NSMutableAttributedString+ReplaceAttributes.swift */; }; FF4E26601EA8DF1E005E8E42 /* ImageAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4E265F1EA8DF1E005E8E42 /* ImageAttachment.swift */; }; FF61909E202481F4004BCD0A /* CodeFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF61909D202481F4004BCD0A /* CodeFormatter.swift */; }; FF7A1C511E5651EA00C4C7C8 /* LineAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF7A1C501E5651EA00C4C7C8 /* LineAttachment.swift */; }; FF7C89B01E3BC52F000472A8 /* NSAttributedString+FontTraits.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF7C89AF1E3BC52F000472A8 /* NSAttributedString+FontTraits.swift */; }; + FF7EAEC4234D253B007A26E0 /* FontProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF7EAEC3234D253B007A26E0 /* FontProvider.swift */; }; FFA61E891DF18F3D00B71BF6 /* ParagraphStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA61E881DF18F3D00B71BF6 /* ParagraphStyle.swift */; }; FFA61EC21DF6C1C900B71BF6 /* NSAttributedString+Archive.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA61EC11DF6C1C900B71BF6 /* NSAttributedString+Archive.swift */; }; FFB5D29720BEB21A0038DCFB /* CiteFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB5D29620BEB21A0038DCFB /* CiteFormatter.swift */; }; FFD0FEB71DAE59A700430586 /* NSLayoutManager+Attachments.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFD0FEB61DAE59A700430586 /* NSLayoutManager+Attachments.swift */; }; + FFD3C1712344DB4E00AE8DA0 /* ForegroundColorCSSAttributeMatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFD3C1702344DB4E00AE8DA0 /* ForegroundColorCSSAttributeMatcher.swift */; }; + FFD3C1732344DCA900AE8DA0 /* ForegroundColorElementAttributeConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFD3C1722344DCA900AE8DA0 /* ForegroundColorElementAttributeConverter.swift */; }; FFD436981E3180A500A0E26F /* FontFormatterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFD436971E3180A500A0E26F /* FontFormatterTests.swift */; }; FFFEC7DB1EA7698900F4210F /* VideoAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFFEC7DA1EA7698900F4210F /* VideoAttachment.swift */; }; /* End PBXBuildFile section */ @@ -503,6 +507,7 @@ FF24AC981F0146AF003CA91D /* Assets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Assets.swift; sourceTree = ""; }; FF437B6320D7CB2D000D9666 /* HTMLLi.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTMLLi.swift; sourceTree = ""; }; FF437B6520D7CB83000D9666 /* LiFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LiFormatter.swift; sourceTree = ""; }; + FF48CAC7234DD5D3007FFC79 /* NSMutableAttributedString+ReplaceAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSMutableAttributedString+ReplaceAttributes.swift"; sourceTree = ""; }; FF4E265F1EA8DF1E005E8E42 /* ImageAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageAttachment.swift; sourceTree = ""; }; FF5B98E21DC29D0C00571CA4 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; }; FF5B98E41DC355B400571CA4 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = SOURCE_ROOT; }; @@ -511,11 +516,14 @@ FF7A1C4A1E51F05700C4C7C8 /* CONTRIBUTING.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = CONTRIBUTING.md; sourceTree = ""; }; FF7A1C501E5651EA00C4C7C8 /* LineAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LineAttachment.swift; sourceTree = ""; }; FF7C89AF1E3BC52F000472A8 /* NSAttributedString+FontTraits.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+FontTraits.swift"; sourceTree = ""; }; + FF7EAEC3234D253B007A26E0 /* FontProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontProvider.swift; sourceTree = ""; }; FFA61E881DF18F3D00B71BF6 /* ParagraphStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParagraphStyle.swift; sourceTree = ""; }; FFA61EC11DF6C1C900B71BF6 /* NSAttributedString+Archive.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+Archive.swift"; sourceTree = ""; }; FFB5D29620BEB21A0038DCFB /* CiteFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CiteFormatter.swift; sourceTree = ""; }; FFC2BBF81F2A25CF00E404FB /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = ""; }; FFD0FEB61DAE59A700430586 /* NSLayoutManager+Attachments.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSLayoutManager+Attachments.swift"; sourceTree = ""; }; + FFD3C1702344DB4E00AE8DA0 /* ForegroundColorCSSAttributeMatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForegroundColorCSSAttributeMatcher.swift; sourceTree = ""; }; + FFD3C1722344DCA900AE8DA0 /* ForegroundColorElementAttributeConverter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForegroundColorElementAttributeConverter.swift; sourceTree = ""; }; FFD436971E3180A500A0E26F /* FontFormatterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FontFormatterTests.swift; sourceTree = ""; }; FFFEC7DA1EA7698900F4210F /* VideoAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoAttachment.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -742,6 +750,7 @@ FFD0FEB61DAE59A700430586 /* NSLayoutManager+Attachments.swift */, F1584795203C9B4C00EE05A1 /* NSMutableAttributedString+ParagraphProperty.swift */, F10BE6171EA7ADA6002E4625 /* NSMutableAttributedString+ReplaceOcurrences.swift */, + FF48CAC7234DD5D3007FFC79 /* NSMutableAttributedString+ReplaceAttributes.swift */, F18733C41DA096EE005AEB80 /* NSRange+Helpers.swift */, FF20D6431EDC395E00294B78 /* NSTextingResult+Helpers.swift */, F1C05B9C1E37FA77007510EA /* String+CharacterName.swift */, @@ -800,6 +809,7 @@ FFA61E881DF18F3D00B71BF6 /* ParagraphStyle.swift */, B5A99D831EBA073D00DED081 /* HTMLStorage.swift */, F9982CF521877663001E606B /* TextViewPasteboardDelegate.swift */, + FF7EAEC3234D253B007A26E0 /* FontProvider.swift */, ); path = TextKit; sourceTree = ""; @@ -898,6 +908,7 @@ F1098740214FF55F00983B6A /* BoldElementAttributeConverter.swift */, F109874421501A2F00983B6A /* ItalicElementAttributeConverter.swift */, F109874821501C8B00983B6A /* UnderlineElementAttributeConverter.swift */, + FFD3C1722344DCA900AE8DA0 /* ForegroundColorElementAttributeConverter.swift */, ); path = Implementations; sourceTree = ""; @@ -1087,6 +1098,7 @@ F15BA610215167D200424120 /* CSSAttributeMatcher.swift */, F1F5C9DA21516E4B00F67990 /* ItalicCSSAttributeMatcher.swift */, F1F5C9DC2151702600F67990 /* UnderlineCSSAttributeMatcher.swift */, + FFD3C1702344DB4E00AE8DA0 /* ForegroundColorCSSAttributeMatcher.swift */, ); path = CSS; sourceTree = ""; @@ -1524,6 +1536,8 @@ B572AC281E817CFE008948C2 /* CommentAttachment.swift in Sources */, F1E1D5881FEC52EE0086B339 /* GenericElementConverter.swift in Sources */, F1FA0E861E6EF514009D98EE /* Node.swift in Sources */, + FFD3C1712344DB4E00AE8DA0 /* ForegroundColorCSSAttributeMatcher.swift in Sources */, + FFD3C1732344DCA900AE8DA0 /* ForegroundColorElementAttributeConverter.swift in Sources */, F1656FDE2152A6A6009C7E3A /* CiteStringAttributeConverter.swift in Sources */, 599F254B1D8BC9A1002871D6 /* String+RangeConversion.swift in Sources */, 599F25481D8BC9A1002871D6 /* Metrics.swift in Sources */, @@ -1565,6 +1579,7 @@ F165D92A20C72EF500EAA6B0 /* Array+ShortcodeAttribute.swift in Sources */, F165D92420C72C1000EAA6B0 /* ShortcodeAttributeSerializer.swift in Sources */, F177FF751FB6404D00CBBE35 /* UILayoutPriority+Swift4.swift in Sources */, + FF7EAEC4234D253B007A26E0 /* FontProvider.swift in Sources */, F1C05B9D1E37FA77007510EA /* String+CharacterName.swift in Sources */, F1FF7D9F201A1D24007B0B32 /* Figcaption.swift in Sources */, FF17B2D2227A589F0022AECE /* LIElementConverter.swift in Sources */, @@ -1631,6 +1646,7 @@ 599F25381D8BC9A1002871D6 /* InAttributesConverter.swift in Sources */, B551A4A01E770B3800EE3A7F /* UIFont+Emoji.swift in Sources */, F13E8AD820B71BAA007C9F8A /* PluginManager.swift in Sources */, + FF48CAC8234DD5D3007FFC79 /* NSMutableAttributedString+ReplaceAttributes.swift in Sources */, F12F586E1EF20394008AE298 /* LinkFormatter.swift in Sources */, F1584796203C9B4C00EE05A1 /* NSMutableAttributedString+ParagraphProperty.swift in Sources */, F15BA6092151501300424120 /* BoldStringAttributeConverter.swift in Sources */, @@ -1800,7 +1816,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = /usr/include/libxml2; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = "-lxml2"; @@ -1861,7 +1877,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = /usr/include/libxml2; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = "-lxml2"; SDKROOT = iphoneos; @@ -1893,6 +1909,7 @@ ); INFOPLIST_FILE = Aztec/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = org.wordpress.Aztec; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1922,6 +1939,7 @@ ); INFOPLIST_FILE = Aztec/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = org.wordpress.Aztec; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2063,7 +2081,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = /usr/include/libxml2; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = "-lxml2"; @@ -2095,6 +2113,7 @@ ); INFOPLIST_FILE = Aztec/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = org.wordpress.Aztec; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2175,7 +2194,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = /usr/include/libxml2; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = "-lxml2"; @@ -2208,6 +2227,7 @@ ); INFOPLIST_FILE = Aztec/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = org.wordpress.Aztec; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/Aztec/Classes/Converters/AttributesToStringAttributes/Implementations/ForegroundColorElementAttributeConverter.swift b/Aztec/Classes/Converters/AttributesToStringAttributes/Implementations/ForegroundColorElementAttributeConverter.swift new file mode 100644 index 000000000..ba661389e --- /dev/null +++ b/Aztec/Classes/Converters/AttributesToStringAttributes/Implementations/ForegroundColorElementAttributeConverter.swift @@ -0,0 +1,24 @@ +import Foundation +import UIKit + +class ForegroundColorElementAttributesConverter: ElementAttributeConverter { + + let cssAttributeMatcher = ForegroundColorCSSAttributeMatcher() + + func convert( + _ attribute: Attribute, + inheriting attributes: [NSAttributedString.Key: Any]) -> [NSAttributedString.Key: Any] { + + guard let cssColor = attribute.firstCSSAttribute(ofType: .foregroundColor), + let colorValue = cssColor.value, + let color = UIColor(hexString: colorValue) else { + return attributes + } + + var attributes = attributes + + attributes[.foregroundColor] = color + + return attributes + } +} diff --git a/Aztec/Classes/EditorView/EditorView.swift b/Aztec/Classes/EditorView/EditorView.swift index a10643e10..53d727161 100644 --- a/Aztec/Classes/EditorView/EditorView.swift +++ b/Aztec/Classes/EditorView/EditorView.swift @@ -107,12 +107,10 @@ public class EditorView: UIView { self.htmlTextView = htmlTextView self.richTextView = richTextView - - if #available(iOS 11, *) { - htmlTextView.smartInsertDeleteType = .no - htmlTextView.smartDashesType = .no - htmlTextView.smartQuotesType = .no - } + + htmlTextView.smartInsertDeleteType = .no + htmlTextView.smartDashesType = .no + htmlTextView.smartQuotesType = .no super.init(coder: aDecoder) @@ -129,12 +127,10 @@ public class EditorView: UIView { self.htmlTextView = UITextView(frame: .zero, textContainer: container) self.richTextView = TextView(defaultFont: defaultFont, defaultParagraphStyle: defaultParagraphStyle, defaultMissingImage: defaultMissingImage) - - if #available(iOS 11, *) { - htmlTextView.smartInsertDeleteType = .no - htmlTextView.smartDashesType = .no - htmlTextView.smartQuotesType = .no - } + + htmlTextView.smartInsertDeleteType = .no + htmlTextView.smartDashesType = .no + htmlTextView.smartQuotesType = .no super.init(frame: .zero) diff --git a/Aztec/Classes/Extensions/NSMutableAttributedString+ReplaceAttributes.swift b/Aztec/Classes/Extensions/NSMutableAttributedString+ReplaceAttributes.swift new file mode 100644 index 000000000..84f2a388d --- /dev/null +++ b/Aztec/Classes/Extensions/NSMutableAttributedString+ReplaceAttributes.swift @@ -0,0 +1,25 @@ +import Foundation +import UIKit + +public extension NSMutableAttributedString { + + /// Replace all instances of the .font attribute that belong to the same family for the new font, trying to keep the same symbolic traits + /// - Parameter font: the original font to be replaced + /// - Parameter newFont: the new font to use. + func replace(font: UIFont, with newFont: UIFont) { + let fullRange = NSRange(location: 0, length: length) + + beginEditing() + enumerateAttributes(in: fullRange, options: []) { (attributes, subrange, stop) in + guard let currentFont = attributes[.font] as? UIFont, currentFont.familyName == font.familyName else { + return + } + var replacementFont = newFont + if let fontDescriptor = newFont.fontDescriptor.withSymbolicTraits(currentFont.fontDescriptor.symbolicTraits) { + replacementFont = UIFont(descriptor: fontDescriptor, size: currentFont.pointSize) + } + addAttribute(.font, value: replacementFont, range: subrange) + } + endEditing() + } +} diff --git a/Aztec/Classes/Formatters/Implementations/CodeFormatter.swift b/Aztec/Classes/Formatters/Implementations/CodeFormatter.swift index 1583dacda..04918e19d 100644 --- a/Aztec/Classes/Formatters/Implementations/CodeFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/CodeFormatter.swift @@ -12,15 +12,8 @@ class CodeFormatter: AttributeFormatter { // MARK: - Init - init(monospaceFont: UIFont = UIFont(descriptor:UIFontDescriptor(name: "Courier", size: 12), size:12), backgroundColor: UIColor = UIColor.lightGray) { - let font: UIFont - - if #available(iOS 11.0, *) { - font = UIFontMetrics.default.scaledFont(for: monospaceFont) - } else { - font = monospaceFont - } - self.monospaceFont = font + init(monospaceFont: UIFont = FontProvider.shared.monospaceFont, backgroundColor: UIColor = UIColor.lightGray) { + self.monospaceFont = monospaceFont self.backgroundColor = backgroundColor self.htmlRepresentationKey = .codeHtmlRepresentation } diff --git a/Aztec/Classes/Formatters/Implementations/PreFormatter.swift b/Aztec/Classes/Formatters/Implementations/PreFormatter.swift index 384c7b117..cf6ecbbd4 100644 --- a/Aztec/Classes/Formatters/Implementations/PreFormatter.swift +++ b/Aztec/Classes/Formatters/Implementations/PreFormatter.swift @@ -14,19 +14,10 @@ open class PreFormatter: ParagraphAttributeFormatter { /// let placeholderAttributes: [NSAttributedString.Key: Any]? - /// Designated Initializer /// - init(monospaceFont: UIFont = UIFont(descriptor:UIFontDescriptor(name: "Courier", size: 12), size:12), placeholderAttributes: [NSAttributedString.Key : Any]? = nil) { - let font: UIFont - - if #available(iOS 11.0, *) { - font = UIFontMetrics.default.scaledFont(for: monospaceFont) - } else { - font = monospaceFont - } - - self.monospaceFont = font + init(monospaceFont: UIFont = FontProvider.shared.monospaceFont, placeholderAttributes: [NSAttributedString.Key : Any]? = nil) { + self.monospaceFont = monospaceFont self.placeholderAttributes = placeholderAttributes } diff --git a/Aztec/Classes/GUI/FormatBar/FormatBar.swift b/Aztec/Classes/GUI/FormatBar/FormatBar.swift index 82ca1300a..c370f5be2 100644 --- a/Aztec/Classes/GUI/FormatBar/FormatBar.swift +++ b/Aztec/Classes/GUI/FormatBar/FormatBar.swift @@ -326,9 +326,7 @@ open class FormatBar: UIView { open override func didMoveToWindow() { super.didMoveToWindow() - if #available(iOS 11.0, *) { - updateForSafeAreaInsets() - } + updateForSafeAreaInsets() } open override func layoutSubviews() { @@ -683,13 +681,8 @@ private extension FormatBar { /// Sets up the Constraints /// func configureConstraints() { - var leadingAnchor = self.leadingAnchor - var trailingAnchor = self.trailingAnchor - - if #available(iOS 11.0, *) { - leadingAnchor = safeAreaLayoutGuide.leadingAnchor - trailingAnchor = safeAreaLayoutGuide.trailingAnchor - } + let leadingAnchor = safeAreaLayoutGuide.leadingAnchor + let trailingAnchor = safeAreaLayoutGuide.trailingAnchor ///Overflow toggle item diff --git a/Aztec/Classes/Libxml2/DOM/Data/CSSAttributeType.swift b/Aztec/Classes/Libxml2/DOM/Data/CSSAttributeType.swift index 9f74c2977..6d008b5a1 100644 --- a/Aztec/Classes/Libxml2/DOM/Data/CSSAttributeType.swift +++ b/Aztec/Classes/Libxml2/DOM/Data/CSSAttributeType.swift @@ -23,6 +23,7 @@ extension CSSAttributeType { public static let fontStyle = CSSAttributeType("font-style") public static let fontWeight = CSSAttributeType("font-weight") public static let textDecoration = CSSAttributeType("text-decoration") + public static let foregroundColor = CSSAttributeType("color") } diff --git a/Aztec/Classes/Libxml2/DOM/Logic/CSS/ForegroundColorCSSAttributeMatcher.swift b/Aztec/Classes/Libxml2/DOM/Logic/CSS/ForegroundColorCSSAttributeMatcher.swift new file mode 100644 index 000000000..b5f50c94f --- /dev/null +++ b/Aztec/Classes/Libxml2/DOM/Logic/CSS/ForegroundColorCSSAttributeMatcher.swift @@ -0,0 +1,12 @@ +import Foundation + +open class ForegroundColorCSSAttributeMatcher: CSSAttributeMatcher { + + public func check(_ cssAttribute: CSSAttribute) -> Bool { + guard let value = cssAttribute.value else { + return false + } + + return cssAttribute.type == .foregroundColor && !value.isEmpty + } +} diff --git a/Aztec/Classes/NSAttributedString/Conversions/AttributedStringSerializer.swift b/Aztec/Classes/NSAttributedString/Conversions/AttributedStringSerializer.swift index 08146561c..235a8062c 100644 --- a/Aztec/Classes/NSAttributedString/Conversions/AttributedStringSerializer.swift +++ b/Aztec/Classes/NSAttributedString/Conversions/AttributedStringSerializer.swift @@ -29,6 +29,7 @@ class AttributedStringSerializer { BoldElementAttributesConverter(), ItalicElementAttributesConverter(), UnderlineElementAttributesConverter(), + ForegroundColorElementAttributesConverter(), ] ) @@ -181,32 +182,6 @@ class AttributedStringSerializer { return content } - - // MARK: - Formatter Maps - - public lazy var attributeFormattersMap: [String: AttributeFormatter] = { - return [:] - }() - - public let styleToFormattersMap: [String: (AttributeFormatter, (String)->Any?)] = [ - "color": (ColorFormatter(), {(value) in return UIColor(hexString: value)}), - "text-decoration": (UnderlineFormatter(), { (value) in return value == "underline" ? NSUnderlineStyle.single.rawValue : nil}) - ] - - func parseStyle(style: String) -> [String: String] { - var stylesDictionary = [String: String]() - let styleAttributes = style.components(separatedBy: ";") - for sytleAttribute in styleAttributes { - let keyValue = sytleAttribute.components(separatedBy: ":") - guard keyValue.count == 2, - let key = keyValue.first?.trimmingCharacters(in: CharacterSet.whitespaces), - let value = keyValue.last?.trimmingCharacters(in: CharacterSet.whitespaces) else { - continue - } - stylesDictionary[key] = value - } - return stylesDictionary - } } private extension AttributedStringSerializer { diff --git a/Aztec/Classes/TextKit/FontProvider.swift b/Aztec/Classes/TextKit/FontProvider.swift new file mode 100644 index 000000000..d4f4ddce1 --- /dev/null +++ b/Aztec/Classes/TextKit/FontProvider.swift @@ -0,0 +1,25 @@ +import Foundation +import UIKit + +public class FontProvider { + + private init() { + + } + + public static var shared = FontProvider() + + public lazy var monospaceFont: UIFont = { + let baseFont = UIFont(descriptor:UIFontDescriptor(name: "Menlo", size: 14), size:14) + let font: UIFont + font = UIFontMetrics.default.scaledFont(for: baseFont) + return font + }() + + public lazy var defaultFont: UIFont = { + let baseFont = UIFont.systemFont(ofSize: 14) + let font: UIFont + font = UIFontMetrics.default.scaledFont(for: baseFont) + return font + }() +} diff --git a/Aztec/Classes/TextKit/LayoutManager.swift b/Aztec/Classes/TextKit/LayoutManager.swift index aaaef8fc7..dbe233234 100644 --- a/Aztec/Classes/TextKit/LayoutManager.swift +++ b/Aztec/Classes/TextKit/LayoutManager.swift @@ -317,7 +317,11 @@ private extension LayoutManager { traits.remove(.traitBold) traits.remove(.traitItalic) - let descriptor = font.fontDescriptor.withSymbolicTraits(traits) - return UIFont(descriptor: descriptor!, size: font.pointSize) + if let descriptor = font.fontDescriptor.withSymbolicTraits(traits) { + return UIFont(descriptor: descriptor, size: font.pointSize) + } else { + // Don't touch the font if we cannot remove the symbolic traits. + return font + } } } diff --git a/Aztec/Classes/TextKit/ParagraphProperty/Header.swift b/Aztec/Classes/TextKit/ParagraphProperty/Header.swift index 46b600695..a13dafe0c 100644 --- a/Aztec/Classes/TextKit/ParagraphProperty/Header.swift +++ b/Aztec/Classes/TextKit/ParagraphProperty/Header.swift @@ -33,12 +33,7 @@ open class Header: ParagraphProperty { public var fontSize: Float { let fontSize = HeaderType.fontSizeMap[self] ?? Constants.defaultFontSize - - if #available(iOS 11.0, *) { - return Float(UIFontMetrics.default.scaledValue(for: CGFloat(fontSize))) - } else { - return fontSize - } + return Float(UIFontMetrics.default.scaledValue(for: CGFloat(fontSize))) } } diff --git a/Aztec/Classes/TextKit/TextView.swift b/Aztec/Classes/TextKit/TextView.swift index b0b7a53be..e7d631a5a 100644 --- a/Aztec/Classes/TextKit/TextView.swift +++ b/Aztec/Classes/TextKit/TextView.swift @@ -226,7 +226,14 @@ open class TextView: UITextView { // MARK: - Properties: UI Defaults - public let defaultFont: UIFont + /// The font to use to render any HTML that doesn't specify an explicit font. + /// If this is changed all the instances that use this font will be updated to the new one. + public var defaultFont: UIFont { + didSet { + textStorage.replace(font: oldValue, with: defaultFont) + } + } + public let defaultParagraphStyle: ParagraphStyle var defaultMissingImage: UIImage @@ -241,23 +248,6 @@ open class TextView: UITextView { return attributes } - /// This closure will be executed whenever the `TextView` needs to set the base style for - /// a caption. Override this to customize the caption styling. - /// - public lazy var captionStyler: ([NSAttributedString.Key:Any]) -> [NSAttributedString.Key:Any] = { [weak self] attributes in - guard let `self` = self else { - return attributes - } - - let font = self.defaultFont.withSize(10) - - var attributes = attributes - attributes[.font] = font - attributes[.foregroundColor] = UIColor.darkGray - - return attributes - } - // MARK: - Plugin Loading var pluginManager: PluginManager { @@ -371,16 +361,17 @@ open class TextView: UITextView { // MARK: - Init & deinit + /// Creates a Text View using the provided parameters as a base for HTML rendering. + /// - Parameter defaultFont: The font to use to render the elements if no specific font is set by the HTML. + /// - Parameter defaultParagraphStyle: The default paragraph style if no explicit attributes are defined in HTML + /// - Parameter defaultMissingImage: The image to use if the view is not able to render an image specified in the HTML. @objc public init( defaultFont: UIFont, defaultParagraphStyle: ParagraphStyle = ParagraphStyle.default, defaultMissingImage: UIImage) { - if #available(iOS 11.0, *) { - self.defaultFont = UIFontMetrics.default.scaledFont(for: defaultFont) - } else { - self.defaultFont = defaultFont - } + self.defaultFont = UIFontMetrics.default.scaledFont(for: defaultFont) + self.defaultParagraphStyle = defaultParagraphStyle self.defaultMissingImage = defaultMissingImage @@ -397,13 +388,7 @@ open class TextView: UITextView { } required public init?(coder aDecoder: NSCoder) { - let font = UIFont.systemFont(ofSize: 14) - if #available(iOS 11.0, *) { - self.defaultFont = UIFontMetrics.default.scaledFont(for: font) - } else { - self.defaultFont = font - } - + defaultFont = FontProvider.shared.defaultFont defaultParagraphStyle = ParagraphStyle.default defaultMissingImage = Assets.imageIcon @@ -413,9 +398,8 @@ open class TextView: UITextView { private func commonInit() { allowsEditingTextAttributes = true - if #available(iOS 10.0, *) { - adjustsFontForContentSizeCategory = true - } + adjustsFontForContentSizeCategory = true + storage.attachmentsDelegate = self font = defaultFont linkTextAttributes = [.underlineStyle: NSNumber(value: NSUnderlineStyle.single.rawValue), .foregroundColor: tintColor as Any] diff --git a/AztecTests/TextKit/TextViewTests.swift b/AztecTests/TextKit/TextViewTests.swift index 4891ba702..c3c878be6 100644 --- a/AztecTests/TextKit/TextViewTests.swift +++ b/AztecTests/TextKit/TextViewTests.swift @@ -377,6 +377,13 @@ class TextViewTests: XCTestCase { XCTAssert(!textView.formattingIdentifiersAtIndex(1).contains(.blockquote)) } + func testColorAttributeAtPosition() { + let textView = TextViewStub(withHTML: "foobarbaz") + + XCTAssert(textView.attributedText!.attributes(at: 4, effectiveRange: nil).keys.contains(.foregroundColor)) + let color = textView.attributedText!.attributes(at: 4, effectiveRange: nil)[.foregroundColor] as! UIColor + XCTAssertEqual(color, UIColor(hexString: "#FF0000")) + } // MARK: - Adding newlines @@ -1666,7 +1673,7 @@ class TextViewTests: XCTestCase { textView.insertText("😘") let currentTypingFont = textView.typingAttributes[.font] as! UIFont - XCTAssertEqual(currentTypingFont, font, "Font should be set to default") + XCTAssertEqual(currentTypingFont.fontDescriptor, font.fontDescriptor, "Font should be set to default") } diff --git a/Example/AztecExample.xcodeproj/project.pbxproj b/Example/AztecExample.xcodeproj/project.pbxproj index 88248f3c4..5e6cc212b 100644 --- a/Example/AztecExample.xcodeproj/project.pbxproj +++ b/Example/AztecExample.xcodeproj/project.pbxproj @@ -582,7 +582,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = /usr/include/libxml2; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -635,7 +635,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = /usr/include/libxml2; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; STRIP_INSTALLED_PRODUCT = NO; @@ -797,7 +797,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = /usr/include/libxml2; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -880,7 +880,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = /usr/include/libxml2; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; diff --git a/Example/Example/EditorDemoController.swift b/Example/Example/EditorDemoController.swift index 5cd6472e0..a1045394b 100644 --- a/Example/Example/EditorDemoController.swift +++ b/Example/Example/EditorDemoController.swift @@ -30,12 +30,8 @@ class EditorDemoController: UIViewController { fileprivate(set) lazy var editorView: Aztec.EditorView = { let defaultHTMLFont: UIFont - - if #available(iOS 11, *) { - defaultHTMLFont = UIFontMetrics.default.scaledFont(for: Constants.defaultContentFont) - } else { - defaultHTMLFont = Constants.defaultContentFont - } + + defaultHTMLFont = UIFontMetrics.default.scaledFont(for: Constants.defaultContentFont) let editorView = Aztec.EditorView( defaultFont: Constants.defaultContentFont, @@ -63,10 +59,8 @@ class EditorDemoController: UIViewController { textView.textAttachmentDelegate = self textView.accessibilityIdentifier = "richContentView" textView.clipsToBounds = false - if #available(iOS 11, *) { - textView.smartDashesType = .no - textView.smartQuotesType = .no - } + textView.smartDashesType = .no + textView.smartQuotesType = .no } private func setupHTMLTextView(_ textView: UITextView) { @@ -79,14 +73,10 @@ class EditorDemoController: UIViewController { textView.autocorrectionType = .no textView.autocapitalizationType = .none textView.clipsToBounds = false - if #available(iOS 10, *) { - textView.adjustsFontForContentSizeCategory = true - } - - if #available(iOS 11, *) { - textView.smartDashesType = .no - textView.smartQuotesType = .no - } + textView.adjustsFontForContentSizeCategory = true + + textView.smartDashesType = .no + textView.smartQuotesType = .no } fileprivate(set) lazy var titleTextView: UITextView = { @@ -195,11 +185,15 @@ class EditorDemoController: UIViewController { } else { html = "" } - + navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(changeFont)) editorView.setHTML(html) editorView.becomeFirstResponder() } + @objc func changeFont() { + editorView.richTextView.defaultFont = UIFont.preferredFont(forTextStyle: .callout) + } + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) @@ -245,9 +239,8 @@ class EditorDemoController: UIViewController { func updateScrollInsets() { var scrollInsets = editorView.contentInset var rightMargin = (view.frame.maxX - editorView.frame.maxX) - if #available(iOS 11.0, *) { - rightMargin -= view.safeAreaInsets.right - } + rightMargin -= view.safeAreaInsets.right + scrollInsets.right = -rightMargin editorView.scrollIndicatorInsets = scrollInsets } @@ -495,6 +488,10 @@ extension EditorDemoController : UITextViewDelegate { return true } + func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { + return false + } + func scrollViewDidScroll(_ scrollView: UIScrollView) { updateTitlePosition() } @@ -794,9 +791,7 @@ extension EditorDemoController { textField.clearButtonMode = UITextField.ViewMode.always; textField.placeholder = NSLocalizedString("URL", comment:"URL text field placeholder"); textField.keyboardType = .URL - if #available(iOS 10, *) { - textField.textContentType = .URL - } + textField.textContentType = .URL textField.text = urlToUse?.absoluteString textField.addTarget(self, diff --git a/WordPress-Aztec-iOS.podspec b/WordPress-Aztec-iOS.podspec index 2b56b742a..0573047d7 100644 --- a/WordPress-Aztec-iOS.podspec +++ b/WordPress-Aztec-iOS.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'WordPress-Aztec-iOS' - s.version = '1.10.1' + s.version = '1.11' s.summary = 'The native HTML Editor.' # This description is used to generate tags and improve search results. @@ -27,7 +27,7 @@ Pod::Spec.new do |s| s.author = { 'Automattic' => 'mobile@automattic.com', 'Diego Rey Mendez' => 'diego.rey.mendez@automattic.com', 'Sergio Estevao' => 'sergioestevao@gmail.com', 'Jorge Leandro Perez' => 'jorge.perez@automattic.com' } s.social_media_url = "http://twitter.com/WordPressiOS" s.source = { :git => 'https://github.com/wordpress-mobile/WordPress-Aztec-iOS.git', :tag => s.version.to_s } - s.ios.deployment_target = '10.0' + s.ios.deployment_target = '11.0' s.swift_version = '5.0' s.module_name = "Aztec" diff --git a/WordPress-Editor-iOS.podspec b/WordPress-Editor-iOS.podspec index 33cdc4e8b..025233351 100644 --- a/WordPress-Editor-iOS.podspec +++ b/WordPress-Editor-iOS.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'WordPress-Editor-iOS' - s.version = '1.10.1' + s.version = '1.11' s.summary = 'The WordPress HTML Editor.' # This description is used to generate tags and improve search results. @@ -27,7 +27,7 @@ Pod::Spec.new do |s| s.author = { 'Automattic' => 'mobile@automattic.com', 'Diego Rey Mendez' => 'diego.rey.mendez@automattic.com', 'Sergio Estevao' => 'sergioestevao@gmail.com', 'Jorge Leandro Perez' => 'jorge.perez@automattic.com' } s.social_media_url = "http://twitter.com/WordPressiOS" s.source = { :git => 'https://github.com/wordpress-mobile/WordPress-Aztec-iOS.git', :tag => s.version.to_s } - s.ios.deployment_target = '10.0' + s.ios.deployment_target = '11.0' s.swift_version = '5.0' s.module_name = "WordPressEditor" diff --git a/WordPressEditor/WordPressEditor.xcodeproj/project.pbxproj b/WordPressEditor/WordPressEditor.xcodeproj/project.pbxproj index 9dae87d91..455e8dbf9 100644 --- a/WordPressEditor/WordPressEditor.xcodeproj/project.pbxproj +++ b/WordPressEditor/WordPressEditor.xcodeproj/project.pbxproj @@ -762,7 +762,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -787,6 +787,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = WordPressEditor/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -871,7 +872,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -930,7 +931,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; @@ -955,6 +956,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = WordPressEditor/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -980,6 +982,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = WordPressEditor/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks",