diff --git a/Mac/MainWindow/Detail/DetailWebViewController.swift b/Mac/MainWindow/Detail/DetailWebViewController.swift
index 43d9ed835..b81ca8712 100644
--- a/Mac/MainWindow/Detail/DetailWebViewController.swift
+++ b/Mac/MainWindow/Detail/DetailWebViewController.swift
@@ -104,13 +104,12 @@ final class DetailWebViewController: NSViewController, WKUIDelegate {
NotificationCenter.default.addObserver(self, selector: #selector(webInspectorEnabledDidChange(_:)), name: .WebInspectorEnabledDidChange, object: nil)
#endif
- webView.loadHTMLString(template(), baseURL: nil)
- }
-
- func template() -> String {
- let path = Bundle.main.path(forResource: "page", ofType: "html")!
- let s = try! NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue)
- return s as String
+ let pageURL = Bundle.main.url(forResource: "page", withExtension: "html")!
+ let page = try! String(contentsOf: pageURL)
+ let baseURL = pageURL.deletingLastPathComponent()
+
+ webView.loadHTMLString(page, baseURL: baseURL)
+
}
// MARK: Scrolling
diff --git a/Mac/MainWindow/Detail/page.html b/Mac/MainWindow/Detail/page.html
index 8178a7548..97e7c4541 100644
--- a/Mac/MainWindow/Detail/page.html
+++ b/Mac/MainWindow/Detail/page.html
@@ -2,33 +2,7 @@
-
+
diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj
index ffcdd8a1a..6070aa612 100644
--- a/NetNewsWire.xcodeproj/project.pbxproj
+++ b/NetNewsWire.xcodeproj/project.pbxproj
@@ -76,6 +76,8 @@
515D4FCC2325815A00EE1167 /* SafariExt.js in Resources */ = {isa = PBXBuildFile; fileRef = 515D4FCB2325815A00EE1167 /* SafariExt.js */; };
51707439232AA97100A461A3 /* ShareFolderPickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51707438232AA97100A461A3 /* ShareFolderPickerController.swift */; };
5170743A232AABFC00A461A3 /* FlattenedAccountFolderPickerData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C452812265093600C03939 /* FlattenedAccountFolderPickerData.swift */; };
+ 517630042336215100E15FFF /* main.js in Resources */ = {isa = PBXBuildFile; fileRef = 517630032336215100E15FFF /* main.js */; };
+ 517630052336215100E15FFF /* main.js in Resources */ = {isa = PBXBuildFile; fileRef = 517630032336215100E15FFF /* main.js */; };
5183CCD0226E1E880010922C /* NonIntrinsicLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCCF226E1E880010922C /* NonIntrinsicLabel.swift */; };
5183CCDA226E31A50010922C /* NonIntrinsicImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */; };
5183CCDD226F1F5C0010922C /* NavigationProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCDC226F1F5C0010922C /* NavigationProgressView.swift */; };
@@ -810,6 +812,7 @@
515D4FCD2325909200EE1167 /* NetNewsWire_iOS_ShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NetNewsWire_iOS_ShareExtension.entitlements; sourceTree = ""; };
515D4FCE2325B3D000EE1167 /* NetNewsWire_iOSshareextension_target.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOSshareextension_target.xcconfig; sourceTree = ""; };
51707438232AA97100A461A3 /* ShareFolderPickerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareFolderPickerController.swift; sourceTree = ""; };
+ 517630032336215100E15FFF /* main.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = main.js; sourceTree = ""; };
5183CCCF226E1E880010922C /* NonIntrinsicLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicLabel.swift; sourceTree = ""; };
5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicImageView.swift; sourceTree = ""; };
5183CCDC226F1F5C0010922C /* NavigationProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationProgressView.swift; sourceTree = ""; };
@@ -1389,6 +1392,7 @@
children = (
849A977D1ED9EC42007D329B /* ArticleRenderer.swift */,
848362FE2262A30E00DA1D35 /* template.html */,
+ 517630032336215100E15FFF /* main.js */,
);
path = "Article Rendering";
sourceTree = "";
@@ -2498,6 +2502,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 517630052336215100E15FFF /* main.js in Resources */,
511D43D0231FA62500FB1562 /* TimelineKeyboardShortcuts.plist in Resources */,
51C452862265093600C03939 /* Add.storyboard in Resources */,
511D43EF231FBDE900FB1562 /* LaunchScreenPad.storyboard in Resources */,
@@ -2532,6 +2537,7 @@
51EF0F8E2279C9260050506E /* AccountsAdd.xib in Resources */,
84C9FC8F22629E8F00D921D6 /* NetNewsWire.sdef in Resources */,
84C9FC7D22629E1200D921D6 /* AccountsDetail.xib in Resources */,
+ 517630042336215100E15FFF /* main.js in Resources */,
5144EA362279FC3D00D19003 /* AccountsAddLocal.xib in Resources */,
84C9FC8C22629E8F00D921D6 /* KeyboardShortcuts.html in Resources */,
5144EA3B227A379E00D19003 /* ImportOPMLSheet.xib in Resources */,
diff --git a/Shared/Article Rendering/main.js b/Shared/Article Rendering/main.js
new file mode 100644
index 000000000..e33d725da
--- /dev/null
+++ b/Shared/Article Rendering/main.js
@@ -0,0 +1,43 @@
+function mouseDidEnterLink(anchor) {
+ window.webkit.messageHandlers.mouseDidEnter.postMessage(anchor.href);
+}
+
+function mouseDidExitLink(anchor) {
+ window.webkit.messageHandlers.mouseDidExit.postMessage(anchor.href);
+}
+
+function wrapFrames() {
+ document.querySelectorAll("iframe").forEach(element => {
+ var wrapper = document.createElement("div");
+ wrapper.classList.add("iframeWrap");
+ element.parentNode.insertBefore(wrapper, element);
+ wrapper.appendChild(element);
+ });
+}
+
+function stripStyles() {
+ document.getElementsByTagName("body")[0].querySelectorAll("style, link[rel=stylesheet]").forEach(element => element.remove());
+ document.getElementsByTagName("body")[0].querySelectorAll("[style]").forEach(element => element.removeAttribute("style"));
+}
+
+function linkHover() {
+ var anchors = document.getElementsByTagName("a");
+ for (var i = 0; i < anchors.length; i++) {
+ anchors[i].addEventListener("mouseenter", function() { mouseDidEnterLink(this) });
+ anchors[i].addEventListener("mouseleave", function() { mouseDidExitLink(this) });
+ }
+}
+
+function error() {
+ document.body.innerHTML = "error";
+}
+
+function render(data) {
+ document.getElementsByTagName("style")[0].innerHTML = data.style;
+ document.body.innerHTML = data.body;
+ window.scrollTo(0, 0);
+
+ wrapFrames()
+ stripStyles()
+ linkHover()
+}
diff --git a/iOS/Detail/DetailViewController.swift b/iOS/Detail/DetailViewController.swift
index 521a17938..c6a8c1cc7 100644
--- a/iOS/Detail/DetailViewController.swift
+++ b/iOS/Detail/DetailViewController.swift
@@ -271,12 +271,6 @@ class DetailViewControllerWebViewProvider {
static var shared = DetailViewControllerWebViewProvider()
- static let template: String = {
- let path = Bundle.main.path(forResource: "page", ofType: "html")!
- let s = try! NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue)
- return s as String
- }()
-
func dequeueWebView() -> WKWebView {
if let webView = queue.popLast() {
replenishQueueIfNeeded()
@@ -296,7 +290,11 @@ class DetailViewControllerWebViewProvider {
webView.uiDelegate = nil
webView.navigationDelegate = nil
- webView.loadHTMLString(DetailViewControllerWebViewProvider.template, baseURL: nil)
+ let pageURL = Bundle.main.url(forResource: "page", withExtension: "html")!
+ let page = try! String(contentsOf: pageURL)
+ let baseURL = pageURL.deletingLastPathComponent()
+
+ webView.loadHTMLString(page, baseURL: baseURL)
queue.insert(webView, at: 0)
}
diff --git a/iOS/Resources/page.html b/iOS/Resources/page.html
index 7665aa643..4baf2cfee 100644
--- a/iOS/Resources/page.html
+++ b/iOS/Resources/page.html
@@ -6,29 +6,8 @@
color-scheme: light dark;
}
-
+