Skip to content
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

Implement copy/paste of images in the file/binary format #810

Merged
merged 12 commits into from
Apr 5, 2019
2,875 changes: 1,509 additions & 1,366 deletions bundle/android/App.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion bundle/android/App.js.map

Large diffs are not rendered by default.

2,885 changes: 1,514 additions & 1,371 deletions bundle/ios/App.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion bundle/ios/App.js.map

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions ios/gutenberg/GutenbergViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ extension GutenbergViewController: GutenbergBridgeDelegate {
}
}

func gutenbergDidRequestImport(from url: URL, with callback: @escaping MediaPickerDidPickMediaCallback) {
let id = mediaUploadCoordinator.upload(url: url)
callback(id, url.absoluteString)
}

func pickAndUpload(from source: UIImagePickerController.SourceType, callback: @escaping MediaPickerDidPickMediaCallback) {
mediaPickCoordinator = MediaPickCoordinator(presenter: self, callback: { (url) in
guard let url = url, let mediaID = self.mediaUploadCoordinator.upload(url: url) else {
Expand Down
30 changes: 28 additions & 2 deletions react-native-aztec/ios/RNTAztecView/RCTAztecView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,30 @@ class RCTAztecView: Aztec.TextView {

return String(data: data, encoding: .utf8)
}

func saveToDisk(image: UIImage) -> URL? {
let fileName = "\(ProcessInfo.processInfo.globallyUniqueString)_file.jpg"

guard let data = image.jpegData(compressionQuality: 0.9) else {
return nil
}

let fileURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)

guard (try? data.write(to: fileURL, options: [.atomic])) != nil else {
return nil
}

return fileURL
}

private func images(from pasteboard: UIPasteboard) -> [String] {
guard let images = pasteboard.images else {
return []
}
let imagesURLs = images.compactMap({ saveToDisk(image: $0)?.absoluteString })
return imagesURLs
}

override func paste(_ sender: Any?) {
let start = selectedRange.location
Expand All @@ -190,13 +214,15 @@ class RCTAztecView: Aztec.TextView {
let pasteboard = UIPasteboard.general
let text = self.text(from: pasteboard) ?? ""
let html = self.html(from: pasteboard) ?? ""

let imagesURLs = self.images(from: pasteboard)

onPaste?([
"currentContent": getHTML(),
"selectionStart": start,
"selectionEnd": end,
"pastedText": text,
"pastedHtml": html])
"pastedHtml": html,
"files": imagesURLs] )
}

// MARK: - Edits
Expand Down
4 changes: 4 additions & 0 deletions react-native-gutenberg-bridge/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ export function requestMediaPickFromDeviceCamera( callback ) {
return RNReactNativeGutenbergBridge.requestMediaPickFrom( 'DEVICE_CAMERA', callback );
}

export function requestMediaImport( url, callback ) {
return RNReactNativeGutenbergBridge.requestMediaImport( url, callback );
}

export function mediaUploadSync() {
return RNReactNativeGutenbergBridge.mediaUploadSync();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ public protocol GutenbergBridgeDelegate: class {
///
func gutenbergDidRequestMedia(from source: MediaPickerSource, with callback: @escaping MediaPickerDidPickMediaCallback)

/// Tells the delegate that gutenberg JS requested the import of media item based on the provided URL
///
/// - Parameters:
/// - url: the url to import
/// - callback: A callback block to be called with an upload mediaIdentifier and a placeholder image file url, use nil on both parameters to signal that the action has failed.
//
func gutenbergDidRequestImport(from url: URL, with callback: @escaping MediaPickerDidPickMediaCallback)

/// Tells the delegate that an image block requested to reconnect with media uploads coordinator.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ @interface RCT_EXTERN_MODULE(RNReactNativeGutenbergBridge, NSObject)
RCT_EXTERN_METHOD(requestImageFailedRetryDialog:(int)mediaID)
RCT_EXTERN_METHOD(requestImageUploadCancelDialog:(int)mediaID)
RCT_EXTERN_METHOD(requestImageUploadCancel:(int)mediaID)
RCT_EXTERN_METHOD(requestMediaImport:(NSString *)sourceURL callback:(RCTResponseSenderBlock)callback)
RCT_EXTERN_METHOD(editorDidLayout)
RCT_EXTERN_METHOD(editorDidMount:(BOOL)hasUnsupportedBlocks)
RCT_EXTERN_METHOD(editorDidEmitLog:(NSString *)message logLevel:(int)logLevel)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,23 @@ public class RNReactNativeGutenbergBridge: RCTEventEmitter {
}
}

@objc
func requestMediaImport(_ urlString: String, callback: @escaping RCTResponseSenderBlock) {
guard let url = URL(string: urlString) else {
callback(nil)
return
}
DispatchQueue.main.async {
self.delegate?.gutenbergDidRequestImport(from: url, with: { (mediaID, url) in
guard let url = url, let mediaID = mediaID else {
callback(nil)
return
}
callback([mediaID, url])
})
}
}

@objc
func mediaUploadSync() {
DispatchQueue.main.async {
Expand Down