Skip to content

Commit e998cdc

Browse files
committed
GQL Json RTE content to HTML support added
1 parent 0f77413 commit e998cdc

18 files changed

Lines changed: 739 additions & 7 deletions

.talismanrc

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,16 @@ fileignoreconfig:
22
- filename: README.md
33
allowed_patterns: [API_KEY, DELIVERY_TOKEN, ENVIRONMENT]
44
- filename: ContentstackUtils.xcodeproj/project.pbxproj
5-
checksum: 5b62a76622fed7df9967d8646467bd2f04c221df2c95eddce7541fd8ab448078
5+
checksum: bc8adda12b44f1b59bb8ff59c8b5135533c024e1d5d3dd8f90ebf83921b13acc
6+
- filename: Sources/ContentstackUtils/JSONNodes.swift
7+
checksum: 46364e65d2303da49c331ef2f3b7ab5792bc8a38091c7e1672a7a9878341f1b4
8+
- filename: Sources/ContentstackUtils/GQLEmbededEntry.swift
9+
checksum: 7f110d0ec5681966c9be5dcf0d3c6080d2a1c0edb12cdb041e81faccaa73436c
10+
- filename: Sources/ContentstackUtils/Edges.swift
11+
checksum: f97583d4ad7fc78230f600ef766254f720c0be9320604f4ca3de6ca340b87357
12+
- filename: Sources/ContentstackUtils/JSONNode.swift
13+
checksum: a6ba5be58ff452ca1eb5549c45dfab3b73caeb0820f24a395568c1bdffb31039
14+
- filename: Sources/ContentstackUtils/ConnectionNode.swift
15+
checksum: 16acd4ea1aa33414082b10b8a1415d2abb6edb0b6280f922c5afa4d699333f7f
16+
- filename: Sources/ContentstackUtils/GQLEmbededAsset.swift
17+
checksum: 12089cea20bec0300bf3293cfdb03279d1fc9fb1f30dc4549ac0b81dac0dfe14

ContentstackUtils.xcodeproj/project.pbxproj

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@
2121
/* End PBXAggregateTarget section */
2222

2323
/* Begin PBXBuildFile section */
24+
0F00785926A59D6600FC4925 /* GQLJsonRTE.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F00785826A59D6600FC4925 /* GQLJsonRTE.swift */; };
25+
0F00785B26A5A0EB00FC4925 /* GQLJsonToHtml.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F00785A26A5A0EB00FC4925 /* GQLJsonToHtml.swift */; };
26+
0F00785D26A6ACBF00FC4925 /* GQLEmbededEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F00785C26A6ACBF00FC4925 /* GQLEmbededEntry.swift */; };
27+
0F00785F26A6ACDC00FC4925 /* GQLEmbededAsset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F00785E26A6ACDC00FC4925 /* GQLEmbededAsset.swift */; };
28+
0F00786126A6AD0100FC4925 /* JSONNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F00786026A6AD0100FC4925 /* JSONNode.swift */; };
29+
0F00786326A6AD2100FC4925 /* JSONNodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F00786226A6AD2100FC4925 /* JSONNodes.swift */; };
30+
0F00786526A6AD3E00FC4925 /* Edges.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F00786426A6AD3E00FC4925 /* Edges.swift */; };
31+
0F00786726A6AD6800FC4925 /* ConnectionNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F00786626A6AD6800FC4925 /* ConnectionNode.swift */; };
2432
0F01BA4B25237725005A3EE0 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F01BA4A25237725005A3EE0 /* String+Extension.swift */; };
2533
0F07E62F25244DB5003E0BD1 /* StringExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F07E62E25244DB5003E0BD1 /* StringExtensionTests.swift */; };
2634
0F57953B266A50710082815C /* Decodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F57953A266A50710082815C /* Decodable.swift */; };
@@ -81,6 +89,14 @@
8189
/* End PBXContainerItemProxy section */
8290

8391
/* Begin PBXFileReference section */
92+
0F00785826A59D6600FC4925 /* GQLJsonRTE.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GQLJsonRTE.swift; sourceTree = "<group>"; };
93+
0F00785A26A5A0EB00FC4925 /* GQLJsonToHtml.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GQLJsonToHtml.swift; sourceTree = "<group>"; };
94+
0F00785C26A6ACBF00FC4925 /* GQLEmbededEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GQLEmbededEntry.swift; sourceTree = "<group>"; };
95+
0F00785E26A6ACDC00FC4925 /* GQLEmbededAsset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GQLEmbededAsset.swift; sourceTree = "<group>"; };
96+
0F00786026A6AD0100FC4925 /* JSONNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONNode.swift; sourceTree = "<group>"; };
97+
0F00786226A6AD2100FC4925 /* JSONNodes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONNodes.swift; sourceTree = "<group>"; };
98+
0F00786426A6AD3E00FC4925 /* Edges.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Edges.swift; sourceTree = "<group>"; };
99+
0F00786626A6AD6800FC4925 /* ConnectionNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionNode.swift; sourceTree = "<group>"; };
84100
0F01BA4A25237725005A3EE0 /* String+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = "<group>"; };
85101
0F07E62E25244DB5003E0BD1 /* StringExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtensionTests.swift; sourceTree = "<group>"; };
86102
0F57953A266A50710082815C /* Decodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Decodable.swift; sourceTree = "<group>"; };
@@ -147,6 +163,14 @@
147163
/* End PBXFrameworksBuildPhase section */
148164

149165
/* Begin PBXGroup section */
166+
0F00785726A59D3B00FC4925 /* GQLJsonToHtmlMock */ = {
167+
isa = PBXGroup;
168+
children = (
169+
0F00785826A59D6600FC4925 /* GQLJsonRTE.swift */,
170+
);
171+
name = GQLJsonToHtmlMock;
172+
sourceTree = "<group>";
173+
};
150174
0F01BA49252376E5005A3EE0 /* Extensions */ = {
151175
isa = PBXGroup;
152176
children = (
@@ -159,6 +183,12 @@
159183
isa = PBXGroup;
160184
children = (
161185
0FEC37AF254FFF6E00B1EFDD /* Metadata.swift */,
186+
0F00785C26A6ACBF00FC4925 /* GQLEmbededEntry.swift */,
187+
0F00785E26A6ACDC00FC4925 /* GQLEmbededAsset.swift */,
188+
0F00786026A6AD0100FC4925 /* JSONNode.swift */,
189+
0F00786226A6AD2100FC4925 /* JSONNodes.swift */,
190+
0F00786426A6AD3E00FC4925 /* Edges.swift */,
191+
0F00786626A6AD6800FC4925 /* ConnectionNode.swift */,
162192
);
163193
name = Models;
164194
sourceTree = "<group>";
@@ -190,6 +220,7 @@
190220
0FA3D58B252208B100E58179 /* Mock */ = {
191221
isa = PBXGroup;
192222
children = (
223+
0F00785726A59D3B00FC4925 /* GQLJsonToHtmlMock */,
193224
0FFD88DD266DDDCF00BA5919 /* RenderMock */,
194225
0FFD88DC266DDDB900BA5919 /* JsonToHtmMock */,
195226
0FEC37B925503E5000B1EFDD /* CustomRenderOptionMock.swift */,
@@ -293,6 +324,7 @@
293324
0F579540266A50D40082815C /* MarkTypeTest.swift */,
294325
0F579546266A50E30082815C /* NodeTypeTest.swift */,
295326
0FFD88D6266DDD1900BA5919 /* ContentstackUtilsJsonToHtmlTest.swift */,
327+
0F00785A26A5A0EB00FC4925 /* GQLJsonToHtml.swift */,
296328
);
297329
name = ContentstackUtilsTests;
298330
path = Tests/ContentstackUtilsTests;
@@ -468,21 +500,27 @@
468500
files = (
469501
0FFD8903266DEC0D00BA5919 /* TextNode.swift in Sources */,
470502
0FEC37B0254FFF6E00B1EFDD /* Metadata.swift in Sources */,
503+
0F00785F26A6ACDC00FC4925 /* GQLEmbededAsset.swift in Sources */,
471504
0FEC0B1F254FE0B2008D4E66 /* Kanna.swift in Sources */,
472505
0FEC37B82550394F00B1EFDD /* EmbedItemType.swift in Sources */,
473506
0FFF2F2A2668FC54003E9DBF /* NodeType.swift in Sources */,
474507
0FEC0B1E254FE0B2008D4E66 /* Deprecated.swift in Sources */,
475508
0FA3D5842521F21300E58179 /* StyleType.swift in Sources */,
509+
0F00786526A6AD3E00FC4925 /* Edges.swift in Sources */,
476510
0FA3D57F2521F1D400E58179 /* Option.swift in Sources */,
477511
0FEC0B1A254FE0B2008D4E66 /* libxmlHTMLNode.swift in Sources */,
478512
0FEC0B1C254FE0B2008D4E66 /* libxmlHTMLDocument.swift in Sources */,
513+
0F00786126A6AD0100FC4925 /* JSONNode.swift in Sources */,
514+
0F00786726A6AD6800FC4925 /* ConnectionNode.swift in Sources */,
479515
0FA3D5852521F21300E58179 /* EntryEmbedded.swift in Sources */,
480516
0FEC0B1B254FE0B2008D4E66 /* CSS.swift in Sources */,
481517
0FFF2F382668FE85003E9DBF /* Node.swift in Sources */,
482518
0F57953B266A50710082815C /* Decodable.swift in Sources */,
483519
0FFF2F242668FB6F003E9DBF /* MarkType.swift in Sources */,
484520
0F01BA4B25237725005A3EE0 /* String+Extension.swift in Sources */,
485521
0FEC0B1D254FE0B2008D4E66 /* libxmlParserOption.swift in Sources */,
522+
0F00786326A6AD2100FC4925 /* JSONNodes.swift in Sources */,
523+
0F00785D26A6ACBF00FC4925 /* GQLEmbededEntry.swift in Sources */,
486524
OBJ_22 /* ContentstackUtils.swift in Sources */,
487525
);
488526
runOnlyForDeploymentPostprocessing = 0;
@@ -515,6 +553,8 @@
515553
0F7142C425514A6F00C18A61 /* ContentstackUtilsArrayTest.swift in Sources */,
516554
0FFD88EE266DE1A600BA5919 /* NodeParser.swift in Sources */,
517555
0FFD88F7266DE1FB00BA5919 /* JsonNodes.swift in Sources */,
556+
0F00785B26A5A0EB00FC4925 /* GQLJsonToHtml.swift in Sources */,
557+
0F00785926A59D6600FC4925 /* GQLJsonRTE.swift in Sources */,
518558
OBJ_41 /* XCTestManifests.swift in Sources */,
519559
0F7142C62551684600C18A61 /* ContentstackUtilsCustomRendertest.swift in Sources */,
520560
0F5E48452525BECA0038C16B /* Constants.swift in Sources */,

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,3 +225,35 @@ stack.contentType(uid: contentTypeUID)
225225
}
226226
}
227227
```
228+
229+
### GraphQL implementation
230+
After fetching the entries from the content type pass the JSON RTE to `ContentstackUtils.GQL.jsonToHtml` function as shown below:
231+
232+
```swift
233+
import ContentstackUtils
234+
import Apollo
235+
...
236+
let graphQLClient: ApolloClient
237+
...
238+
239+
graphQLClient.fetch (query: ProductsQuery(), cachePolicy: CachePolicy.fetchIgnoringCacheData, queue: DispatchQueue.main) {[weak self] (result: Result<GraphQLResult<ProductsQuery.Data>, Error>) in
240+
guard let slf = self else {
241+
return
242+
}
243+
switch result {
244+
case .success(let graphQLResult):
245+
guard let data = graphQLResult.data, let products = data.allAbcd?.items else {
246+
return
247+
}
248+
249+
for product in products {
250+
if let rte = product.superchargedRte {
251+
let result = try? ContentstackUtils.GQL.jsonToHtml(rte: rte.resultMap)
252+
}
253+
}
254+
case .failure(let error):
255+
print("Failure! Error: \(error)")
256+
}
257+
}
258+
```
259+
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//
2+
// ConnectionNode.swift
3+
// ContentstackUtils
4+
//
5+
// Created by Uttam Ukkoji on 20/07/21.
6+
//
7+
8+
9+
internal class ConnectionNode: Decodable {
10+
var node: EmbeddedObject?
11+
public enum FieldKeys: String, CodingKey {
12+
case node
13+
}
14+
public required init(from decoder: Decoder) throws {
15+
let container = try decoder.container(keyedBy: ConnectionNode.FieldKeys.self)
16+
let containerFields = try decoder.container(keyedBy: JSONCodingKeys.self)
17+
let fields = try containerFields.decode(Dictionary<String, Any>.self)
18+
if let nodes = fields["node"] as? [String: Any],
19+
let system = nodes["system"] as? [String: Any],
20+
let contentType = system["content_type_uid"] as? String {
21+
if contentType == "sys_assets" {
22+
node = try container.decode(GQLEmbededAsset.self, forKey: .node)
23+
} else {
24+
node = try container.decode(GQLEmbededEntry.self, forKey: .node)
25+
}
26+
}
27+
}
28+
29+
static func initWith(container nodes: inout UnkeyedDecodingContainer) throws -> [EmbeddedObject] {
30+
var nodesArray = nodes
31+
32+
var object: [EmbeddedObject] = []
33+
while !nodes.isAtEnd {
34+
_ = try nodes.nestedContainer(keyedBy: ConnectionNode.FieldKeys.self)
35+
let connectionNode = try nodesArray.decode(ConnectionNode.self)
36+
if let item = connectionNode.node {
37+
object.append(item)
38+
}
39+
}
40+
return object
41+
}
42+
}

Sources/ContentstackUtils/ContentstackUtils.swift

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,30 @@
1+
import Foundation
2+
13
public struct ContentstackUtils {
24

5+
// public struct JsonNode {
6+
// public var json: Node
7+
// public var embeddedObject:
8+
// }
9+
public struct GQL {
10+
public static func jsonToHtml(rte document: [String: Any?], _ option: Option = Option()) throws -> Any {
11+
do {
12+
let data = try JSONSerialization.data(withJSONObject: document, options: JSONSerialization.WritingOptions.fragmentsAllowed)
13+
if (document["json"] as? [[String: Any?]]) != nil {
14+
let rte = try JSONDecoder().decode(JSONNodes.self, from: data)
15+
option.embdeddedItems = rte.embeddedItemsConnection?.edges
16+
return ContentstackUtils.jsonToHtml(node: rte.json, option)
17+
}else {
18+
let rte = try JSONDecoder().decode(JSONNode.self, from: data)
19+
option.embdeddedItems = rte.embeddedItemsConnection?.edges
20+
return ContentstackUtils.jsonToHtml(node: rte.json, option)
21+
}
22+
} catch (let error) {
23+
throw error
24+
}
25+
}
26+
}
27+
328
public static func render(content: String, _ option: Option) throws -> String {
429
do {
530
let appendContent = content.appendFrame()
@@ -40,7 +65,6 @@ public struct ContentstackUtils {
4065
}
4166
}
4267

43-
4468
public static func jsonToHtml(node documents: [Node], _ option: Option = Option()) -> [String] {
4569
var resultContents: [String] = []
4670
documents.forEach { (document) in
@@ -103,6 +127,13 @@ public struct ContentstackUtils {
103127
if let entry = option.entry,
104128
let embeddedObject = findObject(metadata, entry: entry) {
105129
return option.renderItem(embeddedObject: embeddedObject, metadata: metadata) ?? ""
130+
} else if let embdeddedItems = option.embdeddedItems {
131+
let embedModel = embdeddedItems.filter { (item: EmbeddedObject) -> Bool in
132+
return item.uid == metadata.itemUid && item.contentTypeUID == metadata.contentTypeUid
133+
}
134+
if !embedModel.isEmpty {
135+
return option.renderItem(embeddedObject: embedModel.first!, metadata: metadata) ?? ""
136+
}
106137
}
107138
return ""
108139
}

Sources/ContentstackUtils/Decodable.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ internal extension KeyedDecodingContainer {
5252
dictionary[key.stringValue] = intValue
5353
} else if let doubleValue = try? decode(Double.self, forKey: key) {
5454
dictionary[key.stringValue] = doubleValue
55-
} else if let nestedDictionary = try? decode(Dictionary<String, Any>.self, forKey: key) {
55+
} else if let nestedDictionary = try? decode(Dictionary<String, Any>.self, forKey: key) {
5656
dictionary[key.stringValue] = nestedDictionary
5757
} else if let nestedArray = try? decode(Array<Any>.self, forKey: key) {
5858
dictionary[key.stringValue] = nestedArray
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// Edges.swift
3+
// ContentstackUtils
4+
//
5+
// Created by Uttam Ukkoji on 20/07/21.
6+
//
7+
8+
9+
internal class Edges: Decodable {
10+
var edges: [EmbeddedObject]?
11+
public enum FieldKeys: String, CodingKey {
12+
case edges
13+
}
14+
public required init(from decoder: Decoder) throws {
15+
let container = try decoder.container(keyedBy: FieldKeys.self)
16+
if var nodes = try? container.nestedUnkeyedContainer(forKey: .edges) {
17+
edges = try ConnectionNode.initWith(container: &nodes)
18+
}
19+
}
20+
}

Sources/ContentstackUtils/EntryEmbedded.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
public protocol EmbeddedObject: class {
1+
public protocol EmbeddedObject: AnyObject {
22
/// The `unique identifier` of the entity.
33
var uid: String { get }
44
var contentTypeUID: String {get}
5+
var fields: [String: Any]? {get}
56
}
67

78
public protocol EmbeddedContentTypeUid: EmbeddedObject {
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//
2+
// GQLEmbededAsset.swift
3+
// ContentstackUtils
4+
//
5+
// Created by Uttam Ukkoji on 20/07/21.
6+
//
7+
8+
internal class GQLEmbededAsset: Decodable, EmbeddedAsset {
9+
static var contentTypeUid: String = "sys_asset"
10+
11+
var uid: String
12+
13+
var url: String
14+
15+
var title: String
16+
17+
var filename: String
18+
19+
var contentTypeUID: String
20+
21+
public var fields: [String: Any]?
22+
public enum FieldKeys: String, CodingKey {
23+
case title, uid, url, filename
24+
case contentTypeUID = "content_type_uid"
25+
}
26+
27+
public required init(from decoder: Decoder) throws {
28+
let container = try decoder.container(keyedBy: FieldKeys.self)
29+
uid = ""
30+
url = try container.decodeIfPresent(String.self, forKey: .url) ?? ""
31+
title = try container.decodeIfPresent(String.self, forKey: .title) ?? ""
32+
filename = try container.decodeIfPresent(String.self, forKey: .filename) ?? ""
33+
contentTypeUID = ""
34+
35+
let containerFields = try decoder.container(keyedBy: JSONCodingKeys.self)
36+
fields = try containerFields.decode(Dictionary<String, Any>.self)
37+
38+
if let allfields = fields, let system = allfields["system"] as? [String: Any] {
39+
if let val = system["uid"] as? String {
40+
uid = val
41+
}
42+
43+
if let contentType = system["content_type_uid"] as? String {
44+
contentTypeUID = contentType
45+
}
46+
}
47+
}
48+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//
2+
// GQLEmbededEntry.swift
3+
// ContentstackUtils
4+
//
5+
// Created by Uttam Ukkoji on 20/07/21.
6+
//
7+
8+
internal class GQLEmbededEntry: Decodable, EmbeddedEntry {
9+
static var contentTypeUid: String = "GQL"
10+
11+
var title: String
12+
13+
var uid: String
14+
15+
var contentTypeUID: String
16+
17+
public var fields: [String: Any]?
18+
19+
public enum FieldKeys: String, CodingKey {
20+
case title, uid
21+
case contentTypeUID = "content_type_uid"
22+
}
23+
24+
public required init(from decoder: Decoder) throws {
25+
let container = try decoder.container(keyedBy: FieldKeys.self)
26+
uid = ""
27+
contentTypeUID = ""
28+
title = try container.decodeIfPresent(String.self, forKey: .title) ?? ""
29+
30+
let containerFields = try decoder.container(keyedBy: JSONCodingKeys.self)
31+
fields = try containerFields.decode(Dictionary<String, Any>.self)
32+
33+
if let allfields = fields, let system = allfields["system"] as? [String: Any] {
34+
if let val = system["uid"] as? String {
35+
uid = val
36+
}
37+
38+
if let contentType = system["content_type_uid"] as? String {
39+
contentTypeUID = contentType
40+
}
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)