Skip to content

Commit 181ebc7

Browse files
Merge pull request #1221 from wordpress-mobile/issue/allow_change_of_default_font
Allow configuration of default fonts used in TextView
2 parents 1b53a74 + fa4c640 commit 181ebc7

9 files changed

Lines changed: 95 additions & 49 deletions

File tree

Aztec.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,10 +231,12 @@
231231
FF24AC991F0146AF003CA91D /* Assets.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF24AC981F0146AF003CA91D /* Assets.swift */; };
232232
FF437B6420D7CB2D000D9666 /* HTMLLi.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF437B6320D7CB2D000D9666 /* HTMLLi.swift */; };
233233
FF437B6620D7CB83000D9666 /* LiFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF437B6520D7CB83000D9666 /* LiFormatter.swift */; };
234+
FF48CAC8234DD5D3007FFC79 /* NSMutableAttributedString+ReplaceAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF48CAC7234DD5D3007FFC79 /* NSMutableAttributedString+ReplaceAttributes.swift */; };
234235
FF4E26601EA8DF1E005E8E42 /* ImageAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4E265F1EA8DF1E005E8E42 /* ImageAttachment.swift */; };
235236
FF61909E202481F4004BCD0A /* CodeFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF61909D202481F4004BCD0A /* CodeFormatter.swift */; };
236237
FF7A1C511E5651EA00C4C7C8 /* LineAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF7A1C501E5651EA00C4C7C8 /* LineAttachment.swift */; };
237238
FF7C89B01E3BC52F000472A8 /* NSAttributedString+FontTraits.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF7C89AF1E3BC52F000472A8 /* NSAttributedString+FontTraits.swift */; };
239+
FF7EAEC4234D253B007A26E0 /* FontProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF7EAEC3234D253B007A26E0 /* FontProvider.swift */; };
238240
FFA61E891DF18F3D00B71BF6 /* ParagraphStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA61E881DF18F3D00B71BF6 /* ParagraphStyle.swift */; };
239241
FFA61EC21DF6C1C900B71BF6 /* NSAttributedString+Archive.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA61EC11DF6C1C900B71BF6 /* NSAttributedString+Archive.swift */; };
240242
FFB5D29720BEB21A0038DCFB /* CiteFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB5D29620BEB21A0038DCFB /* CiteFormatter.swift */; };
@@ -505,6 +507,7 @@
505507
FF24AC981F0146AF003CA91D /* Assets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Assets.swift; sourceTree = "<group>"; };
506508
FF437B6320D7CB2D000D9666 /* HTMLLi.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTMLLi.swift; sourceTree = "<group>"; };
507509
FF437B6520D7CB83000D9666 /* LiFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LiFormatter.swift; sourceTree = "<group>"; };
510+
FF48CAC7234DD5D3007FFC79 /* NSMutableAttributedString+ReplaceAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSMutableAttributedString+ReplaceAttributes.swift"; sourceTree = "<group>"; };
508511
FF4E265F1EA8DF1E005E8E42 /* ImageAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageAttachment.swift; sourceTree = "<group>"; };
509512
FF5B98E21DC29D0C00571CA4 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; };
510513
FF5B98E41DC355B400571CA4 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = SOURCE_ROOT; };
@@ -513,6 +516,7 @@
513516
FF7A1C4A1E51F05700C4C7C8 /* CONTRIBUTING.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = CONTRIBUTING.md; sourceTree = "<group>"; };
514517
FF7A1C501E5651EA00C4C7C8 /* LineAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LineAttachment.swift; sourceTree = "<group>"; };
515518
FF7C89AF1E3BC52F000472A8 /* NSAttributedString+FontTraits.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+FontTraits.swift"; sourceTree = "<group>"; };
519+
FF7EAEC3234D253B007A26E0 /* FontProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontProvider.swift; sourceTree = "<group>"; };
516520
FFA61E881DF18F3D00B71BF6 /* ParagraphStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParagraphStyle.swift; sourceTree = "<group>"; };
517521
FFA61EC11DF6C1C900B71BF6 /* NSAttributedString+Archive.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+Archive.swift"; sourceTree = "<group>"; };
518522
FFB5D29620BEB21A0038DCFB /* CiteFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CiteFormatter.swift; sourceTree = "<group>"; };
@@ -746,6 +750,7 @@
746750
FFD0FEB61DAE59A700430586 /* NSLayoutManager+Attachments.swift */,
747751
F1584795203C9B4C00EE05A1 /* NSMutableAttributedString+ParagraphProperty.swift */,
748752
F10BE6171EA7ADA6002E4625 /* NSMutableAttributedString+ReplaceOcurrences.swift */,
753+
FF48CAC7234DD5D3007FFC79 /* NSMutableAttributedString+ReplaceAttributes.swift */,
749754
F18733C41DA096EE005AEB80 /* NSRange+Helpers.swift */,
750755
FF20D6431EDC395E00294B78 /* NSTextingResult+Helpers.swift */,
751756
F1C05B9C1E37FA77007510EA /* String+CharacterName.swift */,
@@ -804,6 +809,7 @@
804809
FFA61E881DF18F3D00B71BF6 /* ParagraphStyle.swift */,
805810
B5A99D831EBA073D00DED081 /* HTMLStorage.swift */,
806811
F9982CF521877663001E606B /* TextViewPasteboardDelegate.swift */,
812+
FF7EAEC3234D253B007A26E0 /* FontProvider.swift */,
807813
);
808814
path = TextKit;
809815
sourceTree = "<group>";
@@ -1573,6 +1579,7 @@
15731579
F165D92A20C72EF500EAA6B0 /* Array+ShortcodeAttribute.swift in Sources */,
15741580
F165D92420C72C1000EAA6B0 /* ShortcodeAttributeSerializer.swift in Sources */,
15751581
F177FF751FB6404D00CBBE35 /* UILayoutPriority+Swift4.swift in Sources */,
1582+
FF7EAEC4234D253B007A26E0 /* FontProvider.swift in Sources */,
15761583
F1C05B9D1E37FA77007510EA /* String+CharacterName.swift in Sources */,
15771584
F1FF7D9F201A1D24007B0B32 /* Figcaption.swift in Sources */,
15781585
FF17B2D2227A589F0022AECE /* LIElementConverter.swift in Sources */,
@@ -1639,6 +1646,7 @@
16391646
599F25381D8BC9A1002871D6 /* InAttributesConverter.swift in Sources */,
16401647
B551A4A01E770B3800EE3A7F /* UIFont+Emoji.swift in Sources */,
16411648
F13E8AD820B71BAA007C9F8A /* PluginManager.swift in Sources */,
1649+
FF48CAC8234DD5D3007FFC79 /* NSMutableAttributedString+ReplaceAttributes.swift in Sources */,
16421650
F12F586E1EF20394008AE298 /* LinkFormatter.swift in Sources */,
16431651
F1584796203C9B4C00EE05A1 /* NSMutableAttributedString+ParagraphProperty.swift in Sources */,
16441652
F15BA6092151501300424120 /* BoldStringAttributeConverter.swift in Sources */,
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import Foundation
2+
import UIKit
3+
4+
public extension NSMutableAttributedString {
5+
6+
/// Replace all instances of the .font attribute that belong to the same family for the new font, trying to keep the same symbolic traits
7+
/// - Parameter font: the original font to be replaced
8+
/// - Parameter newFont: the new font to use.
9+
func replace(font: UIFont, with newFont: UIFont) {
10+
let fullRange = NSRange(location: 0, length: length)
11+
12+
beginEditing()
13+
enumerateAttributes(in: fullRange, options: []) { (attributes, subrange, stop) in
14+
guard let currentFont = attributes[.font] as? UIFont, currentFont.familyName == font.familyName else {
15+
return
16+
}
17+
var replacementFont = newFont
18+
if let fontDescriptor = newFont.fontDescriptor.withSymbolicTraits(currentFont.fontDescriptor.symbolicTraits) {
19+
replacementFont = UIFont(descriptor: fontDescriptor, size: currentFont.pointSize)
20+
}
21+
addAttribute(.font, value: replacementFont, range: subrange)
22+
}
23+
endEditing()
24+
}
25+
}

Aztec/Classes/Formatters/Implementations/CodeFormatter.swift

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,8 @@ class CodeFormatter: AttributeFormatter {
1212

1313
// MARK: - Init
1414

15-
init(monospaceFont: UIFont = UIFont(descriptor:UIFontDescriptor(name: "Courier", size: 12), size:12), backgroundColor: UIColor = UIColor.lightGray) {
16-
let font: UIFont
17-
18-
if #available(iOS 11.0, *) {
19-
font = UIFontMetrics.default.scaledFont(for: monospaceFont)
20-
} else {
21-
font = monospaceFont
22-
}
23-
self.monospaceFont = font
15+
init(monospaceFont: UIFont = FontProvider.shared.monospaceFont, backgroundColor: UIColor = UIColor.lightGray) {
16+
self.monospaceFont = monospaceFont
2417
self.backgroundColor = backgroundColor
2518
self.htmlRepresentationKey = .codeHtmlRepresentation
2619
}

Aztec/Classes/Formatters/Implementations/PreFormatter.swift

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,10 @@ open class PreFormatter: ParagraphAttributeFormatter {
1414
///
1515
let placeholderAttributes: [NSAttributedString.Key: Any]?
1616

17-
1817
/// Designated Initializer
1918
///
20-
init(monospaceFont: UIFont = UIFont(descriptor:UIFontDescriptor(name: "Courier", size: 12), size:12), placeholderAttributes: [NSAttributedString.Key : Any]? = nil) {
21-
let font: UIFont
22-
23-
if #available(iOS 11.0, *) {
24-
font = UIFontMetrics.default.scaledFont(for: monospaceFont)
25-
} else {
26-
font = monospaceFont
27-
}
28-
29-
self.monospaceFont = font
19+
init(monospaceFont: UIFont = FontProvider.shared.monospaceFont, placeholderAttributes: [NSAttributedString.Key : Any]? = nil) {
20+
self.monospaceFont = monospaceFont
3021
self.placeholderAttributes = placeholderAttributes
3122
}
3223

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import Foundation
2+
import UIKit
3+
4+
public class FontProvider {
5+
6+
private init() {
7+
8+
}
9+
10+
public static var shared = FontProvider()
11+
12+
public lazy var monospaceFont: UIFont = {
13+
let baseFont = UIFont(descriptor:UIFontDescriptor(name: "Menlo", size: 14), size:14)
14+
let font: UIFont
15+
if #available(iOS 11.0, *) {
16+
font = UIFontMetrics.default.scaledFont(for: baseFont)
17+
} else {
18+
font = baseFont
19+
}
20+
return font
21+
}()
22+
23+
public lazy var defaultFont: UIFont = {
24+
let baseFont = UIFont.systemFont(ofSize: 14)
25+
let font: UIFont
26+
if #available(iOS 11.0, *) {
27+
font = UIFontMetrics.default.scaledFont(for: baseFont)
28+
} else {
29+
font = baseFont
30+
}
31+
return font
32+
}()
33+
}

Aztec/Classes/TextKit/LayoutManager.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,11 @@ private extension LayoutManager {
317317
traits.remove(.traitBold)
318318
traits.remove(.traitItalic)
319319

320-
let descriptor = font.fontDescriptor.withSymbolicTraits(traits)
321-
return UIFont(descriptor: descriptor!, size: font.pointSize)
320+
if let descriptor = font.fontDescriptor.withSymbolicTraits(traits) {
321+
return UIFont(descriptor: descriptor, size: font.pointSize)
322+
} else {
323+
// Don't touch the font if we cannot remove the symbolic traits.
324+
return font
325+
}
322326
}
323327
}

Aztec/Classes/TextKit/TextView.swift

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,14 @@ open class TextView: UITextView {
226226

227227
// MARK: - Properties: UI Defaults
228228

229-
public let defaultFont: UIFont
229+
/// The font to use to render any HTML that doesn't specify an explicit font.
230+
/// If this is changed all the instances that use this font will be updated to the new one.
231+
public var defaultFont: UIFont {
232+
didSet {
233+
textStorage.replace(font: oldValue, with: defaultFont)
234+
}
235+
}
236+
230237
public let defaultParagraphStyle: ParagraphStyle
231238
var defaultMissingImage: UIImage
232239

@@ -241,23 +248,6 @@ open class TextView: UITextView {
241248
return attributes
242249
}
243250

244-
/// This closure will be executed whenever the `TextView` needs to set the base style for
245-
/// a caption. Override this to customize the caption styling.
246-
///
247-
public lazy var captionStyler: ([NSAttributedString.Key:Any]) -> [NSAttributedString.Key:Any] = { [weak self] attributes in
248-
guard let `self` = self else {
249-
return attributes
250-
}
251-
252-
let font = self.defaultFont.withSize(10)
253-
254-
var attributes = attributes
255-
attributes[.font] = font
256-
attributes[.foregroundColor] = UIColor.darkGray
257-
258-
return attributes
259-
}
260-
261251
// MARK: - Plugin Loading
262252

263253
var pluginManager: PluginManager {
@@ -371,6 +361,10 @@ open class TextView: UITextView {
371361

372362
// MARK: - Init & deinit
373363

364+
/// Creates a Text View using the provided parameters as a base for HTML rendering.
365+
/// - Parameter defaultFont: The font to use to render the elements if no specific font is set by the HTML.
366+
/// - Parameter defaultParagraphStyle: The default paragraph style if no explicit attributes are defined in HTML
367+
/// - Parameter defaultMissingImage: The image to use if the view is not able to render an image specified in the HTML.
374368
@objc public init(
375369
defaultFont: UIFont,
376370
defaultParagraphStyle: ParagraphStyle = ParagraphStyle.default,
@@ -397,13 +391,7 @@ open class TextView: UITextView {
397391
}
398392

399393
required public init?(coder aDecoder: NSCoder) {
400-
let font = UIFont.systemFont(ofSize: 14)
401-
if #available(iOS 11.0, *) {
402-
self.defaultFont = UIFontMetrics.default.scaledFont(for: font)
403-
} else {
404-
self.defaultFont = font
405-
}
406-
394+
defaultFont = FontProvider.shared.defaultFont
407395
defaultParagraphStyle = ParagraphStyle.default
408396
defaultMissingImage = Assets.imageIcon
409397

AztecTests/TextKit/TextViewTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1673,7 +1673,7 @@ class TextViewTests: XCTestCase {
16731673

16741674
textView.insertText("😘")
16751675
let currentTypingFont = textView.typingAttributes[.font] as! UIFont
1676-
XCTAssertEqual(currentTypingFont, font, "Font should be set to default")
1676+
XCTAssertEqual(currentTypingFont.fontDescriptor, font.fontDescriptor, "Font should be set to default")
16771677
}
16781678

16791679

Example/Example/EditorDemoController.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,11 +195,15 @@ class EditorDemoController: UIViewController {
195195
} else {
196196
html = ""
197197
}
198-
198+
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(changeFont))
199199
editorView.setHTML(html)
200200
editorView.becomeFirstResponder()
201201
}
202202

203+
@objc func changeFont() {
204+
editorView.richTextView.defaultFont = UIFont.preferredFont(forTextStyle: .callout)
205+
}
206+
203207
override func viewWillAppear(_ animated: Bool) {
204208
super.viewWillAppear(animated)
205209

0 commit comments

Comments
 (0)