Skip to content

Commit 9e83d77

Browse files
Merge pull request #1237 from wordpress-mobile/issue/fix_color_attributes
Fix copy/paste of attributed string from app without support for dark/light mode
2 parents fb48f65 + 5698366 commit 9e83d77

4 files changed

Lines changed: 75 additions & 8 deletions

File tree

Aztec/Classes/TextKit/TextView.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,12 +242,20 @@ open class TextView: UITextView {
242242
.font: defaultFont,
243243
.paragraphStyle: defaultParagraphStyle,
244244
]
245-
if let color = textColor {
245+
if let color = defaultTextColor {
246246
attributes[.foregroundColor] = color
247247
}
248248
return attributes
249249
}
250-
250+
251+
open lazy var defaultTextColor: UIColor? = {
252+
if #available(iOS 13.0, *) {
253+
return UIColor.label
254+
} else {
255+
return UIColor.darkText
256+
}
257+
}()
258+
251259
// MARK: - Plugin Loading
252260

253261
var pluginManager: PluginManager {
@@ -637,7 +645,7 @@ open class TextView: UITextView {
637645
evaluateRemovalOfSingleLineParagraphAttributesAfterSelectionChange()
638646
ensureRemovalOfParagraphAttributesWhenPressingBackspaceAndEmptyingTheDocument()
639647
ensureCursorRedraw(afterEditing: deletedString.string)
640-
648+
recalculateTypingAttributes()
641649
notifyTextViewDidChange()
642650
}
643651

@@ -1237,6 +1245,7 @@ open class TextView: UITextView {
12371245
private func recalculateTypingAttributes(at location: Int) {
12381246

12391247
guard storage.length > 0 else {
1248+
typingAttributes = defaultAttributes
12401249
return
12411250
}
12421251

Aztec/Classes/TextKit/TextViewPasteboardDelegate.swift

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ open class AztecTextViewPasteboardDelegate: TextViewPasteboardDelegate {
5858
guard let string = UIPasteboard.general.attributedString() else {
5959
return false
6060
}
61-
61+
string.loadLazyAttachments()
6262
let selectedRange = textView.selectedRange
6363
let storage = textView.storage
6464

@@ -69,9 +69,9 @@ open class AztecTextViewPasteboardDelegate: TextViewPasteboardDelegate {
6969
textView?.undoTextReplacement(of: originalText, finalRange: finalRange)
7070
})
7171

72-
string.loadLazyAttachments()
72+
let colorCorrectedString = fixColors(in: string, using: textView.defaultTextColor)
7373

74-
storage.replaceCharacters(in: selectedRange, with: string)
74+
storage.replaceCharacters(in: selectedRange, with: colorCorrectedString)
7575
textView.notifyTextViewDidChange()
7676

7777
let newSelectedRange = NSRange(location: selectedRange.location + string.length, length: 0)
@@ -80,6 +80,21 @@ open class AztecTextViewPasteboardDelegate: TextViewPasteboardDelegate {
8080
return true
8181
}
8282

83+
private func fixColors(in string: NSAttributedString, using baseColor: UIColor?) -> NSAttributedString {
84+
guard #available(iOS 13.0, *) else {
85+
return string
86+
}
87+
let colorToUse = baseColor ?? UIColor.label
88+
89+
let newString = NSMutableAttributedString(attributedString: string)
90+
newString.enumerateAttributes(in: newString.rangeOfEntireString, options: []) { (attributes, range, stop) in
91+
if attributes[.foregroundColor] == nil {
92+
newString.setAttributes([.foregroundColor: colorToUse], range: range)
93+
}
94+
}
95+
return newString
96+
}
97+
8398
/// Tries to paste raw text from the clipboard, replacing the selected range.
8499
///
85100
/// - Returns: True if the paste succeeds, false if it does not.

AztecTests/TextKit/TextViewTests.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2078,4 +2078,32 @@ class TextViewTests: XCTestCase {
20782078
XCTAssertEqual(UIPasteboard.general.html(), "<p><strong>bol</strong></p>")
20792079
}
20802080

2081+
/// Check if pasting attributed text without color, the color is set to default color
2082+
func testPasteAttributedText() {
2083+
let sourceAttributedText = NSAttributedString(string: "Hello world")
2084+
var pasteItems = [String:Any]()
2085+
pasteItems[kUTTypePlainText as String] = try! sourceAttributedText.data(from: sourceAttributedText.rangeOfEntireString, documentAttributes: [.documentType: DocumentType.plain])
2086+
UIPasteboard.general.setItems([pasteItems], options: [:])
2087+
let textView = TextViewStub(withHTML: "")
2088+
textView.defaultTextColor = UIColor.red
2089+
textView.paste(nil)
2090+
2091+
let attributedString = textView.attributedText!
2092+
2093+
let attributes = attributedString.attributes(at: 0, effectiveRange: nil)
2094+
2095+
XCTAssertEqual(attributes[.foregroundColor] as! UIColor, UIColor.red)
2096+
XCTAssertEqual(textView.text, "Hello world")
2097+
}
2098+
2099+
/// Check that deleting all text resets the typying attributes to the default attributes
2100+
func testDeleteAllTextSetTypyingAttributesToDefault() {
2101+
let textView = TextViewStub(withHTML: "<p style=\"color:0xFF0000\">Hello world</p>")
2102+
textView.defaultTextColor = UIColor.green
2103+
textView.selectedRange = textView.attributedText!.rangeOfEntireString
2104+
textView.deleteBackward()
2105+
let attributes = textView.typingAttributes
2106+
XCTAssertEqual(attributes[.foregroundColor] as! UIColor,UIColor.green)
2107+
}
2108+
20812109
}

Example/Example/EditorDemoController.swift

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class EditorDemoController: UIViewController {
6565

6666
private func setupHTMLTextView(_ textView: UITextView) {
6767
let accessibilityLabel = NSLocalizedString("HTML Content", comment: "Post HTML content")
68-
self.configureDefaultProperties(for: textView, accessibilityLabel: accessibilityLabel)
68+
self.configureDefaultProperties(htmlTextView: textView, accessibilityLabel: accessibilityLabel)
6969

7070
textView.isHidden = true
7171
textView.delegate = self
@@ -325,7 +325,22 @@ class EditorDemoController: UIViewController {
325325
}
326326

327327

328-
private func configureDefaultProperties(for textView: UITextView, accessibilityLabel: String) {
328+
private func configureDefaultProperties(for textView: TextView, accessibilityLabel: String) {
329+
textView.accessibilityLabel = accessibilityLabel
330+
textView.font = Constants.defaultContentFont
331+
textView.keyboardDismissMode = .interactive
332+
if #available(iOS 13.0, *) {
333+
textView.textColor = UIColor.label
334+
textView.defaultTextColor = UIColor.label
335+
} else {
336+
// Fallback on earlier versions
337+
textView.textColor = UIColor(red: 0x1A/255.0, green: 0x1A/255.0, blue: 0x1A/255.0, alpha: 1)
338+
textView.defaultTextColor = UIColor(red: 0x1A/255.0, green: 0x1A/255.0, blue: 0x1A/255.0, alpha: 1)
339+
}
340+
textView.linkTextAttributes = [.foregroundColor: UIColor(red: 0x01 / 255.0, green: 0x60 / 255.0, blue: 0x87 / 255.0, alpha: 1), NSAttributedString.Key.underlineStyle: NSNumber(value: NSUnderlineStyle.single.rawValue)]
341+
}
342+
343+
private func configureDefaultProperties(htmlTextView textView: UITextView, accessibilityLabel: String) {
329344
textView.accessibilityLabel = accessibilityLabel
330345
textView.font = Constants.defaultContentFont
331346
textView.keyboardDismissMode = .interactive

0 commit comments

Comments
 (0)