From 2f9499da69df14df875985b8a07ebe841f686562 Mon Sep 17 00:00:00 2001 From: Harlan Kellaway Date: Fri, 7 Jul 2017 13:10:31 -0400 Subject: [PATCH 01/10] Added TextStyle factory function for updating properties --- Example/Marker.xcodeproj/project.pbxproj | 4 + .../Tests/TextStyleFactoryFunctionTests.swift | 496 ++++++++++++++++++ Marker/Classes/TextStyle+Extensions.swift | 108 ++++ Marker/Classes/TextTransform+Extensions.swift | 28 + 4 files changed, 636 insertions(+) create mode 100644 Example/Tests/TextStyleFactoryFunctionTests.swift create mode 100644 Marker/Classes/TextStyle+Extensions.swift create mode 100644 Marker/Classes/TextTransform+Extensions.swift diff --git a/Example/Marker.xcodeproj/project.pbxproj b/Example/Marker.xcodeproj/project.pbxproj index eff0455..701710f 100644 --- a/Example/Marker.xcodeproj/project.pbxproj +++ b/Example/Marker.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 2FC3E7E41F0FC57E0024E2D1 /* TextStyleFactoryFunctionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FC3E7E21F0FC5500024E2D1 /* TextStyleFactoryFunctionTests.swift */; }; 4811C04D1D0B6FB5007279CB /* AppTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4811C04C1D0B6FB5007279CB /* AppTheme.swift */; }; 485ED1131D09E89F00119D5D /* AvenirNextFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = 485ED1121D09E89F00119D5D /* AvenirNextFont.swift */; }; 485ED1181D0A091800119D5D /* ThemeSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 485ED1171D0A091800119D5D /* ThemeSettingsViewController.swift */; }; @@ -38,6 +39,7 @@ 08F1825B7EA29E36898092FB /* Marker.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = Marker.podspec; path = ../Marker.podspec; sourceTree = ""; }; 1E6E60D0D2F5667C8156B123 /* Pods_Marker_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Marker_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 2408A1D80FB40943D0B15C58 /* Pods-Marker_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Marker_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Marker_Tests/Pods-Marker_Tests.debug.xcconfig"; sourceTree = ""; }; + 2FC3E7E21F0FC5500024E2D1 /* TextStyleFactoryFunctionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextStyleFactoryFunctionTests.swift; sourceTree = ""; }; 31D2DC9BD8B466270B5299FF /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 4811C04C1D0B6FB5007279CB /* AppTheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppTheme.swift; sourceTree = ""; }; 485ED1121D09E89F00119D5D /* AvenirNextFont.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvenirNextFont.swift; sourceTree = ""; }; @@ -173,6 +175,7 @@ isa = PBXGroup; children = ( 486EC7691DB440D3009BCA7A /* ParserTests.swift */, + 2FC3E7E21F0FC5500024E2D1 /* TextStyleFactoryFunctionTests.swift */, 607FACE91AFB9204008FA782 /* Supporting Files */, ); path = Tests; @@ -415,6 +418,7 @@ buildActionMask = 2147483647; files = ( 486EC76B1DB440E8009BCA7A /* ParserTests.swift in Sources */, + 2FC3E7E41F0FC57E0024E2D1 /* TextStyleFactoryFunctionTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Example/Tests/TextStyleFactoryFunctionTests.swift b/Example/Tests/TextStyleFactoryFunctionTests.swift new file mode 100644 index 0000000..66ddc7e --- /dev/null +++ b/Example/Tests/TextStyleFactoryFunctionTests.swift @@ -0,0 +1,496 @@ +// +// TextStyleFactoryFunctionTests.swift +// Marker +// +// Created by Harlan Kellaway on 7/7/17. +// +// + +import UIKit +import XCTest +@testable import Marker + +class TextStyleFactoryFunctionTests: XCTestCase { + + var textStyle: TextStyle! + + override func setUp() { + super.setUp() + + textStyle = TextStyle(font: UIFont(name: "Helvetica", size: 10)!, + emFont: UIFont(name: "Helvetica-Oblique", size: 10)!, + strongFont: UIFont(name: "Helvetica-Bold", size: 10)!, + textColor: UIColor.red, + characterSpacing: 1, + lineSpacing: 2, + lineHeightMultiple: 3, + minimumLineHeight: 4, + maximumLineHeight: 5, + firstLineHeadIndent: 6, + headIndent: 7, + paragraphSpacing: 8, + paragraphSpacingBefore: 9, + textAlignment: .left, + lineBreakMode: .byWordWrapping, + strikethroughStyle: .styleSingle, + strikethroughColor: UIColor.red, + textTransform: .lowercased) + } + + override func tearDown() { + textStyle = nil + + super.tearDown() + } + + func testTextStyleFactory_whenNewFont_newFontIsUsed() { + let newFont = textStyle.font.withSize(textStyle.font.pointSize + 10) + let newTextStyle = textStyle.with(newFont: newFont) + let expectedTextStyle = TextStyle(font: newFont, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewEmFont_newEmFontIsUsed() { + let newEmFont = textStyle.emFont.withSize(textStyle.emFont.pointSize + 10) + let newTextStyle = textStyle.with(newEmFont: newEmFont) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: newEmFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewStrongFont_newStrongFontIsUsed() { + let newStrongFont = textStyle.strongFont.withSize(textStyle.strongFont.pointSize + 10) + let newTextStyle = textStyle.with(newStrongFont: newStrongFont) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: newStrongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewTextColor_newTextColorIsUsed() { + let newTextColor = UIColor.blue + let newTextStyle = textStyle.with(newTextColor: newTextColor) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: newTextColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewCharacterSpacing_newCharacterIsUsed() { + let newCharacterSpacing = textStyle.characterSpacing! + 10 + let newTextStyle = textStyle.with(newCharacterSpacing: newCharacterSpacing) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: newCharacterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewLineSpacing_newLineSpacingIsUsed() { + let newLineSpacing = textStyle.lineSpacing! + 10 + let newTextStyle = textStyle.with(newLineSpacing: newLineSpacing) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: newLineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewLineHeightMultiple_newLineHeightMultipleIsUsed() { + let newLineHeightMultiple = textStyle.lineHeightMultiple! + 10 + let newTextStyle = textStyle.with(newLineHeightMultiple: newLineHeightMultiple) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: newLineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewMinimumLineHeight_newMinimumLineHeightIsUsed() { + let newMinimumLineHeight = textStyle.minimumLineHeight! + 10 + let newTextStyle = textStyle.with(newMinimumLineHeight: newMinimumLineHeight) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: newMinimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewMaximumLineHeight_newMaximumLineHeightIsUsed() { + let newMaximumLineHeight = textStyle.maximumLineHeight! + 10 + let newTextStyle = textStyle.with(newMaximumLineHeight: newMaximumLineHeight) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: newMaximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewFirstLineHeadIndent_newFirstLineHeadIndentIsUsed() { + let newFirstLineHeadIndent = textStyle.firstLineHeadIndent! + 10 + let newTextStyle = textStyle.with(newFirstLineHeadIndent: newFirstLineHeadIndent) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: newFirstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewHeadIndent_newHeadIndentIsUsed() { + let newHeadIndent = textStyle.headIndent! + 10 + let newTextStyle = textStyle.with(newHeadIndent: newHeadIndent) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: newHeadIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewParagraphSpacing_newParagraphSpacingIsUsed() { + let newParagraphSpacing = textStyle.paragraphSpacing! + 10 + let newTextStyle = textStyle.with(newParagraphSpacing: newParagraphSpacing) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: newParagraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewParagraphSpacingBefore_newParagraphSpacingBeforeIsUsed() { + let newParagraphSpacingBefore = textStyle.paragraphSpacingBefore! + 10 + let newTextStyle = textStyle.with(newParagraphSpacingBefore: newParagraphSpacingBefore) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: newParagraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewTextAlignment_newTextAlignmentIsUsed() { + let newTextAlignment: NSTextAlignment = .right + let newTextStyle = textStyle.with(newTextAlignment: newTextAlignment) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: newTextAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewLineBreakMode_newLineBreakModeIsUsed() { + let newLineBreakMode: NSLineBreakMode = .byCharWrapping + let newTextStyle = textStyle.with(newLineBreakMode: newLineBreakMode) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: newLineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewStrikethroughStyle_newStrikethroughStyleIsUsed() { + let newStrikethroughStyle: NSUnderlineStyle = .styleDouble + let newTextStyle = textStyle.with(newStrikethroughStyle: newStrikethroughStyle) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: newStrikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewStrikethroughColor_newStrikethroughColorIsUsed() { + let newStrikethroughColor = UIColor.blue + let newTextStyle = textStyle.with(newStrikethroughColor: newStrikethroughColor) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: newStrikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewTextTransform_newTextTransformIsUsed() { + let newTextTransform: TextTransform = .uppercased + let newTextStyle = textStyle.with(newTextTransform: newTextTransform) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: newTextTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + +} diff --git a/Marker/Classes/TextStyle+Extensions.swift b/Marker/Classes/TextStyle+Extensions.swift new file mode 100644 index 0000000..2ecb0aa --- /dev/null +++ b/Marker/Classes/TextStyle+Extensions.swift @@ -0,0 +1,108 @@ +// +// TextStyle+Extensions.swift +// Marker +// +// Created by Harlan Kellaway on 7/7/17. +// Copyright © 2017 Prolific Interactive. All rights reserved. +// + +import UIKit + +/// Adds factory functions producing new TextStyle from existing TextStyle. +public extension TextStyle { + + /// Creates new TextStyle from exisiting TextStyle, updating with provided values.Creates + /// + /// - Parameter newFont: New font to use. + /// - Returns: New TextStyle. + public func with(newFont: UIFont? = nil, + newEmFont: UIFont? = nil, + newStrongFont: UIFont? = nil, + newTextColor: UIColor? = nil, + newCharacterSpacing: CGFloat? = nil, + newLineSpacing: CGFloat? = nil, + newLineHeightMultiple: CGFloat? = nil, + newMinimumLineHeight: CGFloat? = nil, + newMaximumLineHeight: CGFloat? = nil, + newFirstLineHeadIndent: CGFloat? = nil, + newHeadIndent: CGFloat? = nil, + newParagraphSpacing: CGFloat? = nil, + newParagraphSpacingBefore: CGFloat? = nil, + newTextAlignment: NSTextAlignment? = nil, + newLineBreakMode: NSLineBreakMode? = nil, + newStrikethroughStyle: NSUnderlineStyle? = nil, + newStrikethroughColor: UIColor? = nil, + newTextTransform: TextTransform? = nil) -> TextStyle { + let fontToUse = (newFont == nil) ? self.font : newFont! + let emFontToUse = (newEmFont == nil) ? self.emFont : newEmFont! + let strongFontToUse = (newStrongFont == nil) ? self.strongFont : newStrongFont! + let textColorToUse = (newTextColor == nil) ? self.textColor : newTextColor! + let characterSpacingToUse = (newCharacterSpacing == nil) ? self.characterSpacing : newCharacterSpacing! + let lineSpacingToUse = (newLineSpacing == nil) ? self.lineSpacing : newLineSpacing! + let lineHeightMultipleToUse = (newLineHeightMultiple == nil) ? self.lineHeightMultiple : newLineHeightMultiple! + let minimumLineHeightToUse = (newMinimumLineHeight == nil) ? self.minimumLineHeight : newMinimumLineHeight! + let maximumLineHeightToUse = (newMaximumLineHeight == nil) ? self.maximumLineHeight : newMaximumLineHeight! + let firstLineHeadIndentToUse = (newFirstLineHeadIndent == nil) ? self.firstLineHeadIndent : newFirstLineHeadIndent! + let headIndentToUse = (newHeadIndent == nil) ? self.headIndent : newHeadIndent! + let paragraphSpacingToUse = (newParagraphSpacing == nil) ? self.paragraphSpacing : newParagraphSpacing! + let paragraphSpacingBeforeToUse = (newParagraphSpacingBefore == nil) ? self.paragraphSpacingBefore : newParagraphSpacingBefore! + let textAlignmentToUse = (newTextAlignment == nil) ? self.textAlignment : newTextAlignment! + let lineBreakModeToUse = (newLineBreakMode == nil) ? self.lineBreakMode : newLineBreakMode! + let strikethroughStyleToUse = (newStrikethroughStyle == nil) ? self.strikethroughStyle : newStrikethroughStyle! + let strikethroughColorToUse = (newStrikethroughColor == nil) ? self.strikethroughColor : newStrikethroughColor! + let textTransformToUse = (newTextTransform == nil) ? self.textTransform : newTextTransform! + + return TextStyle( + font: fontToUse, + emFont: emFontToUse, + strongFont: strongFontToUse, + textColor: textColorToUse, + characterSpacing: characterSpacingToUse, + lineSpacing: lineSpacingToUse, + lineHeightMultiple: lineHeightMultipleToUse, + minimumLineHeight: minimumLineHeightToUse, + maximumLineHeight: maximumLineHeightToUse, + firstLineHeadIndent: firstLineHeadIndentToUse, + headIndent: headIndentToUse, + paragraphSpacing: paragraphSpacingToUse, + paragraphSpacingBefore: paragraphSpacingBeforeToUse, + textAlignment: textAlignmentToUse, + lineBreakMode: lineBreakModeToUse, + strikethroughStyle: strikethroughStyleToUse, + strikethroughColor: strikethroughColorToUse, + textTransform: textTransformToUse + ) + } + +} + +// MARK: - Protocol conformance + +// MARK: Equatable + +extension TextStyle: Equatable { } + +public func ==(lhs: TextStyle, rhs: TextStyle) -> Bool { + guard lhs.font == rhs.font, + lhs.emFont == rhs.emFont, + lhs.strongFont == rhs.strongFont, + lhs.textColor == rhs.textColor, + lhs.characterSpacing == rhs.characterSpacing, + lhs.lineSpacing == rhs.lineSpacing, + lhs.lineHeightMultiple == rhs.lineHeightMultiple, + lhs.minimumLineHeight == rhs.minimumLineHeight, + lhs.maximumLineHeight == rhs.maximumLineHeight, + lhs.firstLineHeadIndent == rhs.firstLineHeadIndent, + lhs.headIndent == rhs.headIndent, + lhs.paragraphSpacing == rhs.paragraphSpacing, + lhs.paragraphSpacingBefore == rhs.paragraphSpacingBefore, + lhs.textAlignment == rhs.textAlignment, + lhs.lineBreakMode == rhs.lineBreakMode, + lhs.strikethroughStyle == rhs.strikethroughStyle, + lhs.strikethroughColor == rhs.strikethroughColor, + lhs.textTransform == rhs.textTransform else { + return false + } + + return true +} diff --git a/Marker/Classes/TextTransform+Extensions.swift b/Marker/Classes/TextTransform+Extensions.swift new file mode 100644 index 0000000..2a579a2 --- /dev/null +++ b/Marker/Classes/TextTransform+Extensions.swift @@ -0,0 +1,28 @@ +// +// TextTransform+Extensions.swift +// Marker +// +// Created by Harlan Kellaway on 7/7/17. +// Copyright © 2017 Prolific Interactive. All rights reserved. +// + +import Foundation + +// MARK: - Protocol conformance + +// MARK: Equatable + +extension TextTransform: Equatable { } + +public func ==(lhs: TextTransform, rhs: TextTransform) -> Bool { + switch (lhs, rhs) { + case (.none, .none): + return true + case (.lowercased, .lowercased): + return true + case (.uppercased, .uppercased): + return true + default: + return false + } +} From a2c6d0c23405ef4465da6ba9cb04aa205025b51d Mon Sep 17 00:00:00 2001 From: Harlan Kellaway Date: Fri, 7 Jul 2017 13:23:08 -0400 Subject: [PATCH 02/10] Added TextStyle factory functions for bold/italic --- .../Tests/TextStyleFactoryFunctionTests.swift | 48 +++++++++++++++++++ Marker/Classes/TextStyle+Extensions.swift | 38 +++++++++++++-- 2 files changed, 83 insertions(+), 3 deletions(-) diff --git a/Example/Tests/TextStyleFactoryFunctionTests.swift b/Example/Tests/TextStyleFactoryFunctionTests.swift index 66ddc7e..92ec30c 100644 --- a/Example/Tests/TextStyleFactoryFunctionTests.swift +++ b/Example/Tests/TextStyleFactoryFunctionTests.swift @@ -493,4 +493,52 @@ class TextStyleFactoryFunctionTests: XCTestCase { XCTAssertEqual(newTextStyle, expectedTextStyle) } + func testTextStyleFactory_whenBolded_fontIsBold() { + let newTextStyle = textStyle.bold() + let expectedTextStyle = TextStyle(font: textStyle.strongFont, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenItalicized_fontIsitalic() { + let newTextStyle = textStyle.italic() + let expectedTextStyle = TextStyle(font: textStyle.emFont, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + } diff --git a/Marker/Classes/TextStyle+Extensions.swift b/Marker/Classes/TextStyle+Extensions.swift index 2ecb0aa..86b6182 100644 --- a/Marker/Classes/TextStyle+Extensions.swift +++ b/Marker/Classes/TextStyle+Extensions.swift @@ -11,10 +11,28 @@ import UIKit /// Adds factory functions producing new TextStyle from existing TextStyle. public extension TextStyle { - /// Creates new TextStyle from exisiting TextStyle, updating with provided values.Creates + /// Creates new TextStyle from exisiting TextStyle, updating with provided values. /// - /// - Parameter newFont: New font to use. - /// - Returns: New TextStyle. + /// - Parameters: + /// - newFont: New font. + /// - newEmFont: New emphasis font. + /// - newStrongFont: New strong font. + /// - newTextColor: New text color. + /// - newCharacterSpacing: New character spacing. + /// - newLineSpacing: New line spacing. + /// - newLineHeightMultiple: New line height multiple. + /// - newMinimumLineHeight: New minimum line height. + /// - newMaximumLineHeight: New maximum line height. + /// - newFirstLineHeadIndent: New first line head indent. + /// - newHeadIndent: New head indent. + /// - newParagraphSpacing: New paragraph spacing. + /// - newParagraphSpacingBefore: New paragraph spacing before. + /// - newTextAlignment: New text alignment. + /// - newLineBreakMode: New line break mode. + /// - newStrikethroughStyle: New strikethrough style. + /// - newStrikethroughColor: New strikethrough color. + /// - newTextTransform: New text transform. + /// - Returns: New Text Style with updated value(s). public func with(newFont: UIFont? = nil, newEmFont: UIFont? = nil, newStrongFont: UIFont? = nil, @@ -74,6 +92,20 @@ public extension TextStyle { ) } + /// Creates new TextStyle from exisiting TextStyle, replacing font with bold variation. + /// + /// - Returns: New TextStyle with updated font. + public func bold() -> TextStyle { + return self.with(newFont: strongFont) + } + + /// Creates new TextStyle from exisiting TextStyle, replacing font with italic variation. + /// + /// - Returns: New TextStyle with updated font. + public func italic() -> TextStyle { + return self.with(newFont: emFont) + } + } // MARK: - Protocol conformance From a0065fe23021078611b5be0d0f8b4fe9f2ee5c2f Mon Sep 17 00:00:00 2001 From: Harlan Kellaway Date: Fri, 7 Jul 2017 13:48:17 -0400 Subject: [PATCH 03/10] Added equality tests for TextStyle and TextTransform --- Example/Marker.xcodeproj/project.pbxproj | 8 ++ Example/Tests/TextStyleEquatableTests.swift | 110 ++++++++++++++++++ .../Tests/TextTransformEquatableTests.swift | 33 ++++++ Marker/Classes/TextTransform+Extensions.swift | 2 + 4 files changed, 153 insertions(+) create mode 100644 Example/Tests/TextStyleEquatableTests.swift create mode 100644 Example/Tests/TextTransformEquatableTests.swift diff --git a/Example/Marker.xcodeproj/project.pbxproj b/Example/Marker.xcodeproj/project.pbxproj index 701710f..20e5abb 100644 --- a/Example/Marker.xcodeproj/project.pbxproj +++ b/Example/Marker.xcodeproj/project.pbxproj @@ -8,6 +8,8 @@ /* Begin PBXBuildFile section */ 2FC3E7E41F0FC57E0024E2D1 /* TextStyleFactoryFunctionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FC3E7E21F0FC5500024E2D1 /* TextStyleFactoryFunctionTests.swift */; }; + 2FC3E7E71F0FFB2B0024E2D1 /* TextStyleEquatableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FC3E7E51F0FFB220024E2D1 /* TextStyleEquatableTests.swift */; }; + 2FC3E7EA1F0FFEF90024E2D1 /* TextTransformEquatableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FC3E7E81F0FFEEC0024E2D1 /* TextTransformEquatableTests.swift */; }; 4811C04D1D0B6FB5007279CB /* AppTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4811C04C1D0B6FB5007279CB /* AppTheme.swift */; }; 485ED1131D09E89F00119D5D /* AvenirNextFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = 485ED1121D09E89F00119D5D /* AvenirNextFont.swift */; }; 485ED1181D0A091800119D5D /* ThemeSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 485ED1171D0A091800119D5D /* ThemeSettingsViewController.swift */; }; @@ -40,6 +42,8 @@ 1E6E60D0D2F5667C8156B123 /* Pods_Marker_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Marker_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 2408A1D80FB40943D0B15C58 /* Pods-Marker_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Marker_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Marker_Tests/Pods-Marker_Tests.debug.xcconfig"; sourceTree = ""; }; 2FC3E7E21F0FC5500024E2D1 /* TextStyleFactoryFunctionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextStyleFactoryFunctionTests.swift; sourceTree = ""; }; + 2FC3E7E51F0FFB220024E2D1 /* TextStyleEquatableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextStyleEquatableTests.swift; sourceTree = ""; }; + 2FC3E7E81F0FFEEC0024E2D1 /* TextTransformEquatableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextTransformEquatableTests.swift; sourceTree = ""; }; 31D2DC9BD8B466270B5299FF /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 4811C04C1D0B6FB5007279CB /* AppTheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppTheme.swift; sourceTree = ""; }; 485ED1121D09E89F00119D5D /* AvenirNextFont.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvenirNextFont.swift; sourceTree = ""; }; @@ -175,7 +179,9 @@ isa = PBXGroup; children = ( 486EC7691DB440D3009BCA7A /* ParserTests.swift */, + 2FC3E7E51F0FFB220024E2D1 /* TextStyleEquatableTests.swift */, 2FC3E7E21F0FC5500024E2D1 /* TextStyleFactoryFunctionTests.swift */, + 2FC3E7E81F0FFEEC0024E2D1 /* TextTransformEquatableTests.swift */, 607FACE91AFB9204008FA782 /* Supporting Files */, ); path = Tests; @@ -417,7 +423,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2FC3E7EA1F0FFEF90024E2D1 /* TextTransformEquatableTests.swift in Sources */, 486EC76B1DB440E8009BCA7A /* ParserTests.swift in Sources */, + 2FC3E7E71F0FFB2B0024E2D1 /* TextStyleEquatableTests.swift in Sources */, 2FC3E7E41F0FC57E0024E2D1 /* TextStyleFactoryFunctionTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Example/Tests/TextStyleEquatableTests.swift b/Example/Tests/TextStyleEquatableTests.swift new file mode 100644 index 0000000..daed37b --- /dev/null +++ b/Example/Tests/TextStyleEquatableTests.swift @@ -0,0 +1,110 @@ +// +// TextStyleEquatableTests.swift +// Marker +// +// Created by Harlan Kellaway on 7/7/17. +// +// + +import UIKit +import XCTest +@testable import Marker + +class TextStyleEquatableTests: XCTestCase { + + var textStyle: TextStyle! + + override func setUp() { + super.setUp() + + textStyle = TextStyle(font: UIFont(name: "Helvetica", size: 10)!, + emFont: UIFont(name: "Helvetica-Oblique", size: 10)!, + strongFont: UIFont(name: "Helvetica-Bold", size: 10)!, + textColor: UIColor.red, + characterSpacing: 1, + lineSpacing: 2, + lineHeightMultiple: 3, + minimumLineHeight: 4, + maximumLineHeight: 5, + firstLineHeadIndent: 6, + headIndent: 7, + paragraphSpacing: 8, + paragraphSpacingBefore: 9, + textAlignment: .left, + lineBreakMode: .byWordWrapping, + strikethroughStyle: .styleSingle, + strikethroughColor: UIColor.red, + textTransform: .lowercased) + } + + override func tearDown() { + textStyle = nil + + super.tearDown() + } + + func testTextStyle_isEqual_whenAllPropertiesTheSame() { + let sameTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(textStyle, sameTextStyle) + } + + func testTextStyle_isNotEqual_whenPropertiesAreDiffernt() { + let differentFont = textStyle.with(newFont: textStyle.font.withSize(textStyle.font.pointSize + 10)) + let differentEmFont = textStyle.with(newEmFont: textStyle.emFont.withSize(textStyle.emFont.pointSize + 10)) + let differentStrongFont = textStyle.with(newStrongFont: textStyle.strongFont.withSize(textStyle.strongFont.pointSize + 10)) + let differentTextColor = textStyle.with(newTextColor: UIColor.blue) + let differentCharacterSpacing = textStyle.with(newCharacterSpacing: textStyle.characterSpacing! + 10) + let differentLineSpacing = textStyle.with(newLineSpacing: textStyle.lineSpacing! + 10) + let differentLineHeightMultiple = textStyle.with(newLineHeightMultiple: textStyle.lineHeightMultiple! + 10) + let differentMinimumLineHeight = textStyle.with(newMinimumLineHeight: textStyle.minimumLineHeight! + 10) + let differentMaximumLineHeight = textStyle.with(newMaximumLineHeight: textStyle.maximumLineHeight! + 10) + let differentFirstLineHeadIndent = textStyle.with(newFirstLineHeadIndent: textStyle.firstLineHeadIndent! + 10) + let differentHeadIndent = textStyle.with(newHeadIndent: textStyle.headIndent! + 10) + let differentParagraphSpacing = textStyle.with(newParagraphSpacing: textStyle.paragraphSpacing! + 10) + let differentParagraphSpacingBefore = textStyle.with(newParagraphSpacingBefore: textStyle.paragraphSpacingBefore! + 10) + let differentTextAlignment = textStyle.with(newTextAlignment: .right) + let differentLineBreakMode = textStyle.with(newLineBreakMode: .byCharWrapping) + let differentStrikethroughStyle = textStyle.with(newStrikethroughStyle: .styleDouble) + let differentStrikethroughColor = textStyle.with(newStrikethroughColor: UIColor.blue) + let differentTextTransform = textStyle.with(newTextTransform: .uppercased) + + + XCTAssertNotEqual(textStyle, differentFont) + XCTAssertNotEqual(textStyle, differentEmFont) + XCTAssertNotEqual(textStyle, differentStrongFont) + XCTAssertNotEqual(textStyle, differentTextColor) + XCTAssertNotEqual(textStyle, differentCharacterSpacing) + XCTAssertNotEqual(textStyle, differentLineSpacing) + XCTAssertNotEqual(textStyle, differentLineHeightMultiple) + XCTAssertNotEqual(textStyle, differentMinimumLineHeight) + XCTAssertNotEqual(textStyle, differentMaximumLineHeight) + XCTAssertNotEqual(textStyle, differentFirstLineHeadIndent) + XCTAssertNotEqual(textStyle, differentHeadIndent) + XCTAssertNotEqual(textStyle, differentParagraphSpacing) + XCTAssertNotEqual(textStyle, differentParagraphSpacingBefore) + XCTAssertNotEqual(textStyle, differentTextAlignment) + XCTAssertNotEqual(textStyle, differentLineBreakMode) + XCTAssertNotEqual(textStyle, differentStrikethroughStyle) + XCTAssertNotEqual(textStyle, differentStrikethroughColor) + XCTAssertNotEqual(textStyle, differentTextTransform) + } + +} diff --git a/Example/Tests/TextTransformEquatableTests.swift b/Example/Tests/TextTransformEquatableTests.swift new file mode 100644 index 0000000..a0724c9 --- /dev/null +++ b/Example/Tests/TextTransformEquatableTests.swift @@ -0,0 +1,33 @@ +// +// TextTransformEquatableTests.swift +// Marker +// +// Created by Harlan Kellaway on 7/7/17. +// +// + +import UIKit +import XCTest +@testable import Marker + +class TextTransformEquatableTests: XCTestCase { + + func testTextStyle_isEqual_whenSameValue_andNotCustom() { + let none: TextTransform = .none + let lowercased: TextTransform = .lowercased + let uppercased: TextTransform = .uppercased + let capitalized: TextTransform = .capitalized + + XCTAssertEqual(none, none) + XCTAssertEqual(lowercased, lowercased) + XCTAssertEqual(uppercased, uppercased) + XCTAssertEqual(capitalized, capitalized) + } + + func testTextStyle_isNotEqual_whenCustom() { + let custom: TextTransform = .custom({ string in "\(string) \(string)" }) + + XCTAssertNotEqual(custom, custom) + } + +} diff --git a/Marker/Classes/TextTransform+Extensions.swift b/Marker/Classes/TextTransform+Extensions.swift index 2a579a2..c445758 100644 --- a/Marker/Classes/TextTransform+Extensions.swift +++ b/Marker/Classes/TextTransform+Extensions.swift @@ -22,6 +22,8 @@ public func ==(lhs: TextTransform, rhs: TextTransform) -> Bool { return true case (.uppercased, .uppercased): return true + case (.capitalized, .capitalized): + return true default: return false } From 75410784e2fac787a5daf457c564b8d4e208893b Mon Sep 17 00:00:00 2001 From: Harlan Kellaway Date: Fri, 7 Jul 2017 14:09:35 -0400 Subject: [PATCH 04/10] Added TextStyle factor function for new font size --- .../Tests/TextStyleFactoryFunctionTests.swift | 25 +++++++++++++++++++ Marker/Classes/TextStyle+Extensions.swift | 12 +++++++++ 2 files changed, 37 insertions(+) diff --git a/Example/Tests/TextStyleFactoryFunctionTests.swift b/Example/Tests/TextStyleFactoryFunctionTests.swift index 92ec30c..22f37e7 100644 --- a/Example/Tests/TextStyleFactoryFunctionTests.swift +++ b/Example/Tests/TextStyleFactoryFunctionTests.swift @@ -493,6 +493,31 @@ class TextStyleFactoryFunctionTests: XCTestCase { XCTAssertEqual(newTextStyle, expectedTextStyle) } + func testTextStyleFactory_whenNewFontSize_allFontsHaveNewSize() { + let newFontSize = textStyle.font.pointSize + 10 + let newTextStyle = textStyle.with(newFontSize: newFontSize) + let expectedTextStyle = TextStyle(font: textStyle.font.withSize(newFontSize), + emFont: textStyle.emFont.withSize(newFontSize), + strongFont: textStyle.strongFont.withSize(newFontSize), + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + func testTextStyleFactory_whenBolded_fontIsBold() { let newTextStyle = textStyle.bold() let expectedTextStyle = TextStyle(font: textStyle.strongFont, diff --git a/Marker/Classes/TextStyle+Extensions.swift b/Marker/Classes/TextStyle+Extensions.swift index 86b6182..54c7fd8 100644 --- a/Marker/Classes/TextStyle+Extensions.swift +++ b/Marker/Classes/TextStyle+Extensions.swift @@ -92,6 +92,18 @@ public extension TextStyle { ) } + /// Creates new TextStyle from exisiting TextStyle, updating fonts with new size. + /// + /// - Parameter newFontSize: New font size. + /// - Returns: New TextStyle. + public func with(newFontSize: CGFloat) -> TextStyle { + return self.with( + newFont: self.font.withSize(newFontSize), + newEmFont: self.emFont.withSize(newFontSize), + newStrongFont: self.strongFont.withSize(newFontSize) + ) + } + /// Creates new TextStyle from exisiting TextStyle, replacing font with bold variation. /// /// - Returns: New TextStyle with updated font. From ae79f9a7cee188f86dd1448c9c0fd4f235bba66b Mon Sep 17 00:00:00 2001 From: Harlan Kellaway Date: Fri, 7 Jul 2017 17:18:59 -0400 Subject: [PATCH 05/10] Added support for underline --- Marker/Classes/Marker.swift | 11 +++++++++++ Marker/Classes/Parser/MarkdownElement.swift | 4 ++++ Marker/Classes/Parser/MarkdownParser.swift | 9 +++++++-- Marker/Classes/TextStyle.swift | 12 ++++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/Marker/Classes/Marker.swift b/Marker/Classes/Marker.swift index 1ab3dfa..3dfc555 100644 --- a/Marker/Classes/Marker.swift +++ b/Marker/Classes/Marker.swift @@ -61,6 +61,7 @@ public func parsedMarkdownString(from markdownText: String, elements.forEach { (element) in var font: UIFont? = nil var strikethroughStyle: NSUnderlineStyle? = nil + var underlineStyle: NSUnderlineStyle? = nil switch element { case .em(_): @@ -69,6 +70,8 @@ public func parsedMarkdownString(from markdownText: String, font = textStyle.strongFont case .strikethrough(_): strikethroughStyle = textStyle.strikethroughStyle + case .underline(_): + underlineStyle = textStyle.underlineStyle } if let font = font { @@ -84,6 +87,14 @@ public func parsedMarkdownString(from markdownText: String, range: parsedString.range(from: element.range)) } } + + if let underlineStyle = underlineStyle { + attributedString.addAttributes([NSUnderlineStyleAttributeName: underlineStyle.rawValue], range: parsedString.range(from: element.range)) + + if let underlineColor = textStyle.underlineColor { + attributedString.addAttributes([NSUnderlineColorAttributeName: underlineColor], range: parsedString.range(from: element.range)) + } + } } return attributedString diff --git a/Marker/Classes/Parser/MarkdownElement.swift b/Marker/Classes/Parser/MarkdownElement.swift index 9457ec9..61bc2f5 100644 --- a/Marker/Classes/Parser/MarkdownElement.swift +++ b/Marker/Classes/Parser/MarkdownElement.swift @@ -13,11 +13,13 @@ import Foundation /// - em: Emphasis element. /// - strong: Strong element. /// - strikethrough: Strikethrough element. +/// - underline: Underline element. internal enum MarkdownElement { case em(Range) case strong(Range) case strikethrough(Range) + case underline(Range) /// Range of characters that the elements apply to. var range: Range { @@ -28,6 +30,8 @@ internal enum MarkdownElement { return range case .strikethrough(let range): return range + case .underline(let range): + return range } } diff --git a/Marker/Classes/Parser/MarkdownParser.swift b/Marker/Classes/Parser/MarkdownParser.swift index e1aa33c..75aeca5 100644 --- a/Marker/Classes/Parser/MarkdownParser.swift +++ b/Marker/Classes/Parser/MarkdownParser.swift @@ -27,6 +27,7 @@ internal struct MarkdownParser { private static let underscoreStrongSymbol = Symbol(rawValue: "__") private static let asteriskStrongSymbol = Symbol(rawValue: "**") private static let tildeStrikethroughSymbol = Symbol(rawValue: "~~") + private static let equalUnderlineSymbol = Symbol(rawValue: "==") // MARK: - Static functions @@ -41,7 +42,8 @@ internal struct MarkdownParser { let asteriskEmSymbol = asteriskEmSymbol, let underscoreStrongSymbol = underscoreStrongSymbol, let asteriskStrongSymbol = asteriskStrongSymbol, - let tildeStrikethroughSymbol = tildeStrikethroughSymbol else { + let tildeStrikethroughSymbol = tildeStrikethroughSymbol, + let equalUnderlineSymbol = equalUnderlineSymbol else { return (string, []) } @@ -53,6 +55,8 @@ internal struct MarkdownParser { return .strong(element.range) case tildeStrikethroughSymbol: return .strikethrough(element.range) + case equalUnderlineSymbol: + return .underline(element.range) default: throw ParserError.invalidTagSymbol } @@ -63,7 +67,8 @@ internal struct MarkdownParser { asteriskEmSymbol, underscoreStrongSymbol, asteriskStrongSymbol, - tildeStrikethroughSymbol]) + tildeStrikethroughSymbol, + equalUnderlineSymbol]) return try (strippedString, elements.map(transformToMarkdownElement)) } diff --git a/Marker/Classes/TextStyle.swift b/Marker/Classes/TextStyle.swift index 461c18b..a364aab 100644 --- a/Marker/Classes/TextStyle.swift +++ b/Marker/Classes/TextStyle.swift @@ -67,6 +67,12 @@ public struct TextStyle { /// Stroke color for strikethough text. public var strikethroughColor: UIColor? + /// Underline style for underlined text.s + public var underlineStyle: NSUnderlineStyle? + + /// Stroke color for underlined text. + public var underlineColor: UIColor? + /// Text transform. public var textTransform: TextTransform @@ -145,6 +151,8 @@ public struct TextStyle { - parameter lineBreakMode: Line break node. - parameter strikethroughStyle: Strikethrough style. - parameter strikethroughColor: Strikethrough color. + - parameter underlineStyle: Underline style. + - parameter underlineColor: Underline color.s - parameter textTransform: Text transform option. - returns: An initialized text style object. @@ -166,6 +174,8 @@ public struct TextStyle { lineBreakMode: NSLineBreakMode? = nil, strikethroughStyle: NSUnderlineStyle? = nil, strikethroughColor: UIColor? = nil, + underlineStyle: NSUnderlineStyle? = nil, + underlineColor: UIColor? = nil, textTransform: TextTransform = .none) { self.font = font self.emFont = (emFont == nil) ? font : emFont! @@ -184,6 +194,8 @@ public struct TextStyle { self.lineBreakMode = lineBreakMode self.strikethroughStyle = strikethroughStyle self.strikethroughColor = strikethroughColor + self.underlineStyle = underlineStyle + self.underlineColor = underlineColor self.textTransform = textTransform } } From 39427b7d9603abef33303bc4ce505b17c2426f3f Mon Sep 17 00:00:00 2001 From: Harlan Kellaway Date: Fri, 7 Jul 2017 17:27:06 -0400 Subject: [PATCH 06/10] Added underline properties to factory helper --- .../Tests/TextStyleFactoryFunctionTests.swift | 98 +++++++++++++++++++ Marker/Classes/TextStyle+Extensions.swift | 10 ++ Marker/Classes/TextStyle.swift | 2 +- 3 files changed, 109 insertions(+), 1 deletion(-) diff --git a/Example/Tests/TextStyleFactoryFunctionTests.swift b/Example/Tests/TextStyleFactoryFunctionTests.swift index 22f37e7..37c74c8 100644 --- a/Example/Tests/TextStyleFactoryFunctionTests.swift +++ b/Example/Tests/TextStyleFactoryFunctionTests.swift @@ -34,6 +34,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: .byWordWrapping, strikethroughStyle: .styleSingle, strikethroughColor: UIColor.red, + underlineStyle: .styleSingle, + underlineColor: UIColor.red, textTransform: .lowercased) } @@ -63,6 +65,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -88,6 +92,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -113,6 +119,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -138,6 +146,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -163,6 +173,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -188,6 +200,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -213,6 +227,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -238,6 +254,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -263,6 +281,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -288,6 +308,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -313,6 +335,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -338,6 +362,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -363,6 +389,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -388,6 +416,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -413,6 +443,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: newLineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -438,6 +470,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: newStrikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -463,6 +497,62 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: newStrikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewUnderlineStyle_newUnderlineStyleIsUsed() { + let newUnderlineStyle: NSUnderlineStyle = .styleDouble + let newTextStyle = textStyle.with(newUnderlineStyle: newUnderlineStyle) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + underlineStyle: newUnderlineStyle, + underlineColor: textStyle.underlineColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenNewUnderlineColor_newUnderlineColorIsUsed() { + let newUnderlineColor = UIColor.blue + let newTextStyle = textStyle.with(newUnderlineColor: newUnderlineColor) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: newUnderlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -488,6 +578,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: newTextTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -513,6 +605,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -537,6 +631,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) @@ -561,6 +657,8 @@ class TextStyleFactoryFunctionTests: XCTestCase { lineBreakMode: textStyle.lineBreakMode, strikethroughStyle: textStyle.strikethroughStyle, strikethroughColor: textStyle.strikethroughColor, + underlineStyle: textStyle.underlineStyle, + underlineColor: textStyle.underlineColor, textTransform: textStyle.textTransform) XCTAssertEqual(newTextStyle, expectedTextStyle) diff --git a/Marker/Classes/TextStyle+Extensions.swift b/Marker/Classes/TextStyle+Extensions.swift index 54c7fd8..dcf6d63 100644 --- a/Marker/Classes/TextStyle+Extensions.swift +++ b/Marker/Classes/TextStyle+Extensions.swift @@ -31,6 +31,8 @@ public extension TextStyle { /// - newLineBreakMode: New line break mode. /// - newStrikethroughStyle: New strikethrough style. /// - newStrikethroughColor: New strikethrough color. + /// - newUnderlineStyle: New underline style. + /// - newUnderlineColor: New underline color. /// - newTextTransform: New text transform. /// - Returns: New Text Style with updated value(s). public func with(newFont: UIFont? = nil, @@ -50,6 +52,8 @@ public extension TextStyle { newLineBreakMode: NSLineBreakMode? = nil, newStrikethroughStyle: NSUnderlineStyle? = nil, newStrikethroughColor: UIColor? = nil, + newUnderlineStyle: NSUnderlineStyle? = nil, + newUnderlineColor: UIColor? = nil, newTextTransform: TextTransform? = nil) -> TextStyle { let fontToUse = (newFont == nil) ? self.font : newFont! let emFontToUse = (newEmFont == nil) ? self.emFont : newEmFont! @@ -68,6 +72,8 @@ public extension TextStyle { let lineBreakModeToUse = (newLineBreakMode == nil) ? self.lineBreakMode : newLineBreakMode! let strikethroughStyleToUse = (newStrikethroughStyle == nil) ? self.strikethroughStyle : newStrikethroughStyle! let strikethroughColorToUse = (newStrikethroughColor == nil) ? self.strikethroughColor : newStrikethroughColor! + let underlineStyleToUse = (newUnderlineStyle == nil) ? self.underlineStyle : newUnderlineStyle! + let underlineColorToUse = (newUnderlineColor == nil) ? self.underlineColor : newUnderlineColor! let textTransformToUse = (newTextTransform == nil) ? self.textTransform : newTextTransform! return TextStyle( @@ -88,6 +94,8 @@ public extension TextStyle { lineBreakMode: lineBreakModeToUse, strikethroughStyle: strikethroughStyleToUse, strikethroughColor: strikethroughColorToUse, + underlineStyle: underlineStyleToUse, + underlineColor: underlineColorToUse, textTransform: textTransformToUse ) } @@ -144,6 +152,8 @@ public func ==(lhs: TextStyle, rhs: TextStyle) -> Bool { lhs.lineBreakMode == rhs.lineBreakMode, lhs.strikethroughStyle == rhs.strikethroughStyle, lhs.strikethroughColor == rhs.strikethroughColor, + lhs.underlineStyle == rhs.underlineStyle, + lhs.underlineColor == rhs.underlineColor, lhs.textTransform == rhs.textTransform else { return false } diff --git a/Marker/Classes/TextStyle.swift b/Marker/Classes/TextStyle.swift index a364aab..84dc6b6 100644 --- a/Marker/Classes/TextStyle.swift +++ b/Marker/Classes/TextStyle.swift @@ -67,7 +67,7 @@ public struct TextStyle { /// Stroke color for strikethough text. public var strikethroughColor: UIColor? - /// Underline style for underlined text.s + /// Underline style for underlined text. public var underlineStyle: NSUnderlineStyle? /// Stroke color for underlined text. From b285c752691e978959ac847a1f9073b1db680a7e Mon Sep 17 00:00:00 2001 From: Harlan Kellaway Date: Fri, 7 Jul 2017 17:39:34 -0400 Subject: [PATCH 07/10] Added parser tests --- Example/Tests/ParserTests.swift | 56 ++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/Example/Tests/ParserTests.swift b/Example/Tests/ParserTests.swift index 9aef4aa..adfac3f 100644 --- a/Example/Tests/ParserTests.swift +++ b/Example/Tests/ParserTests.swift @@ -60,24 +60,42 @@ class ParserTests: XCTestCase { } } + func testParseUnderlinedElements() { + do { + let (parsedString, parsedElements) = try MarkdownParser.parse("==abc== def ==ghi==") + + XCTAssert(parsedString == "abc def ghi") + XCTAssert(parsedElements.count == 2) + + parsedElements.forEach { XCTAssert($0.isUnderlinedElement()) } + + XCTAssert(parsedElements[0].range == parsedString.range(of: "abc")) + XCTAssert(parsedElements[1].range == parsedString.range(of: "ghi")) + } catch { + XCTFail("Parsing failed.") + } + } + func testParseMixedElements() { do { - let (parsedString, parsedElements) = try MarkdownParser.parse("*abc* __def__ _ghi_ **jkl** ~~mno~~") + let (parsedString, parsedElements) = try MarkdownParser.parse("*abc* __def__ _ghi_ **jkl** ~~mno~~ ==pqr==") - XCTAssert(parsedString == "abc def ghi jkl mno") - XCTAssert(parsedElements.count == 5) + XCTAssert(parsedString == "abc def ghi jkl mno pqr") + XCTAssert(parsedElements.count == 6) XCTAssert(parsedElements[0].isEmElement()) XCTAssert(parsedElements[1].isStrongElement()) XCTAssert(parsedElements[2].isEmElement()) XCTAssert(parsedElements[3].isStrongElement()) XCTAssert(parsedElements[4].isStrikethroughElement()) + XCTAssert(parsedElements[5].isUnderlinedElement()) XCTAssert(parsedElements[0].range == parsedString.range(of: "abc")) XCTAssert(parsedElements[1].range == parsedString.range(of: "def")) XCTAssert(parsedElements[2].range == parsedString.range(of: "ghi")) XCTAssert(parsedElements[3].range == parsedString.range(of: "jkl")) XCTAssert(parsedElements[4].range == parsedString.range(of: "mno")) + XCTAssert(parsedElements[5].range == parsedString.range(of: "pqr")) } catch { XCTFail("Parsing failed.") } @@ -116,22 +134,35 @@ class ParserTests: XCTestCase { } } + func testLiteralEqual() { + do { + let (parsedString, parsedElements) = try MarkdownParser.parse("two + two = four") + + XCTAssert(parsedString == "two + two = four") + XCTAssert(parsedElements.count == 0) + } catch { + XCTFail("Parsing failed.") + } + } + func testElementsInMiddleOfWords() { do { - let (parsedString, parsedElements) = try MarkdownParser.parse("the_quick_brown*fox*jumps__over__the**lazy**dog.") + let (parsedString, parsedElements) = try MarkdownParser.parse("the_quick_brown*fox*jumps__over__the**lazy**==dog==.") XCTAssert(parsedString == "thequickbrownfoxjumpsoverthelazydog.") - XCTAssert(parsedElements.count == 4) + XCTAssert(parsedElements.count == 5) XCTAssert(parsedElements[0].isEmElement()) XCTAssert(parsedElements[1].isEmElement()) XCTAssert(parsedElements[2].isStrongElement()) XCTAssert(parsedElements[3].isStrongElement()) + XCTAssert(parsedElements[4].isUnderlinedElement()) XCTAssert(parsedElements[0].range == parsedString.range(of: "quick")) XCTAssert(parsedElements[1].range == parsedString.range(of: "fox")) XCTAssert(parsedElements[2].range == parsedString.range(of: "over")) XCTAssert(parsedElements[3].range == parsedString.range(of: "lazy")) + XCTAssert(parsedElements[4].range == parsedString.range(of: "dog")) } catch { XCTFail("Parsing failed.") } @@ -163,6 +194,12 @@ class ParserTests: XCTestCase { } catch { XCTAssert(error as! ElementParser.ParserError == ElementParser.ParserError.unclosedTags) } + + do { + let _ = try MarkdownParser.parse("Not ==correct.") + } catch { + XCTAssert(error as! ElementParser.ParserError == ElementParser.ParserError.unclosedTags) + } } } @@ -196,4 +233,13 @@ private extension MarkdownElement { } } + func isUnderlinedElement() -> Bool { + switch self { + case .underline(_): + return true + default: + return false + } + } + } From fb6ce38343c5bae8c1263470cd3b436bfab19d77 Mon Sep 17 00:00:00 2001 From: Harlan Kellaway Date: Fri, 7 Jul 2017 18:58:36 -0400 Subject: [PATCH 08/10] Updated README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4128ab5..f5b64bc 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ Marker abstracts the most common attributed text properties into a data object c * Text alignment * Line break mode * Strikethrough style and color +* Underline style and color * Text transformation option `TextStyle` objects are a simple way of aggregating style information. For example: @@ -94,6 +95,7 @@ Marker also supports setting text with common Markdown tags: * Bold (`__` or `**`) * Italic (`_` or `*`) * Strikethrough (`~~`) +* Underline (`==`) To set Markdown text on these elements, use `setMarkdownText(_:using:)` (or `setMarkdownTitleText(_:using:)` for `UIButton`) function. From fb7e77e9f3e75c9d5101eda35e36a4f8dc6841dc Mon Sep 17 00:00:00 2001 From: Harlan Kellaway Date: Mon, 10 Jul 2017 13:09:23 -0400 Subject: [PATCH 09/10] Added TextStyle factory function for underline --- .../Tests/TextStyleFactoryFunctionTests.swift | 56 +++++++++++++++++++ Marker/Classes/TextStyle+Extensions.swift | 11 ++++ 2 files changed, 67 insertions(+) diff --git a/Example/Tests/TextStyleFactoryFunctionTests.swift b/Example/Tests/TextStyleFactoryFunctionTests.swift index 37c74c8..50c9ebb 100644 --- a/Example/Tests/TextStyleFactoryFunctionTests.swift +++ b/Example/Tests/TextStyleFactoryFunctionTests.swift @@ -664,4 +664,60 @@ class TextStyleFactoryFunctionTests: XCTestCase { XCTAssertEqual(newTextStyle, expectedTextStyle) } + func testTextStyleFactory_whenUnderlined_underlinePropertiesAreSet() { + let underlineStyle: NSUnderlineStyle = .styleDouble + let underlineColor = UIColor.green + let newTextStyle = textStyle.underlined(color: underlineColor, style: underlineStyle) + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + underlineStyle: underlineStyle, + underlineColor: underlineColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + + func testTextStyleFactory_whenUnderlined_defaultsToSingleLineOfSameColor() { + let expectedStyle: NSUnderlineStyle = .styleSingle + let expectedColor = textStyle.textColor + let newTextStyle = textStyle.underlined() + let expectedTextStyle = TextStyle(font: textStyle.font, + emFont: textStyle.emFont, + strongFont: textStyle.strongFont, + textColor: textStyle.textColor, + characterSpacing: textStyle.characterSpacing, + lineSpacing: textStyle.lineSpacing, + lineHeightMultiple: textStyle.lineHeightMultiple, + minimumLineHeight: textStyle.minimumLineHeight, + maximumLineHeight: textStyle.maximumLineHeight, + firstLineHeadIndent: textStyle.firstLineHeadIndent, + headIndent: textStyle.headIndent, + paragraphSpacing: textStyle.paragraphSpacing, + paragraphSpacingBefore: textStyle.paragraphSpacingBefore, + textAlignment: textStyle.textAlignment, + lineBreakMode: textStyle.lineBreakMode, + strikethroughStyle: textStyle.strikethroughStyle, + strikethroughColor: textStyle.strikethroughColor, + underlineStyle: expectedStyle, + underlineColor: expectedColor, + textTransform: textStyle.textTransform) + + XCTAssertEqual(newTextStyle, expectedTextStyle) + } + } diff --git a/Marker/Classes/TextStyle+Extensions.swift b/Marker/Classes/TextStyle+Extensions.swift index dcf6d63..aa00569 100644 --- a/Marker/Classes/TextStyle+Extensions.swift +++ b/Marker/Classes/TextStyle+Extensions.swift @@ -126,6 +126,17 @@ public extension TextStyle { return self.with(newFont: emFont) } + /// Creates new Text Style from exisiting TextStyle, with underline. + /// + /// - Parameter color: Underline color. Defaults to textColor. + /// - Parameter style: Underline style. Defaults to single line. + /// - Returns: New TextStyle with underline. + public func underlined(color: UIColor? = nil, style: NSUnderlineStyle = .styleSingle) -> TextStyle { + return self + .with(newUnderlineStyle: style) + .with(newUnderlineColor: color ?? textColor) + } + } // MARK: - Protocol conformance From d9dcade30c57fda8f2930ca177fef1a9cea20be4 Mon Sep 17 00:00:00 2001 From: Harlan Kellaway Date: Mon, 10 Jul 2017 14:43:33 -0400 Subject: [PATCH 10/10] Updated README --- Marker/Classes/TextStyle.swift | 2 +- README.md | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Marker/Classes/TextStyle.swift b/Marker/Classes/TextStyle.swift index 84dc6b6..dcc7745 100644 --- a/Marker/Classes/TextStyle.swift +++ b/Marker/Classes/TextStyle.swift @@ -152,7 +152,7 @@ public struct TextStyle { - parameter strikethroughStyle: Strikethrough style. - parameter strikethroughColor: Strikethrough color. - parameter underlineStyle: Underline style. - - parameter underlineColor: Underline color.s + - parameter underlineColor: Underline color. - parameter textTransform: Text transform option. - returns: An initialized text style object. diff --git a/README.md b/README.md index f5b64bc..af98818 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,9 @@ Marker also supports setting text with common Markdown tags: * Bold (`__` or `**`) * Italic (`_` or `*`) + +As well as convenient Markdown tags specific to Marker: + * Strikethrough (`~~`) * Underline (`==`)