Convert iOS to use Javascript rendering
This commit is contained in:
parent
710abf30c7
commit
3decd23c45
|
@ -100,6 +100,8 @@
|
|||
51AF460C23247F11001742EF /* SettingsFeedbinAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510D707F22B02A5F004E8F65 /* SettingsFeedbinAccountView.swift */; };
|
||||
51AF460E232488C6001742EF /* Account-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51AF460D232488C6001742EF /* Account-Extensions.swift */; };
|
||||
51B62E68233186730085F949 /* MasterTimelineAvatarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B62E67233186730085F949 /* MasterTimelineAvatarView.swift */; };
|
||||
51BB7C272335A8E5008E8144 /* ArticleActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51BB7C262335A8E5008E8144 /* ArticleActivityItemSource.swift */; };
|
||||
51BB7C312335ACDE008E8144 /* page.html in Resources */ = {isa = PBXBuildFile; fileRef = 51BB7C302335ACDE008E8144 /* page.html */; };
|
||||
51C451A9226377C200C03939 /* ArticlesDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8407167F2262A61100344432 /* ArticlesDatabase.framework */; };
|
||||
51C451AA226377C200C03939 /* ArticlesDatabase.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8407167F2262A61100344432 /* ArticlesDatabase.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
51C451B9226377C900C03939 /* Articles.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 840716732262A60F00344432 /* Articles.framework */; };
|
||||
|
@ -373,7 +375,6 @@
|
|||
9EA33BB92318F8C10097B644 /* AccountsFeedlyWebWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EA33BB72318F8C10097B644 /* AccountsFeedlyWebWindowController.swift */; };
|
||||
9EA33BBA2318F8C10097B644 /* AccountsFeedlyWeb.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9EA33BB82318F8C10097B644 /* AccountsFeedlyWeb.xib */; };
|
||||
B528F81E23333C7E00E735DD /* page.html in Resources */ = {isa = PBXBuildFile; fileRef = B528F81D23333C7E00E735DD /* page.html */; };
|
||||
B528F81F23333C7E00E735DD /* page.html in Resources */ = {isa = PBXBuildFile; fileRef = B528F81D23333C7E00E735DD /* page.html */; };
|
||||
D553738B20186C20006D8857 /* Article+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D553737C20186C1F006D8857 /* Article+Scriptability.swift */; };
|
||||
D57BE6E0204CD35F00D11AAC /* NSScriptCommand+NetNewsWire.swift in Sources */ = {isa = PBXBuildFile; fileRef = D57BE6DF204CD35F00D11AAC /* NSScriptCommand+NetNewsWire.swift */; };
|
||||
D5907D7F2004AC00005947E5 /* NSApplication+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5907D7E2004AC00005947E5 /* NSApplication+Scriptability.swift */; };
|
||||
|
@ -826,6 +827,8 @@
|
|||
519E743422C663F900A78E47 /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||
51AF460D232488C6001742EF /* Account-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Account-Extensions.swift"; sourceTree = "<group>"; };
|
||||
51B62E67233186730085F949 /* MasterTimelineAvatarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterTimelineAvatarView.swift; sourceTree = "<group>"; };
|
||||
51BB7C262335A8E5008E8144 /* ArticleActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleActivityItemSource.swift; sourceTree = "<group>"; };
|
||||
51BB7C302335ACDE008E8144 /* page.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = page.html; sourceTree = "<group>"; };
|
||||
51C4524E226506F400C03939 /* UIStoryboard-Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIStoryboard-Extensions.swift"; sourceTree = "<group>"; };
|
||||
51C45250226506F400C03939 /* String-Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String-Extensions.swift"; sourceTree = "<group>"; };
|
||||
51C45254226507D200C03939 /* AppAssets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppAssets.swift; sourceTree = "<group>"; };
|
||||
|
@ -1385,7 +1388,6 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
849A977D1ED9EC42007D329B /* ArticleRenderer.swift */,
|
||||
B528F81D23333C7E00E735DD /* page.html */,
|
||||
848362FE2262A30E00DA1D35 /* template.html */,
|
||||
);
|
||||
path = "Article Rendering";
|
||||
|
@ -1674,6 +1676,7 @@
|
|||
84216D0222128B9D0049B9B9 /* DetailWebViewController.swift */,
|
||||
84E8E0EA202F693600562D8F /* DetailWebView.swift */,
|
||||
84D52E941FE588BB00D14F5B /* DetailStatusBarView.swift */,
|
||||
B528F81D23333C7E00E735DD /* page.html */,
|
||||
848362FC2262A30800DA1D35 /* styleSheet.css */,
|
||||
5127B235222B4849006D641D /* Keyboard */,
|
||||
);
|
||||
|
@ -1943,6 +1946,7 @@
|
|||
51C45254226507D200C03939 /* AppAssets.swift */,
|
||||
51C45255226507D200C03939 /* AppDefaults.swift */,
|
||||
51E3EB3C229AB08300645299 /* ErrorHandler.swift */,
|
||||
51BB7C262335A8E5008E8144 /* ArticleActivityItemSource.swift */,
|
||||
51C4525D226508F600C03939 /* MasterFeed */,
|
||||
51C4526D2265091600C03939 /* MasterTimeline */,
|
||||
51C4527D2265092C00C03939 /* Detail */,
|
||||
|
@ -1967,6 +1971,7 @@
|
|||
51F85BEE2272520B00C787DC /* Thanks.rtf */,
|
||||
51F85BF22272531500C787DC /* Dedication.rtf */,
|
||||
51C452B72265178500C03939 /* styleSheet.css */,
|
||||
51BB7C302335ACDE008E8144 /* page.html */,
|
||||
84C9FC9B2262A1A900D921D6 /* Assets.xcassets */,
|
||||
84C9FC9C2262A1A900D921D6 /* Info.plist */,
|
||||
84BB0F812333426400DED65E /* NetNewsWire.entitlements */,
|
||||
|
@ -2230,16 +2235,16 @@
|
|||
TargetAttributes = {
|
||||
513C5CE5232571C2003D4054 = {
|
||||
CreatedOnToolsVersion = 11.0;
|
||||
DevelopmentTeam = DY2XQRVWN9;
|
||||
DevelopmentTeam = SHJK2V3AJG;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
6581C73220CED60000F4AD34 = {
|
||||
DevelopmentTeam = SHJK2V3AJG;
|
||||
ProvisioningStyle = Manual;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
840D617B2029031C009BC708 = {
|
||||
CreatedOnToolsVersion = 9.3;
|
||||
DevelopmentTeam = DY2XQRVWN9;
|
||||
DevelopmentTeam = SHJK2V3AJG;
|
||||
ProvisioningStyle = Automatic;
|
||||
SystemCapabilities = {
|
||||
com.apple.BackgroundModes = {
|
||||
|
@ -2250,7 +2255,7 @@
|
|||
849C645F1ED37A5D003D8FC0 = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
DevelopmentTeam = SHJK2V3AJG;
|
||||
ProvisioningStyle = Manual;
|
||||
ProvisioningStyle = Automatic;
|
||||
SystemCapabilities = {
|
||||
com.apple.HardenedRuntime = {
|
||||
enabled = 1;
|
||||
|
@ -2259,7 +2264,7 @@
|
|||
};
|
||||
849C64701ED37A5D003D8FC0 = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
DevelopmentTeam = 9C84TZ7Q6Z;
|
||||
DevelopmentTeam = SHJK2V3AJG;
|
||||
ProvisioningStyle = Automatic;
|
||||
TestTargetID = 849C645F1ED37A5D003D8FC0;
|
||||
};
|
||||
|
@ -2498,7 +2503,7 @@
|
|||
511D43EF231FBDE900FB1562 /* LaunchScreenPad.storyboard in Resources */,
|
||||
511D43D2231FA62C00FB1562 /* GlobalKeyboardShortcuts.plist in Resources */,
|
||||
84C9FCA12262A1B300D921D6 /* Main.storyboard in Resources */,
|
||||
B528F81F23333C7E00E735DD /* page.html in Resources */,
|
||||
51BB7C312335ACDE008E8144 /* page.html in Resources */,
|
||||
51F85BF32272531500C787DC /* Dedication.rtf in Resources */,
|
||||
84C9FCA42262A1B800D921D6 /* LaunchScreenPhone.storyboard in Resources */,
|
||||
51F85BEB22724CB600C787DC /* About.rtf in Resources */,
|
||||
|
@ -2718,6 +2723,7 @@
|
|||
51938DF3231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */,
|
||||
51C4525A226508D600C03939 /* UIStoryboard-Extensions.swift in Sources */,
|
||||
519D740823243FEA008BB345 /* SettingsSubscriptionsImportDocumentPickerView.swift in Sources */,
|
||||
51BB7C272335A8E5008E8144 /* ArticleActivityItemSource.swift in Sources */,
|
||||
51AF460C23247F11001742EF /* SettingsFeedbinAccountView.swift in Sources */,
|
||||
51F85BF52273625800C787DC /* Bundle-Extensions.swift in Sources */,
|
||||
519D740723243FE7008BB345 /* SettingsSubscriptionsExportDocumentPickerView.swift in Sources */,
|
||||
|
|
|
@ -53,6 +53,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele
|
|||
super.init()
|
||||
appDelegate = self
|
||||
|
||||
// Force lazy initialization of the web view provider so that it can warm up the queue of prepared web views
|
||||
let _ = DetailViewControllerWebViewProvider.shared
|
||||
|
||||
AccountManager.shared = AccountManager(accountsFolder: RSDataSubfolder(nil, "Accounts")!)
|
||||
|
||||
registerBackgroundTasks()
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// ArticleActivityItemSource.swift
|
||||
// NetNewsWire-iOS
|
||||
//
|
||||
// Created by Maurice Parker on 9/20/19.
|
||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class ArticleActivityItemSource: NSObject, UIActivityItemSource {
|
||||
|
||||
private let url: URL
|
||||
private let subject: String?
|
||||
|
||||
init(url: URL, subject: String?) {
|
||||
self.url = url
|
||||
self.subject = subject
|
||||
}
|
||||
|
||||
func activityViewControllerPlaceholderItem(_ : UIActivityViewController) -> Any {
|
||||
return url
|
||||
}
|
||||
|
||||
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
|
||||
return url
|
||||
}
|
||||
|
||||
func activityViewController(_ activityViewController: UIActivityViewController, subjectForActivityType activityType: UIActivity.ActivityType?) -> String {
|
||||
return subject ?? ""
|
||||
}
|
||||
|
||||
}
|
|
@ -99,14 +99,23 @@ class DetailViewController: UIViewController {
|
|||
}
|
||||
|
||||
func reloadHTML() {
|
||||
|
||||
guard let article = coordinator.currentArticle, let webView = webView else {
|
||||
return
|
||||
}
|
||||
let style = ArticleStylesManager.shared.currentStyle
|
||||
let (styleSheet, html) = ArticleRenderer.articleHTML(article: article, style: style)
|
||||
webView.loadHTMLString(html, baseURL: nil)
|
||||
|
||||
let style = ArticleStylesManager.shared.currentStyle
|
||||
let rendering = ArticleRenderer.articleHTML(article: article, style: style)
|
||||
|
||||
let templateData = TemplateData(style: rendering.style, body: rendering.html)
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
var render = "error();"
|
||||
if let data = try? encoder.encode(templateData) {
|
||||
let json = String(data: data, encoding: .utf8)!
|
||||
render = "render(\(json));"
|
||||
}
|
||||
|
||||
webView.evaluateJavaScript(render)
|
||||
}
|
||||
|
||||
// MARK: Notifications
|
||||
|
@ -205,31 +214,8 @@ class DetailViewController: UIViewController {
|
|||
}
|
||||
|
||||
}
|
||||
//print("\(candidateY) : \(webView.scrollView.contentSize.height)")
|
||||
|
||||
class ArticleActivityItemSource: NSObject, UIActivityItemSource {
|
||||
|
||||
private let url: URL
|
||||
private let subject: String?
|
||||
|
||||
init(url: URL, subject: String?) {
|
||||
self.url = url
|
||||
self.subject = subject
|
||||
}
|
||||
|
||||
func activityViewControllerPlaceholderItem(_ : UIActivityViewController) -> Any {
|
||||
return url
|
||||
}
|
||||
|
||||
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
|
||||
return url
|
||||
}
|
||||
|
||||
func activityViewController(_ activityViewController: UIActivityViewController, subjectForActivityType activityType: UIActivity.ActivityType?) -> String {
|
||||
return subject ?? ""
|
||||
}
|
||||
|
||||
}
|
||||
// MARK: WKNavigationDelegate
|
||||
|
||||
extension DetailViewController: WKNavigationDelegate {
|
||||
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
||||
|
@ -259,6 +245,8 @@ extension DetailViewController: WKNavigationDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private extension DetailViewController {
|
||||
|
||||
func updateProgressIndicatorIfNeeded() {
|
||||
|
@ -269,13 +257,26 @@ private extension DetailViewController {
|
|||
|
||||
}
|
||||
|
||||
private struct TemplateData: Codable {
|
||||
let style: String
|
||||
let body: String
|
||||
}
|
||||
|
||||
|
||||
// MARK: -
|
||||
|
||||
/// WKWebView has an awful behavior of a flash to white on first load when in dark mode.
|
||||
/// Keep a queue of WebViews where we've already done a trivial load so that by the time we need them in the UI, they're past the flash-to-shite part of their lifecycle.
|
||||
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()
|
||||
|
@ -295,8 +296,7 @@ class DetailViewControllerWebViewProvider {
|
|||
webView.uiDelegate = nil
|
||||
webView.navigationDelegate = nil
|
||||
|
||||
let html = ArticleRenderer.noContentHTML(style: .defaultStyle)
|
||||
webView.loadHTMLString(html, baseURL: nil)
|
||||
webView.loadHTMLString(DetailViewControllerWebViewProvider.template, baseURL: nil)
|
||||
|
||||
queue.insert(webView, at: 0)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function mouseDidEnterLink(anchor) {
|
||||
window.webkit.messageHandlers.mouseDidEnter.postMessage(anchor.href);
|
||||
}
|
||||
|
||||
function mouseDidExitLink(anchor) {
|
||||
window.webkit.messageHandlers.mouseDidExit.postMessage(anchor.href);
|
||||
}
|
||||
|
||||
function render(data) {
|
||||
document.getElementsByTagName("style")[0].innerHTML = data.style;
|
||||
document.body.innerHTML = data.body;
|
||||
window.scrollTo(0, 0);
|
||||
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 error() {
|
||||
document.body.innerHTML = "error";
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -269,8 +269,6 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
|
|||
NotificationCenter.default.addObserver(self, selector: #selector(userDefaultsDidChange(_:)), name: UserDefaults.didChangeNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(accountDidDownloadArticles(_:)), name: .AccountDidDownloadArticles, object: nil)
|
||||
|
||||
// Force lazy initialization of the web view provider so that it can warm up the queue of prepared web views
|
||||
let _ = DetailViewControllerWebViewProvider.shared
|
||||
}
|
||||
|
||||
func start(for size: CGSize) -> UIViewController {
|
||||
|
|
Loading…
Reference in New Issue