-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Share Gallery media library handling between GutenbergKit editors #25855
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
Changes from all commits
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 |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| import Foundation | ||
| import GutenbergKit | ||
| import Testing | ||
| import UIKit | ||
|
|
||
| @testable import WordPress | ||
| @testable import WordPressData | ||
|
|
||
| @MainActor | ||
| struct PostGBKEditorViewControllerTests { | ||
|
|
||
| @Test("presents the site media library for GutenbergKit requests") | ||
| func presentsSiteMediaLibrary() throws { | ||
| let context = ContextManager.forTesting().mainContext | ||
| let blog = BlogBuilder(context).build() | ||
| let viewController = PostGBKEditorViewController( | ||
| postId: nil, | ||
| postType: .post, | ||
| title: "", | ||
| content: "", | ||
| status: "draft", | ||
| blog: blog | ||
| ) | ||
| let window = UIWindow() | ||
| window.rootViewController = viewController | ||
| window.makeKeyAndVisible() | ||
| viewController.loadViewIfNeeded() | ||
|
|
||
| let data = Data( | ||
| #"{"allowedTypes":["image"],"multiple":true,"value":[],"contextId":"test"}"#.utf8 | ||
| ) | ||
| let action = try JSONDecoder().decode(OpenMediaLibraryAction.self, from: data) | ||
|
|
||
| viewController.editor( | ||
| viewController.editorViewController, | ||
| didRequestMediaFromSiteMediaLibrary: action | ||
| ) | ||
|
|
||
| let navigation = try #require(viewController.presentedViewController as? UINavigationController) | ||
| #expect(navigation.viewControllers.first is SiteMediaPickerViewController) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ import UIKit | |
| import WebKit | ||
| import SafariServices | ||
| import GutenbergKit | ||
| import WordPressData | ||
| import WordPressShared | ||
| import WordPressUI | ||
|
|
||
|
|
@@ -13,6 +14,8 @@ class PostGBKEditorViewController: UIViewController, GutenbergKit.EditorViewCont | |
| /* private */ let editorViewController: GutenbergKit.EditorViewController | ||
| private let status: String // TODO: Can be deleted? | ||
|
|
||
| private lazy var mediaPickerHelper = GutenbergMediaPickerHelper(context: self, blog: blog) | ||
|
|
||
| private var keyboardShowObserver: Any? | ||
| private var keyboardHideObserver: Any? | ||
| private var keyboardFrame = CGRect.zero | ||
|
|
@@ -200,7 +203,47 @@ class PostGBKEditorViewController: UIViewController, GutenbergKit.EditorViewCont | |
| _ viewController: GutenbergKit.EditorViewController, | ||
| didRequestMediaFromSiteMediaLibrary config: OpenMediaLibraryAction | ||
| ) { | ||
| // Do nothing | ||
| let flags = mediaFilterFlags(using: config.allowedTypes ?? []) | ||
|
|
||
| let initialSelectionArray: [Int] | ||
| switch config.value { | ||
| case .single(let id): | ||
| initialSelectionArray = [id] | ||
| case .multiple(let ids): | ||
| initialSelectionArray = ids | ||
| case .none: | ||
| initialSelectionArray = [] | ||
| } | ||
|
|
||
| mediaPickerHelper.presentSiteMediaPicker( | ||
| filter: flags, | ||
| allowMultipleSelection: config.multiple, | ||
| initialSelection: initialSelectionArray | ||
| ) { [weak self] assets in | ||
| guard let self, let media = assets as? [Media], !media.isEmpty else { | ||
| return | ||
| } | ||
| let mediaInfos = media.map { item in | ||
| var metadata: [String: String] = [:] | ||
| if let videopressGUID = item.videopressGUID { | ||
| metadata["videopressGUID"] = videopressGUID | ||
| } | ||
| return MediaInfo( | ||
| id: item.mediaID?.int32Value, | ||
| url: item.remoteURL, | ||
| type: item.mediaTypeString, | ||
| caption: item.caption, | ||
| title: item.filename, | ||
| alt: item.alt, | ||
| metadata: [:] | ||
| ) | ||
| } | ||
| if let jsonString = convertMediaInfoArrayToJSONString(mediaInfos) { | ||
| // Escape the string for JavaScript | ||
| let escapedJsonString = jsonString.replacingOccurrences(of: "'", with: "\\'") | ||
| editorViewController.setMediaUploadAttachment(escapedJsonString) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| func editor(_ viewController: GutenbergKit.EditorViewController, didTriggerAutocompleter type: String) { | ||
|
|
@@ -244,6 +287,40 @@ class PostGBKEditorViewController: UIViewController, GutenbergKit.EditorViewCont | |
| // Do nothing | ||
| nil | ||
| } | ||
|
|
||
| private func convertMediaInfoArrayToJSONString(_ mediaInfoArray: [MediaInfo]) -> String? { | ||
| do { | ||
| let jsonData = try JSONEncoder().encode(mediaInfoArray) | ||
| if let jsonString = String(data: jsonData, encoding: .utf8) { | ||
| return jsonString | ||
| } | ||
| } catch { | ||
| DDLogError("Error encoding MediaInfo array: \(error)") | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| private func mediaFilterFlags(using filterArray: [OpenMediaLibraryAction.MediaType]) -> GutenbergMediaType { | ||
| var mediaType: Int = 0 | ||
| for filter in filterArray { | ||
| switch filter { | ||
| case .image: | ||
| mediaType = mediaType | GutenbergMediaType.image.rawValue | ||
| case .video: | ||
| mediaType = mediaType | GutenbergMediaType.video.rawValue | ||
| case .audio: | ||
| mediaType = mediaType | GutenbergMediaType.audio.rawValue | ||
| case .other: | ||
| mediaType = mediaType | GutenbergMediaType.other.rawValue | ||
| case .any: | ||
| mediaType = mediaType | GutenbergMediaType.all.rawValue | ||
| @unknown default: | ||
| fatalError() | ||
|
Member
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. Noting a pre-existing issue finding by Claude that we might address in a follow-up PR: Could this
|
||
| } | ||
| } | ||
|
|
||
| return GutenbergMediaType(rawValue: mediaType) | ||
| } | ||
| } | ||
|
|
||
| private extension PostGBKEditorViewController { | ||
|
|
||
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.
Noting a pre-existing issue finding by Claude that we might address in a follow-up PR:
Is passing
metadata: [:]here intentional? Themetadatadict built just above withvideopressGUIDnever gets used, so the GUID is dropped before it reaches the web editor —MediaInfo.metadatais an encoded field. No compiler warning since it is mutated inside theif.Moved verbatim, so pre-existing — but worth flagging since this path now serves custom post types too. Looks like a one-word fix (
metadata: metadata) if you want it here rather than a follow-up.