Skip to content

Commit 840c297

Browse files
Merge pull request #64 from contentful/hyper_lin_to_entry
Hyper lin to entry
2 parents 2702e6b + 2abe6a6 commit 840c297

File tree

6 files changed

+76
-7
lines changed

6 files changed

+76
-7
lines changed

ContentfulRichTextRenderer.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Pod::Spec.new do |spec|
44
spec.name = "ContentfulRichTextRenderer"
5-
spec.version = "0.4.0"
5+
spec.version = "0.4.1"
66
spec.summary = "Swift library for rendering Contentful RichTextDocument."
77
spec.homepage = "https://github.com/contentful-labs/rich-text-renderer.swift"
88
spec.social_media_url = 'https://twitter.com/contentful'

Sources/RichTextRenderer/NodeRenderers/ResourceLinkInline/ResourceLinkInlineRenderer.swift

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import UIKit
1010
*/
1111
open class ResourceLinkInlineRenderer: NodeRendering {
1212
public typealias NodeType = ResourceLinkInline
13+
14+
internal static let kContentfulLinkKey = "kContentfulLinkKey"
1315

1416
required public init() {}
1517

@@ -18,11 +20,41 @@ open class ResourceLinkInlineRenderer: NodeRendering {
1820
rootRenderer: RichTextDocumentRendering,
1921
context: [CodingUserInfoKey : Any]
2022
) -> [NSMutableAttributedString] {
21-
guard let provider = context.rendererConfiguration.resourceLinkInlineStringProvider else { return [] }
23+
24+
switch node.data.target {
25+
case .asset(_), .entry(_), .unresolved(_):
26+
let contentNodes = node.content.compactMap { $0 as? RenderableNodeProviding }
27+
let result = contentNodes.reduce(into: [NSAttributedString]()) { result, contentNode in
28+
let renderedNode = rootRenderer.render(
29+
node: contentNode,
30+
context: context
31+
)
2232

23-
var rendered = [provider.string(for: node.data.target, context: context)]
24-
rendered.applyListItemStylingIfNecessary(node: node, context: context)
33+
result.append(contentsOf: renderedNode)
34+
}.reduce(into: NSMutableAttributedString()) { result, child in
35+
result.append(child)
36+
}
2537

26-
return rendered
38+
result.addAttributes(
39+
[
40+
.link: "inlineResourceLink://\(node.data.target.id)",
41+
NSAttributedString.Key(ResourceLinkInlineRenderer.kContentfulLinkKey): node.data.target
42+
],
43+
range: result.fullRange
44+
)
45+
46+
return [result]
47+
case .entryDecodable(_):
48+
guard let provider = context.rendererConfiguration.resourceLinkInlineStringProvider else {
49+
return []
50+
}
51+
52+
var rendered = [provider.string(for: node.data.target, context: context)]
53+
rendered.applyListItemStylingIfNecessary(node: node, context: context)
54+
55+
return rendered
56+
default:
57+
return []
58+
}
2759
}
2860
}

Sources/RichTextRenderer/Renderer/Default/DefaultRendererConfiguration.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
// RichTextRenderer
22

33
import UIKit
4+
import Contentful
45

56
/// Default configuration for the `RichTextRenderer`.
67
public struct DefaultRendererConfiguration: RendererConfiguration {
8+
79
public var styleProvider: StyleProviding = DefaultStyleProvider()
810
public var contentInsets: UIEdgeInsets = .init(top: 10, left: 10, bottom: 10, right: 15)
911
public var textConfiguration: TextConfiguration = .default
@@ -12,6 +14,8 @@ public struct DefaultRendererConfiguration: RendererConfiguration {
1214
public var horizontalRuleViewProvider: HorizontalRuleViewProviding = HorizontalRuleViewProvider()
1315
public var resourceLinkInlineStringProvider: ResourceLinkInlineStringProviding? = nil
1416
public var resourceLinkBlockViewProvider: ResourceLinkBlockViewProviding? = nil
17+
public var onResourceHyperlinkPressed: ((Contentful.Link) -> Void)?
18+
public var onHyperlinkPressed: ((String) -> Void)?
1519

1620
public init() {}
1721
}

Sources/RichTextRenderer/Renderer/Default/DefaultStyleProvider.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,6 @@ public final class DefaultStyleProvider: StyleProviding {
8282
self.baseFont = baseFont
8383
self.baseColor = baseColor // Base color setup
8484
self.monospacedFont = monospacedFont ?? baseFont
85-
self.baseHyperlinkColor = hyperlinkColor ?? baseColor
85+
self.baseHyperlinkColor = hyperlinkColor ?? .systemBlue
8686
}
8787
}

Sources/RichTextRenderer/Renderer/RendererConfiguration.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,10 @@ public protocol RendererConfiguration {
2828

2929
/// Provides a view for `ResourceLinkBlock` nodes.
3030
var resourceLinkBlockViewProvider: ResourceLinkBlockViewProviding? { get }
31+
32+
/// Called, when an asset or entry hyperlink is pressed
33+
var onResourceHyperlinkPressed: ((_ destination: Link) -> Void)? { get }
34+
35+
/// Called, when a url hyperlink is pressed
36+
var onHyperlinkPressed: ((String) -> Void)? { get }
3137
}

Sources/RichTextRenderer/ViewController/RichTextViewController.swift

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import Contentful
88

99
The content of the document is rendered to internal text view.
1010
*/
11-
open class RichTextViewController: UIViewController, NSLayoutManagerDelegate {
11+
open class RichTextViewController: UIViewController, NSLayoutManagerDelegate, UITextViewDelegate {
1212

1313
private enum Constant {
1414
static let embedSuffix = "-embed"
@@ -133,6 +133,7 @@ open class RichTextViewController: UIViewController, NSLayoutManagerDelegate {
133133
textView.isScrollEnabled = false
134134
}
135135
textView.isEditable = false
136+
textView.delegate = self
136137
}
137138

138139
private func invalidateLayout() {
@@ -443,4 +444,30 @@ open class RichTextViewController: UIViewController, NSLayoutManagerDelegate {
443444
exclusionPathsStorage[key] = exclusionPath
444445
textView.textContainer.exclusionPaths.append(exclusionPath)
445446
}
447+
448+
// MARK: - UITextViewDelegate
449+
450+
public func textView(_ textView: UITextView,
451+
shouldInteractWith URL: URL,
452+
in characterRange: NSRange,
453+
interaction: UITextItemInteraction) -> Bool {
454+
let attributes = textView.attributedText.attributes(at: characterRange.location, longestEffectiveRange: nil, in: characterRange)
455+
456+
// Asset or Entry hyperlink
457+
if let linkToResource = attributes[NSAttributedString.Key(rawValue: ResourceLinkInlineRenderer.kContentfulLinkKey)] as? Link {
458+
renderer.configuration.onResourceHyperlinkPressed?(linkToResource)
459+
460+
return false
461+
}
462+
463+
// URL hyperlink interceptor
464+
if let link = attributes[.link] as? String, let callback = renderer.configuration.onHyperlinkPressed {
465+
callback(link)
466+
467+
return false
468+
}
469+
470+
471+
return true
472+
}
446473
}

0 commit comments

Comments
 (0)