Skip to content

Commit

Permalink
Add remote stylesheet support (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
keitaoouchi authored Sep 14, 2021
1 parent 8fa17d9 commit 35964c6
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 6 deletions.
4 changes: 4 additions & 0 deletions Example/Example.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
3E5E1E1E26E8F1620098F0E3 /* CustomCss.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E5E1E1D26E8F1610098F0E3 /* CustomCss.swift */; };
3E71C76026EA0D7400C79EA9 /* Plugins.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E71C75F26EA0D7400C79EA9 /* Plugins.swift */; };
3E910F3026F06F6E009C311B /* RemoteStylesheets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E910F2F26F06F6E009C311B /* RemoteStylesheets.swift */; };
3E9561AE26EB7E9900FFCC19 /* NonStyled.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E9561AD26EB7E9900FFCC19 /* NonStyled.swift */; };
DE524D651EC47CB100E8C2F9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE524D641EC47CB100E8C2F9 /* AppDelegate.swift */; };
DE524D671EC47CB100E8C2F9 /* CodeOnly.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE524D661EC47CB100E8C2F9 /* CodeOnly.swift */; };
Expand All @@ -26,6 +27,7 @@
/* Begin PBXFileReference section */
3E5E1E1D26E8F1610098F0E3 /* CustomCss.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomCss.swift; sourceTree = "<group>"; };
3E71C75F26EA0D7400C79EA9 /* Plugins.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Plugins.swift; sourceTree = "<group>"; };
3E910F2F26F06F6E009C311B /* RemoteStylesheets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteStylesheets.swift; sourceTree = "<group>"; };
3E9561AD26EB7E9900FFCC19 /* NonStyled.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonStyled.swift; sourceTree = "<group>"; };
7DB4CCAB27BE7F6CF35BA1E5 /* Pods-Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig"; sourceTree = "<group>"; };
88E6DEC525FE3CD3BAB79EA8 /* Pods-Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -65,6 +67,7 @@
3E5E1E1D26E8F1610098F0E3 /* CustomCss.swift */,
3E71C75F26EA0D7400C79EA9 /* Plugins.swift */,
3E9561AD26EB7E9900FFCC19 /* NonStyled.swift */,
3E910F2F26F06F6E009C311B /* RemoteStylesheets.swift */,
);
path = ViewController;
sourceTree = "<group>";
Expand Down Expand Up @@ -237,6 +240,7 @@
buildActionMask = 2147483647;
files = (
FCB2E9491ECA929500285B87 /* Storyboard.swift in Sources */,
3E910F3026F06F6E009C311B /* RemoteStylesheets.swift in Sources */,
FCB2E9471ECA8B7600285B87 /* ViewController.swift in Sources */,
3E9561AE26EB7E9900FFCC19 /* NonStyled.swift in Sources */,
3E5E1E1E26E8F1620098F0E3 /* CustomCss.swift in Sources */,
Expand Down
12 changes: 11 additions & 1 deletion Example/Example/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,19 @@ final class ViewController: UIViewController {
let btn6 = UIButton()
btn6.setTitle("Non Styled", for: .normal)
btn6.addTarget(self, action: #selector(openNonStyledSample(sender:)), for: .touchUpInside)

let btn7 = UIButton()
btn7.setTitle("Remote Stylesheet", for: .normal)
btn7.addTarget(self, action: #selector(openRemoteStylesheetSample(sender:)), for: .touchUpInside)

[
btn1,
btn2,
btn3,
btn4,
btn5,
btn6
btn6,
btn7
].forEach { button in

button.setTitleColor(UIColor.systemBlue, for: .normal)
Expand Down Expand Up @@ -85,4 +90,9 @@ final class ViewController: UIViewController {
let example = NonStyledSampleViewController()
navigationController?.pushViewController(example, animated: true)
}

@objc func openRemoteStylesheetSample(sender: Any) {
let example = RemoteStyleSheetsSampleViewController()
navigationController?.pushViewController(example, animated: true)
}
}
47 changes: 47 additions & 0 deletions Example/Example/ViewController/RemoteStylesheets.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import UIKit
import MarkdownView

class RemoteStyleSheetsSampleViewController: UIViewController {

init() {
super.init(nibName: nil, bundle: nil)
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground

let md = MarkdownView()
view.addSubview(md)
md.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
md.topAnchor.constraint(equalTo: view.topAnchor),
md.leadingAnchor.constraint(equalTo: view.leadingAnchor),
md.trailingAnchor.constraint(equalTo: view.trailingAnchor),
md.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])

let markdown = """
# Katex
$\\sqrt{3x-1}+(1+x)^2$
"""
md.load(markdown: markdown, plugins: [js], stylesheets: [stylesheet])
}

}

extension RemoteStyleSheetsSampleViewController {
var js: String {
let url = URL(string: "https://raw.githubusercontent.com/keitaoouchi/markdownview-sample-plugin/master/dist/dst.js")!
return try! String(contentsOf: url)
}

var stylesheet: URL {
URL(string: "https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css")!
}
}
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ Each plugin should be self-contained, with no external dependent plugins.

<img src="https://github.com/keitaoouchi/MarkdownView/blob/master/sample_plugin.png" width=300>

[Here](https://github.com/keitaoouchi/markdownview-sample-plugin) is a sample project that builds `markdown-it-new-katex` as a compatible library.

## Requirements

| Target | Version |
Expand Down
28 changes: 23 additions & 5 deletions Sources/MarkdownView/MarkdownView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ open class MarkdownView: UIView {
/// You can use this for performance optimization.
///
/// - Note: `webView` needs complete loading before invoking `show` method.
public convenience init(css: String?, plugins: [String]?, styled: Bool = true) {
public convenience init(css: String?, plugins: [String]?, stylesheets: [URL]? = nil, styled: Bool = true) {
self.init(frame: .zero)

let configuration = WKWebViewConfiguration()
configuration.userContentController = makeContentController(css: css, plugins: plugins, markdown: nil, enableImage: nil)
configuration.userContentController = makeContentController(css: css, plugins: plugins, stylesheets: stylesheets, markdown: nil, enableImage: nil)
self.webView = makeWebView(with: configuration)
self.webView?.load(URLRequest(url: styled ? Self.styledHtmlUrl : Self.nonStyledHtmlUrl))
}
Expand All @@ -64,12 +64,12 @@ extension MarkdownView {
/// Load markdown with a newly configured webView.
///
/// If you want to preserve already applied css or plugins, use `show` instead.
@objc public func load(markdown: String?, enableImage: Bool = true, css: String? = nil, plugins: [String]? = nil, styled: Bool = true) {
@objc public func load(markdown: String?, enableImage: Bool = true, css: String? = nil, plugins: [String]? = nil, stylesheets: [URL]? = nil, styled: Bool = true) {
guard let markdown = markdown else { return }

self.webView?.removeFromSuperview()
let configuration = WKWebViewConfiguration()
configuration.userContentController = makeContentController(css: css, plugins: plugins, markdown: markdown, enableImage: enableImage)
configuration.userContentController = makeContentController(css: css, plugins: plugins, stylesheets: stylesheets, markdown: markdown, enableImage: enableImage)
self.webView = makeWebView(with: configuration)
self.webView?.load(URLRequest(url: styled ? Self.styledHtmlUrl : Self.nonStyledHtmlUrl))
}
Expand Down Expand Up @@ -134,6 +134,15 @@ private extension MarkdownView {
].joined()
}

func linkScript(_ url: URL) -> String {
[
"var link = document.createElement('link');",
"link.href = '\(url.absoluteURL)';",
"link.rel = 'stylesheet';",
"document.head.appendChild(link);"
].joined()
}

func usePluginScript(_ pluginBody: String) -> String {
"""
var _module = {};
Expand Down Expand Up @@ -206,7 +215,11 @@ private extension MarkdownView {
return wv
}

func makeContentController(css: String?, plugins: [String]?, markdown: String?, enableImage: Bool?) -> WKUserContentController {
func makeContentController(css: String?,
plugins: [String]?,
stylesheets: [URL]?,
markdown: String?,
enableImage: Bool?) -> WKUserContentController {
let controller = WKUserContentController()

if let css = css {
Expand All @@ -219,6 +232,11 @@ private extension MarkdownView {
controller.addUserScript(scriptInjection)
})

stylesheets?.forEach({ url in
let linkInjection = WKUserScript(source: linkScript(url), injectionTime: .atDocumentEnd, forMainFrameOnly: true)
controller.addUserScript(linkInjection)
})

if let markdown = markdown {
let escapedMarkdown = self.escape(markdown: markdown) ?? ""
let imageOption = (enableImage ?? true) ? "true" : "false"
Expand Down

0 comments on commit 35964c6

Please sign in to comment.