diff --git a/ios/Sources/GutenbergKit/Sources/EditorConfiguration.swift b/ios/Sources/GutenbergKit/Sources/EditorConfiguration.swift index d66301c3..a6017de4 100644 --- a/ios/Sources/GutenbergKit/Sources/EditorConfiguration.swift +++ b/ios/Sources/GutenbergKit/Sources/EditorConfiguration.swift @@ -26,10 +26,8 @@ public struct EditorConfiguration { public let namespaceExcludedPaths: [String] /// Authorization header public let authHeader: String - /// Global variables to be made available to the editor - public let webViewGlobals: [WebViewGlobal] /// Raw block editor settings from the WordPress REST API - public let editorSettings: EditorSettings + public let editorSettings: String /// Locale used for translations public let locale: String /// Endpoint for loading editor assets, used when enabling `shouldUsePlugins` @@ -52,8 +50,7 @@ public struct EditorConfiguration { siteApiNamespace: [String], namespaceExcludedPaths: [String], authHeader: String, - webViewGlobals: [WebViewGlobal], - editorSettings: EditorSettings, + editorSettings: String, locale: String, editorAssetsEndpoint: URL? = nil, cookies: [HTTPCookie] = [] @@ -70,7 +67,6 @@ public struct EditorConfiguration { self.siteApiNamespace = siteApiNamespace self.namespaceExcludedPaths = namespaceExcludedPaths self.authHeader = authHeader - self.webViewGlobals = webViewGlobals self.editorSettings = editorSettings self.locale = locale self.editorAssetsEndpoint = editorAssetsEndpoint @@ -91,7 +87,6 @@ public struct EditorConfiguration { siteApiNamespace: siteApiNamespace, namespaceExcludedPaths: namespaceExcludedPaths, authHeader: authHeader, - webViewGlobals: webViewGlobals, editorSettings: editorSettings, locale: locale, editorAssetsEndpoint: editorAssetsEndpoint @@ -106,12 +101,6 @@ public struct EditorConfiguration { content.addingPercentEncoding(withAllowedCharacters: .alphanumerics)! } - var editorSettingsJSON: String { - // `editorSettings` values are always `encodable` so this should never fail - let jsonData = try! JSONSerialization.data(withJSONObject: editorSettings, options: []) - return String(data: jsonData, encoding: .utf8) ?? "undefined" - } - public static let `default` = EditorConfigurationBuilder().build() } @@ -128,8 +117,7 @@ public struct EditorConfigurationBuilder { private var siteApiNamespace: [String] private var namespaceExcludedPaths: [String] private var authHeader: String - private var webViewGlobals: [WebViewGlobal] - private var editorSettings: EditorSettings + private var editorSettings: String private var locale: String private var editorAssetsEndpoint: URL? @@ -146,8 +134,7 @@ public struct EditorConfigurationBuilder { siteApiNamespace: [String] = [], namespaceExcludedPaths: [String] = [], authHeader: String = "", - webViewGlobals: [WebViewGlobal] = [], - editorSettings: EditorSettings = [:], + editorSettings: String = "undefined", locale: String = "en", editorAssetsEndpoint: URL? = nil ){ @@ -163,7 +150,6 @@ public struct EditorConfigurationBuilder { self.siteApiNamespace = siteApiNamespace self.namespaceExcludedPaths = namespaceExcludedPaths self.authHeader = authHeader - self.webViewGlobals = webViewGlobals self.editorSettings = editorSettings self.locale = locale self.editorAssetsEndpoint = editorAssetsEndpoint @@ -241,13 +227,7 @@ public struct EditorConfigurationBuilder { return copy } - public func setWebViewGlobals(_ webViewGlobals: [WebViewGlobal]) -> EditorConfigurationBuilder { - var copy = self - copy.webViewGlobals = webViewGlobals - return copy - } - - public func setEditorSettings(_ editorSettings: EditorSettings) -> EditorConfigurationBuilder { + public func setEditorSettings(_ editorSettings: String) -> EditorConfigurationBuilder { var copy = self copy.editorSettings = editorSettings return copy @@ -279,7 +259,6 @@ public struct EditorConfigurationBuilder { siteApiNamespace: siteApiNamespace, namespaceExcludedPaths: namespaceExcludedPaths, authHeader: authHeader, - webViewGlobals: webViewGlobals, editorSettings: editorSettings, locale: locale, editorAssetsEndpoint: editorAssetsEndpoint @@ -287,61 +266,6 @@ public struct EditorConfigurationBuilder { } } -public struct WebViewGlobal: Equatable { - let name: String - let value: WebViewGlobalValue - - public init(name: String, value: WebViewGlobalValue) throws { - // Validate name is a valid JavaScript identifier - guard Self.isValidJavaScriptIdentifier(name) else { - throw WebViewGlobalError.invalidIdentifier(name) - } - self.name = name - self.value = value - } - - private static func isValidJavaScriptIdentifier(_ name: String) -> Bool { - // Add validation logic for JavaScript identifiers - return name.range(of: "^[a-zA-Z_$][a-zA-Z0-9_$]*$", options: .regularExpression) != nil - } -} - -public enum WebViewGlobalError: Error { - case invalidIdentifier(String) -} - -public enum WebViewGlobalValue: Equatable { - case string(String) - case number(Double) - case boolean(Bool) - case object([String: WebViewGlobalValue]) - case array([WebViewGlobalValue]) - case null - - func toJavaScript() -> String { - switch self { - case .string(let str): - return "\"\(str.escaped)\"" - case .number(let num): - return "\(num)" - case .boolean(let bool): - return "\(bool)" - case .object(let dict): - let sortedKeys = dict.keys.sorted() - var pairs: [String] = [] - for key in sortedKeys { - let value = dict[key]! - pairs.append("\"\(key.escaped)\": \(value.toJavaScript())") - } - return "{\(pairs.joined(separator: ","))}" - case .array(let array): - return "[\(array.map { $0.toJavaScript() }.joined(separator: ","))]" - case .null: - return "null" - } - } -} - public typealias EditorSettings = [String: Encodable] // String escaping extension diff --git a/ios/Sources/GutenbergKit/Sources/EditorViewController.swift b/ios/Sources/GutenbergKit/Sources/EditorViewController.swift index e22b4dfe..7b4380ad 100644 --- a/ios/Sources/GutenbergKit/Sources/EditorViewController.swift +++ b/ios/Sources/GutenbergKit/Sources/EditorViewController.swift @@ -146,13 +146,7 @@ public final class EditorViewController: UIViewController, GutenbergEditorContro private func getEditorConfiguration() -> WKUserScript { - // Generate JavaScript globals - let globalsJS = configuration.webViewGlobals.map { global in - "window[\"\(global.name)\"] = \(global.value.toJavaScript());" - }.joined(separator: "\n") - let jsCode = """ - \(globalsJS) window.GBKit = { siteURL: '\(configuration.siteURL)', @@ -162,7 +156,7 @@ public final class EditorViewController: UIViewController, GutenbergEditorContro authHeader: '\(configuration.authHeader)', themeStyles: \(configuration.shouldUseThemeStyles), hideTitle: \(configuration.shouldHideTitle), - editorSettings: \(configuration.editorSettingsJSON), + editorSettings: \(configuration.editorSettings), locale: '\(configuration.locale)', post: { id: \(configuration.postID ?? -1), diff --git a/ios/Tests/GutenbergKitTests/EditorConfigurationBuilderTests.swift b/ios/Tests/GutenbergKitTests/EditorConfigurationBuilderTests.swift index 7dd3c071..74e51a40 100644 --- a/ios/Tests/GutenbergKitTests/EditorConfigurationBuilderTests.swift +++ b/ios/Tests/GutenbergKitTests/EditorConfigurationBuilderTests.swift @@ -20,15 +20,14 @@ struct EditorConfigurationBuilderTests { #expect(builder.siteApiNamespace == []) #expect(builder.namespaceExcludedPaths == []) #expect(builder.authHeader == "") - #expect(builder.webViewGlobals == []) - #expect(builder.editorSettings.isEmpty) + #expect(builder.editorSettings == "undefined") #expect(builder.locale == "en") #expect(builder.editorAssetsEndpoint == nil) } @Test("Editor Configuration to Builder") func testThatEditorConfigurationToBuilder() throws { - let configuration = try EditorConfigurationBuilder() + let configuration = EditorConfigurationBuilder() .setTitle("Title") .setContent("Content") .setPostID(123) @@ -41,8 +40,7 @@ struct EditorConfigurationBuilderTests { .setSiteApiNamespace(["wp", "v2"]) .setNamespaceExcludedPaths(["jetpack"]) .setAuthHeader("Bearer Token") - .setWebViewGlobals([WebViewGlobal(name: "foo", value: .string("bar"))]) - .setEditorSettings(["foo":"bar"]) + .setEditorSettings(#"{"foo":"bar"}"#) .setLocale("fr") .setEditorAssetsEndpoint(URL(string: "https://example.com/wp-content/plugins/gutenberg/build/")) .build() // Convert to a configuration @@ -61,8 +59,7 @@ struct EditorConfigurationBuilderTests { #expect(configuration.siteApiNamespace == ["wp", "v2"]) #expect(configuration.namespaceExcludedPaths == ["jetpack"]) #expect(configuration.authHeader == "Bearer Token") - #expect(configuration.webViewGlobals == [try WebViewGlobal(name: "foo", value: .string("bar"))]) - #expect(configuration.editorSettingsJSON == #"{"foo":"bar"}"#) + #expect(configuration.editorSettings == #"{"foo":"bar"}"#) #expect(configuration.locale == "fr") #expect(configuration.editorAssetsEndpoint == URL(string: "https://example.com/wp-content/plugins/gutenberg/build/")) } @@ -138,25 +135,15 @@ struct EditorConfigurationBuilderTests { #expect(EditorConfigurationBuilder().setAuthHeader("Bearer token").build().authHeader == "Bearer token") } - @Test("Sets webViewGlobals Correctly") - func editorConfigurationBuilderSetsWebViewGlobalsCorrectly() throws { - #expect( - try EditorConfigurationBuilder() - .setWebViewGlobals([WebViewGlobal(name: "foo", value: .string("bar"))]) - .build() - .webViewGlobals - == [WebViewGlobal(name: "foo", value: .string("bar"))] - ) - } - @Test("Sets editorSettings Correctly") func editorConfigurationBuilderSetsEditorSettingsCorrectly() throws { + let json = #"{"foo":"bar"}"# #expect( EditorConfigurationBuilder() - .setEditorSettings(["foo": "bar"]) + .setEditorSettings(json) .build() - .editorSettingsJSON - == "{\"foo\":\"bar\"}" + .editorSettings + == json ) } diff --git a/ios/Tests/GutenbergKitTests/EditorConfigurationTests.swift b/ios/Tests/GutenbergKitTests/EditorConfigurationTests.swift deleted file mode 100644 index eb328fbf..00000000 --- a/ios/Tests/GutenbergKitTests/EditorConfigurationTests.swift +++ /dev/null @@ -1,115 +0,0 @@ -import Foundation -import Testing -@testable import GutenbergKit - -@Suite -final class EditorConfigurationTests { - - @Test - func testValidJavaScriptIdentifiers() throws { - let validIdentifiers = [ - "myVar", - "_privateVar", - "$jQuery", - "myVar123", - "MY_CONSTANT", - "a", - "A" - ] - - for identifier in validIdentifiers { - _ = try WebViewGlobal(name: identifier, value: .string("test")) - } - } - - @Test - func testInvalidJavaScriptIdentifiers() { - let invalidIdentifiers = [ - "123invalid", - "my-var", - "my.var", - "my var", - "", - "my@var", - "my#var" - ] - - for identifier in invalidIdentifiers { - #expect(throws: WebViewGlobalError.self, performing: { - try WebViewGlobal(name: identifier, value: .string("test")) - }) - } - } - - // MARK: - WebViewGlobalValue Tests - @Test - func testStringValueConversion() { - let testCases = [ - ("simple", "\"simple\""), - ("with \"quotes\"", "\"with \\\"quotes\\\"\""), - ("with\nnewline", "\"with\\nnewline\""), - ("with\ttab", "\"with\\ttab\""), - ("with\rreturn", "\"with\\rreturn\""), - ("with\u{8}backspace", "\"with\\bbackspace\""), - ("with\u{12}formfeed", "\"with\\fformfeed\"") - ] - - for (input, expected) in testCases { - #expect(WebViewGlobalValue.string(input).toJavaScript() == expected) - } - } - - @Test - func testNumberValueConversion() { - let testCases = [ - (42.0, "42.0"), - (-3.14, "-3.14"), - (0.0, "0.0"), - (1.0, "1.0") - ] - - for (input, expected) in testCases { - #expect(WebViewGlobalValue.number(input).toJavaScript() == expected) - } - } - - @Test - func testBooleanValueConversion() { - #expect(WebViewGlobalValue.boolean(true).toJavaScript() == "true") - #expect(WebViewGlobalValue.boolean(false).toJavaScript() == "false") - } - - @Test - func testNullValueConversion() { - #expect(WebViewGlobalValue.null.toJavaScript() == "null") - } - - @Test - func testObjectValueConversion() throws { - let object = WebViewGlobalValue.object([ - "name": .string("test"), - "count": .number(42), - "active": .boolean(true), - "nested": .object([ - "value": .string("nested") - ]) - ]) - - let actual = object.toJavaScript() - let expected = "{\"active\": true,\"count\": 42.0,\"name\": \"test\",\"nested\": {\"value\": \"nested\"}}" - #expect(actual == expected) - } - - @Test - func testArrayValueConversion() { - let array = WebViewGlobalValue.array([ - .string("test"), - .number(42), - .boolean(true), - .null - ]) - - let expected = "[\"test\",42.0,true,null]" - #expect(array.toJavaScript() == expected) - } -}