Skip to content

Instantly share code, notes, and snippets.

@evitiello
Created April 25, 2020 00:40
Show Gist options
  • Save evitiello/676677486b363f2f57f5cb15d5092ff8 to your computer and use it in GitHub Desktop.
Save evitiello/676677486b363f2f57f5cb15d5092ff8 to your computer and use it in GitHub Desktop.
//
// WebView.swift
// Core
//
// Created by Eric Vitiello on 1/28/20.
// Copyright © 2020 Eric Vitiello. All rights reserved.
//
import SwiftUI
import Combine
import WebKit
/// A container for using a WKWebView in SwiftUI
public struct WebView: View, UIViewRepresentable {
@ObservedObject var node: Node
public let view: WKWebView = WKWebView()
public var colorScheme: ColorScheme = .light
init(node: Node, colorScheme: ColorScheme) {
self.colorScheme = colorScheme
self.node = node
}
public func makeUIView(context: Context) -> WKWebView {
self.view.uiDelegate = context.coordinator
self.view.navigationDelegate = context.coordinator
self.view.backgroundColor = UIColor.systemBackground
self.view.isOpaque = false
return self.view
}
public func updateUIView(_ uiView: WKWebView, context: Context) {
self.updateContent(withString: self.node.renderedContent())
}
public func updateContent(withString content: String) {
self.view.loadHTMLString(content, baseURL: nil)
}
public func makeCoordinator() -> Coordinator {
Coordinator(self, colorScheme: colorScheme, node: node)
}
/// Coordinator handles delegate communications for the WebView
public final class Coordinator: NSObject, WKUIDelegate, WKNavigationDelegate {
var control: WebView
var colorScheme: ColorScheme = .light
@ObservedObject var node: Node
var subscribers: [AnyCancellable] = []
init(_ control: WebView, colorScheme: ColorScheme, node: Node) {
self.control = control
self.colorScheme = colorScheme
self.node = node
let subscriber = node.$content.receive(on: RunLoop.main).sink(receiveValue: contentDidChange)
subscribers.append(subscriber)
}
deinit {
for subscriber in subscribers { subscriber.cancel() }
}
var contentDidChange: (String) -> Void = { content in
Logger.log("Node Content Changed, rerendering.", severity: .Verbose)
}
public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
let fileStem: String = (colorScheme == .dark) ? "markdown-dark" : "markdown-light"
let cssFileContent = self.cssFileContents(fileStem: fileStem)
let cssCommonFileContent = self.cssFileContents(fileStem: "markdown-common")
let jsString = "var styleCommon = document.createElement('style'); styleCommon.innerHTML = '\(cssCommonFileContent)'; document.head.appendChild(styleCommon); var style = document.createElement('style'); style.innerHTML = '\(cssFileContent)'; document.head.appendChild(style); var title = document.createElement('title'); title.innerHTML = 'Node Detail Content'; document.head.appendChild(title);"
webView.evaluateJavaScript(jsString, completionHandler: nil)
}
private func cssFileContents(fileStem: String) -> String {
Logger.log("Current Appearance: \(colorScheme)", severity: .Verbose)
guard let path = Bundle.main.path(forResource: fileStem, ofType: "css") else { return "" }
let cssFileContent = try! String(contentsOfFile: path)
let cssString = cssFileContent.trimmingCharacters(in: .whitespacesAndNewlines).filter { !"\n\r".contains($0) }
return cssString
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment