Skip to content
This repository was archived by the owner on Sep 12, 2024. It is now read-only.

Commit 5229a6c

Browse files
committed
Fix codemirror content with special characters + md style
1 parent 26a20f6 commit 5229a6c

File tree

6 files changed

+1066
-16
lines changed

6 files changed

+1066
-16
lines changed

Snip.xcodeproj/project.pbxproj

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
7936F89F24DA02DD00F09AE7 /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7936F89E24DA02DD00F09AE7 /* TextField.swift */; };
2424
794D27CE24F672E4006E3B3D /* SnipTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 794D27CD24F672E4006E3B3D /* SnipTests.swift */; };
2525
794D27D924F68FF2006E3B3D /* Down in Frameworks */ = {isa = PBXBuildFile; productRef = 794D27D824F68FF2006E3B3D /* Down */; };
26+
794D27DB24F6A19C006E3B3D /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 794D27DA24F6A19C006E3B3D /* Data.swift */; };
27+
794D27DE24F6A39B006E3B3D /* md.css in Resources */ = {isa = PBXBuildFile; fileRef = 794D27DD24F6A39B006E3B3D /* md.css */; };
2628
796B092524D1B4A3006904C4 /* SnipItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 796B092424D1B4A3006904C4 /* SnipItem.swift */; };
2729
796B092924D1B563006904C4 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 796B092824D1B563006904C4 /* Settings.swift */; };
2830
796B093124D1B8F5006904C4 /* CodeMirrorView.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 796B092F24D1B8F5006904C4 /* CodeMirrorView.bundle */; };
@@ -87,6 +89,8 @@
8789
794D27CB24F672E4006E3B3D /* SnipTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SnipTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
8890
794D27CD24F672E4006E3B3D /* SnipTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnipTests.swift; sourceTree = "<group>"; };
8991
794D27CF24F672E4006E3B3D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
92+
794D27DA24F6A19C006E3B3D /* Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = "<group>"; };
93+
794D27DD24F6A39B006E3B3D /* md.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; path = md.css; sourceTree = "<group>"; };
9094
796B092424D1B4A3006904C4 /* SnipItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnipItem.swift; sourceTree = "<group>"; };
9195
796B092824D1B563006904C4 /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
9296
796B092F24D1B8F5006904C4 /* CodeMirrorView.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = CodeMirrorView.bundle; path = Snip/External/CodeMirrorView.bundle; sourceTree = "<group>"; };
@@ -173,6 +177,14 @@
173177
path = SnipTests;
174178
sourceTree = "<group>";
175179
};
180+
794D27DC24F6A37E006E3B3D /* Resources */ = {
181+
isa = PBXGroup;
182+
children = (
183+
794D27DD24F6A39B006E3B3D /* md.css */,
184+
);
185+
path = Resources;
186+
sourceTree = "<group>";
187+
};
176188
796B092324D1B48F006904C4 /* Model */ = {
177189
isa = PBXGroup;
178190
children = (
@@ -277,6 +289,7 @@
277289
79DBD4C824D1CBBD00568364 /* Representables */,
278290
79BC1D2124D16E67008FD16E /* SnipViewApp.swift */,
279291
79BC1D1F24D16E67008FD16E /* AppDelegate.swift */,
292+
794D27DC24F6A37E006E3B3D /* Resources */,
280293
79BC1D2324D16E6A008FD16E /* Assets.xcassets */,
281294
79BC1D2824D16E6A008FD16E /* Main.storyboard */,
282295
79BC1D2B24D16E6A008FD16E /* Info.plist */,
@@ -306,6 +319,7 @@
306319
79956A4624E57AC700B823E1 /* Dictionary.swift */,
307320
79956A4824E57AD900B823E1 /* CharacterSet.swift */,
308321
79956A4F24E5BC2300B823E1 /* URL.swift */,
322+
794D27DA24F6A19C006E3B3D /* Data.swift */,
309323
);
310324
path = Extensions;
311325
sourceTree = "<group>";
@@ -441,6 +455,7 @@
441455
isa = PBXResourcesBuildPhase;
442456
buildActionMask = 2147483647;
443457
files = (
458+
794D27DE24F6A39B006E3B3D /* md.css in Resources */,
444459
796B093124D1B8F5006904C4 /* CodeMirrorView.bundle in Resources */,
445460
79BC1D2A24D16E6A008FD16E /* Main.storyboard in Resources */,
446461
79BC1D2724D16E6A008FD16E /* Preview Assets.xcassets in Resources */,
@@ -478,6 +493,7 @@
478493
79956A4924E57AD900B823E1 /* CharacterSet.swift in Sources */,
479494
79956A4E24E5A4A200B823E1 /* OAuth.swift in Sources */,
480495
791B8D7824E2C6C200851E2A /* SharePicker.swift in Sources */,
496+
794D27DB24F6A19C006E3B3D /* Data.swift in Sources */,
481497
79F07A2724D3028C00469324 /* VisualEffectView.swift in Sources */,
482498
79956A5024E5BC2300B823E1 /* URL.swift in Sources */,
483499
791AC9C124DAB60900CAB87C /* SnippetManager.swift in Sources */,

Snip/Extensions/Data.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//
2+
// Data.swift
3+
// Snip
4+
//
5+
// Created by Anthony Fernandez on 8/26/20.
6+
// Copyright © 2020 pictarine. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
extension Data {
12+
func hexEncodedString() -> String {
13+
return map { String(format: "%02hhx", $0) }.joined()
14+
}
15+
}

Snip/External/CodeMirrorView.bundle/Contents/Resources/index.html

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@
7575
var content = GetContent();
7676
window.webkit.messageHandlers.codeMirrorTextContentDidChange.postMessage(content);
7777
});
78+
79+
function getStringFromHex(content) {
80+
return decodeURIComponent(content.replace(/\s+/g, '').replace(/[0-9a-f]{2}/g, '%$&'));
81+
}
7882

7983
function SupportedMimeTypes() {
8084
return Object.keys(CodeMirror.mimeModes).join(",");
@@ -141,7 +145,8 @@
141145
}
142146

143147
function SetContent(content) {
144-
editor.doc.setValue(content);
148+
var text = getStringFromHex(content);
149+
editor.doc.setValue(text);
145150
editor.doc.clearHistory();
146151
editor.doc.markClean();
147152
}

Snip/Representables/CodeMirrorViewController.swift

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,12 @@ class CodeMirrorViewController: NSObject {
4444
}
4545

4646
func setContent(_ value: String) {
47-
//
48-
// It's tricky to pass FULL JSON or HTML text with \n or "", ... into JS Bridge
49-
// Have to wrap with `data_here`
50-
// And use String.raw to prevent escape some special string -> String will show exactly how it's
51-
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
52-
//
53-
let first = "var content = String.raw`"
54-
let content = """
55-
\(value)
56-
"""
57-
let end = "`; SetContent(content);"
58-
let script = first + content + end
59-
callJavascript(javascriptString: script)
60-
//callJavascript(javascriptString: "SetContent(\"\(content)\");")
47+
if let hexString = value.data(using: .utf8)?.hexEncodedString() {
48+
let script = """
49+
var content = "\(hexString)"; SetContent(content);
50+
"""
51+
callJavascript(javascriptString: script)
52+
}
6153
}
6254

6355
func getContent(_ block: JavascriptCallback?) {

Snip/Representables/MarkdownHTMLViewer.swift

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,41 @@ struct MarkdownHTMLViewer: NSViewRepresentable {
1616
var code: String
1717
var mode: Mode
1818

19+
class Coodinator: NSObject, WKNavigationDelegate {
20+
21+
private func encodeStringTo64(fromString: String) -> String? {
22+
let plainData = fromString.data(using: .utf8)
23+
return plainData?.base64EncodedString(options: [])
24+
}
25+
26+
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
27+
guard let path = Bundle.main.path(forResource: "md", ofType: "css") else {
28+
return
29+
}
30+
31+
let cssString = try! String(contentsOfFile: path).components(separatedBy: .newlines).joined()
32+
33+
let cssStyle = """
34+
javascript:(function() {
35+
var parent = document.getElementsByTagName('head').item(0);
36+
var style = document.createElement('style');
37+
style.type = 'text/css';
38+
style.innerHTML = window.atob('\(encodeStringTo64(fromString: cssString)!)');
39+
parent.appendChild(style)})()
40+
"""
41+
42+
let cssScript = WKUserScript(source: cssStyle, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
43+
44+
webView.configuration.userContentController.addUserScript(cssScript)
45+
}
46+
47+
}
48+
49+
func makeCoordinator() -> Coodinator {
50+
return Coodinator()
51+
}
52+
53+
1954
fileprivate func setContent(_ webView: WKWebView) {
2055

2156
var htmlSource = ""
@@ -28,14 +63,15 @@ struct MarkdownHTMLViewer: NSViewRepresentable {
2863
let down = Down(markdownString: code)
2964

3065
if let html = try? down.toHTML() {
31-
htmlSource = html
66+
htmlSource = "<article class=\"markdown-body\">\(html)</article>"
3267
}
3368
}
3469

3570
webView.loadHTMLString(htmlSource, baseURL: nil)
3671
}
3772

3873
func makeNSView(context: Context) -> WKWebView {
74+
3975
let preferences = WKPreferences()
4076
preferences.javaScriptEnabled = true
4177

@@ -45,6 +81,7 @@ struct MarkdownHTMLViewer: NSViewRepresentable {
4581
let webView = WKWebView(frame: .zero, configuration: configuration)
4682
webView.setValue(false, forKey: "drawsBackground")
4783
webView.allowsMagnification = false
84+
webView.navigationDelegate = context.coordinator
4885

4986
setContent(webView)
5087

0 commit comments

Comments
 (0)