-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue/1045 paste of attributed strings #1097
Changes from 10 commits
08e996e
f9186ca
440e60c
4580317
d181c81
f9eef7b
eb23f13
0061b1e
f75b3c1
26883a1
157345c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
github "wordpress-mobile/AztecEditor-iOS" "fff3d4712c6971cd2673fce273c8e9d9330a15ca" | ||
github "wordpress-mobile/AztecEditor-iOS" "1.7.0" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
github "wordpress-mobile/AztecEditor-iOS" "fff3d4712c6971cd2673fce273c8e9d9330a15ca" | ||
github "wordpress-mobile/AztecEditor-iOS" "1.7.0" |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -178,26 +178,41 @@ class RCTAztecView: Aztec.TextView { | |
} | ||
|
||
// MARK: - Paste handling | ||
|
||
private func html(from pasteboard: UIPasteboard) -> String? { | ||
guard let data = pasteboard.data(forPasteboardType: kUTTypeHTML as String) else { | ||
return nil | ||
private func read(from pasteboard: UIPasteboard, uti: CFString, documentType: DocumentType) -> String? { | ||
guard let data = pasteboard.data(forPasteboardType: uti as String), | ||
let attributedString = try? NSAttributedString(data: data, options: [.documentType: documentType], documentAttributes: nil), | ||
let storage = self.textStorage as? TextStorage else { | ||
return nil | ||
} | ||
|
||
return String(data: data, encoding: .utf8) | ||
return storage.getHTML(from: attributedString) | ||
} | ||
|
||
private func text(from pasteboard: UIPasteboard) -> String? { | ||
guard let data = pasteboard.data(forPasteboardType: kUTTypePlainText as String) else { | ||
return nil | ||
|
||
private func readHTML(from pasteboard: UIPasteboard) -> String? { | ||
|
||
if let data = pasteboard.data(forPasteboardType: kUTTypeHTML as String), let html = String(data: data, encoding: .utf8) { | ||
// Make sure we are not getting a full HTML DOC. We only want inner content | ||
if !html.hasPrefix("<!DOCTYPE html") { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm doing this check here to check if we are not importing a full HTML document because on my tests I found that the when copying from the Notes app, it was sending the full HTML document, using My assumption is that when importing HTML if a full document is there, maybe there is content there is not valid or importable to GB so instead we should try to read RTF. If we think that this is not a good assumption we can remove this line, but then import from the Notes app will not work. For the record when pasting from Safari, it provide only the selected HTML and not the full document so the import from HTML works correctly. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
FWIW, code exists on GB side to handle inline styles on span tags, however, the limitations of our DOM implementation (jsdom-jscore) prevent it from working correctly. To "enable" this code path, we'd need the style property on
It's possible that implementing the necessary DOM spec will require significant time / effort. I think your approach is good to mitigate the underlying problem (that our DOM implementation is insufficient). I wonder if wrapping the html in a "full document" is correlated with using inline styles on spans, or if Notes.app happens to behave this way, and other apps have differing behavior regarding these two characteristics. Is there some way to directly check if the pasteboard html generated by the external app uses inline styles on span tags? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I agree with this!
I just tested the Google docs app, and it happens that it does use inline styles on spans, but without wrapping it up on a full HTML document. So this approach doesn't work for it. But it does work for the Notes app. I'm OK with shipping this improvement to support the Apple default's Note app, and check for a more wide alternative later on. What do you think @SergioEstevao ? |
||
return html | ||
} | ||
} | ||
|
||
return String(data: data, encoding: .utf8) | ||
} | ||
|
||
private func cleanHTML() -> String { | ||
let html = getHTML(prettify: false) | ||
return html | ||
if let flatRTFDString = read(from: pasteboard, uti: kUTTypeFlatRTFD, documentType: DocumentType.rtfd) { | ||
return flatRTFDString | ||
} | ||
|
||
if let rtfString = read(from: pasteboard, uti: kUTTypeRTF, documentType: DocumentType.rtf) { | ||
return rtfString | ||
} | ||
|
||
if let rtfdString = read(from: pasteboard, uti: kUTTypeRTFD, documentType: DocumentType.rtfd) { | ||
return rtfdString | ||
} | ||
|
||
return nil | ||
} | ||
|
||
private func readText(from pasteboard: UIPasteboard) -> String? { | ||
return pasteboard.string | ||
} | ||
|
||
func saveToDisk(image: UIImage) -> URL? { | ||
|
@@ -216,7 +231,7 @@ class RCTAztecView: Aztec.TextView { | |
return fileURL | ||
} | ||
|
||
private func images(from pasteboard: UIPasteboard) -> [String] { | ||
private func readImages(from pasteboard: UIPasteboard) -> [String] { | ||
guard let images = pasteboard.images else { | ||
return [] | ||
} | ||
|
@@ -229,9 +244,9 @@ class RCTAztecView: Aztec.TextView { | |
let end = selectedRange.location + selectedRange.length | ||
|
||
let pasteboard = UIPasteboard.general | ||
let text = self.text(from: pasteboard) ?? "" | ||
let html = self.html(from: pasteboard) ?? "" | ||
let imagesURLs = self.images(from: pasteboard) | ||
let text = readText(from: pasteboard) ?? "" | ||
let html = readHTML(from: pasteboard) ?? "" | ||
let imagesURLs = readImages(from: pasteboard) | ||
|
||
onPaste?([ | ||
"currentContent": cleanHTML(), | ||
|
@@ -315,6 +330,11 @@ class RCTAztecView: Aztec.TextView { | |
} | ||
|
||
// MARK: - Native-to-RN Value Packing Logic | ||
|
||
private func cleanHTML() -> String { | ||
let html = getHTML(prettify: false) | ||
return html | ||
} | ||
|
||
func packForRN(_ text: String, withName name: String) -> [AnyHashable: Any] { | ||
return [name: text, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small detail:
uti
is alreadyString
so this extraas String
is not needed.Maybe we can change
uti
's type to beCFString
to make it simpler on the caller side?