-
Notifications
You must be signed in to change notification settings - Fork 4.3k
/
Copy pathGutenbergBridgeDelegate.swift
272 lines (225 loc) · 10.7 KB
/
GutenbergBridgeDelegate.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
public struct MediaInfo: Encodable {
public let id: Int32?
public let url: String?
public let type: String?
public let title: String?
public let caption: String?
public init(id: Int32?, url: String?, type: String?, caption: String? = nil, title: String? = nil) {
self.id = id
self.url = url
self.type = type
self.caption = caption
self.title = title
}
}
/// Definition of capabilities to enable in the Block Editor
public enum Capabilities: String {
case mediaFilesCollectionBlock
case mentions
case xposts
case unsupportedBlockEditor
case canEnableUnsupportedBlockEditor
case modalLayoutPicker
}
/// Wrapper for single block data
public struct Block {
/// Gutenberg internal block ID
public let id: String
/// Gutenberg internal block name
public let name: String
/// User facing block name string (localized)
public let title: String
/// Block HTML content
public let content: String
/// Creates a copy of the receiver modifying only its content field.
/// - Parameter newContent: The content for the new block instance.
/// - Returns: A new block instance with copied fields and new content.
public func replacingContent(with newContent: String) -> Block {
Block(id: id, name: name, title: title, content: newContent)
}
}
public struct ContentInfo {
public let characterCount: Int
public let wordCount: Int
public let paragraphCount: Int
public let blockCount: Int
}
extension ContentInfo {
static func decode(from dict: [String: Int]) -> ContentInfo? {
guard let characters = dict["characterCount"],
let words = dict["wordCount"],
let paragraphs = dict["paragraphCount"],
let blocks = dict["blockCount"] else {
return nil
}
return ContentInfo(characterCount: characters, wordCount: words, paragraphCount: paragraphs, blockCount: blocks)
}
}
public typealias MediaPickerDidPickMediaCallback = (_ media: [MediaInfo]?) -> Void
public typealias MediaImportCallback = (_ media: MediaInfo?) -> Void
/// Declare internal Media Sources.
/// Label and Type are not relevant since they are delcared on the JS side.
/// Hopefully soon, this will need to be declared on the client side.
extension Gutenberg.MediaSource {
public static let mediaLibrary = Gutenberg.MediaSource(id: "SITE_MEDIA_LIBRARY", label: "", types: [.image, .video])
public static let deviceLibrary = Gutenberg.MediaSource(id: "DEVICE_MEDIA_LIBRARY", label: "", types: [.image, .video])
public static let deviceCamera = Gutenberg.MediaSource(id: "DEVICE_CAMERA", label: "", types: [.image, .video])
static var registeredInternalSources: [Gutenberg.MediaSource] {
return [
.deviceCamera,
.deviceLibrary,
.mediaLibrary,
]
}
}
/// Ref. https://github.com/facebook/react-native/blob/master/Libraries/polyfills/console.js#L376
public enum LogLevel: Int {
case trace
case info
case warn
case error
case fatal
}
// Avoid possible future problems due to log level int value changes.
extension LogLevel {
init (_ rnLogLevel: RCTLogLevel) {
switch rnLogLevel {
case .trace: self = .trace
case .info: self = .info
case .warning: self = .warn
case .error: self = .error
case .fatal: self = .fatal
@unknown default:
assertionFailure("Unknown log level: \(rnLogLevel)")
self = .trace
}
}
}
extension RCTLogLevel {
init(_ logLevel: LogLevel) {
switch logLevel {
case .trace: self = .trace
case .info: self = .info
case .warn: self = .warning
case .error: self = .error
case .fatal: self = .fatal
}
}
}
public enum GutenbergUserEvent {
case editorSessionTemplateApply(_ template: String)
case editorSessionTemplatePreview(_ template: String)
init?(event: String, properties:[AnyHashable: Any]?) {
switch event {
case "editor_session_template_apply":
guard let template = properties?["template"] as? String else { return nil }
self = .editorSessionTemplateApply(template)
case "editor_session_template_preview":
guard let template = properties?["template"] as? String else { return nil }
self = .editorSessionTemplatePreview(template)
default:
return nil
}
}
}
public protocol GutenbergBridgeDelegate: class {
/// Tells the delegate that Gutenberg had returned the requested HTML content.
/// You can request HTML content by calling `requestHTML()` on a Gutenberg bridge instance.
///
/// - Parameters:
/// - title: the title as shown by the editor.
/// - html: The current HTML presented by the editor.
/// - changed: True if the given HTML presents changes from the last request or initial value.
/// - contentInfo: Information about the post content: characters, words, paragraphs, blocks.
func gutenbergDidProvideHTML(title: String, html: String, changed: Bool, contentInfo: ContentInfo?)
/// Tells the delegate that an image block requested an image from the media picker.
///
/// - Parameters:
/// - source: the source from where the picker will get the media
/// - callback: A callback block to be called with an array of upload mediaIdentifiers and a placeholder images file url, use nil on both parameters to signal that the action was canceled.
///
func gutenbergDidRequestMedia(from source: Gutenberg.MediaSource, filter: [Gutenberg.MediaType], allowMultipleSelection: Bool, 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 array of upload mediaIdentifiers and a placeholder images file url, use nil on both parameters to signal that the action has failed.
//
func gutenbergDidRequestImport(from url: URL, with callback: @escaping MediaImportCallback)
/// Tells the delegate that an image block requested to reconnect with media uploads coordinator.
///
func gutenbergDidRequestMediaUploadSync()
/// Tells the delegate that an image block requested for the actions available for the media upload.
///
func gutenbergDidRequestMediaUploadActionDialog(for mediaID: Int32)
/// Tells the delegate that an image block requested for the upload cancelation.
///
func gutenbergDidRequestMediaUploadCancelation(for mediaID: Int32)
/// Tells the delegate that the Gutenberg module has finished loading.
///
func gutenbergDidLoad()
/// Tells the delegate every time the editor has finished layout.
///
func gutenbergDidLayout()
/// Tells the delegate that the editor view has completed the initial render.
/// - Parameters:
/// - unsupportedBlockNames: A list of loaded block names that are not supported.
///
func gutenbergDidMount(unsupportedBlockNames: [String])
/// Tells the delegate that logger method is called.
///
func gutenbergDidEmitLog(message: String, logLevel: LogLevel)
/// Tells the delegate that the editor has sent an autosave event.
///
func editorDidAutosave()
/// Tells the delegate that the editor needs to perform a network request.
/// The paths given to perform the request are from the WP ORG REST API.
/// https://developer.wordpress.org/rest-api/reference/
/// - Parameter path: The path to perform the request.
/// - Parameter completion: Completion handler to be called with the result or an error.
func gutenbergDidRequestFetch(path: String, completion: @escaping (Swift.Result<Any, NSError>) -> Void)
/// Tells the delegate to display a fullscreen image from a given URL
///
func gutenbergDidRequestImagePreview(with mediaUrl: URL, thumbUrl: URL?)
/// Tells the delegate to display the media editor from a given URL
///
func gutenbergDidRequestMediaEditor(with mediaUrl: URL, callback: @escaping MediaPickerDidPickMediaCallback)
/// Tells the delegate that the editor needs to log a custom event
/// - Parameter event: The event key to be logged
func gutenbergDidLogUserEvent(_ event: GutenbergUserEvent)
/// Tells the delegate that the editor needs to render an unsupported block
func gutenbergDidRequestUnsupportedBlockFallback(for block: Block)
/// Tells the delegate that the editor requested a mention
/// - Parameter callback: Completion handler to be called with an user mention or an error
func gutenbergDidRequestMention(callback: @escaping (Swift.Result<String, NSError>) -> Void)
/// Tells the delegate that the editor requested a mention
/// - Parameter callback: Completion handler to be called with an xpost or an error
func gutenbergDidRequestXpost(callback: @escaping (Swift.Result<String, NSError>) -> Void)
/// Tells the delegate that the editor requested to show the tooltip
func gutenbergDidRequestStarterPageTemplatesTooltipShown() -> Bool
/// Tells the delegate that the editor requested to set the tooltip's visibility
/// - Parameter tooltipShown: Tooltip's visibility value
func gutenbergDidRequestSetStarterPageTemplatesTooltipShown(_ tooltipShown: Bool)
func gutenbergDidSendButtonPressedAction(_ buttonType: Gutenberg.ActionButtonType)
// Media Collection
/// Tells the delegate that a media collection block requested to reconnect with media save coordinator.
///
func gutenbergDidRequestMediaSaveSync()
func gutenbergDidRequestMediaFilesEditorLoad(_ mediaFiles: [String], blockId: String)
func gutenbergDidRequestMediaFilesFailedRetryDialog(_ mediaFiles: [String])
func gutenbergDidRequestMediaFilesUploadCancelDialog(_ mediaFiles: [String])
func gutenbergDidRequestMediaFilesSaveCancelDialog(_ mediaFiles: [String])
}
// MARK: - Optional GutenbergBridgeDelegate methods
public extension GutenbergBridgeDelegate {
func gutenbergDidLoad() { }
func gutenbergDidLayout() { }
func gutenbergDidRequestUnsupportedBlockFallback(for block: Block) { }
func gutenbergDidSendButtonPressedAction(_ buttonType: Gutenberg.ActionButtonType) { }
// Media Collection
func gutenbergDidRequestMediaSaveSync() {}
func gutenbergDidRequestMediaFilesEditorLoad(_ mediaFiles: [String], blockId: String) { }
func gutenbergDidRequestMediaFilesFailedRetryDialog(_ mediaFiles: [String]) { }
func gutenbergDidRequestMediaFilesUploadCancelDialog(_ mediaFiles: [String]) { }
func gutenbergDidRequestMediaFilesSaveCancelDialog(_ mediaFiles: [String]) { }
}