diff --git a/Mac/MainWindow/Detail/DetailWebViewController.swift b/Mac/MainWindow/Detail/DetailWebViewController.swift index 6fd4a2de1..9ed5b73e7 100644 --- a/Mac/MainWindow/Detail/DetailWebViewController.swift +++ b/Mac/MainWindow/Detail/DetailWebViewController.swift @@ -8,6 +8,7 @@ import AppKit import WebKit +import RSCore import RSWeb import Articles @@ -118,8 +119,7 @@ final class DetailWebViewController: NSViewController, WKUIDelegate { NotificationCenter.default.addObserver(self, selector: #selector(avatarDidBecomeAvailable(_:)), name: .AvatarDidBecomeAvailable, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(faviconDidBecomeAvailable(_:)), name: .FaviconDidBecomeAvailable, object: nil) - webView.loadFileURL(ArticleRenderer.page.url, allowingReadAccessTo: ArticleRenderer.page.baseURL) - + webView.loadFileURL(ArticleRenderer.blank.url, allowingReadAccessTo: ArticleRenderer.blank.baseURL) } // MARK: Notifications @@ -196,12 +196,6 @@ extension DetailWebViewController: WKNavigationDelegate { } // MARK: - Private -struct TemplateData: Codable { - let style: String - let body: String - let title: String - let baseURL: String -} private extension DetailWebViewController { @@ -236,16 +230,15 @@ private extension DetailWebViewController { rendering = ArticleRenderer.articleHTML(article: article, extractedArticle: extractedArticle, style: style) } - let templateData = TemplateData(style: rendering.style, body: rendering.html, title: rendering.title, baseURL: rendering.baseURL) + let substitutions = [ + "title": rendering.title, + "baseURL": rendering.baseURL, + "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), 0);" - } - - webView.evaluateJavaScript(render) + let html = try! MacroProcessor.renderedText(withTemplate: ArticleRenderer.page.html, substitutions: substitutions) + webView.loadHTMLString(html, baseURL: ArticleRenderer.page.baseURL) } func fetchScrollInfo(_ completion: @escaping (ScrollInfo?) -> Void) { diff --git a/Mac/MainWindow/Detail/blank.html b/Mac/MainWindow/Detail/blank.html new file mode 100644 index 000000000..4ff14e9ce --- /dev/null +++ b/Mac/MainWindow/Detail/blank.html @@ -0,0 +1,6 @@ + + + + + + diff --git a/Mac/MainWindow/Detail/page.html b/Mac/MainWindow/Detail/page.html index 5ed1f5e46..6d715390f 100644 --- a/Mac/MainWindow/Detail/page.html +++ b/Mac/MainWindow/Detail/page.html @@ -1,13 +1,20 @@ - - + [[title]] + + + [[body]] diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 7bbc3d0ad..a3254266e 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -14,6 +14,9 @@ 3B826DCE2385C89600FC1ADB /* AccountsFeedWranglerWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B826DCA2385C84800FC1ADB /* AccountsFeedWranglerWindowController.swift */; }; 49F40DF82335B71000552BF4 /* newsfoot.js in Resources */ = {isa = PBXBuildFile; fileRef = 49F40DEF2335B71000552BF4 /* newsfoot.js */; }; 49F40DF92335B71000552BF4 /* newsfoot.js in Resources */ = {isa = PBXBuildFile; fileRef = 49F40DEF2335B71000552BF4 /* newsfoot.js */; }; + 5103A9982421643300410853 /* blank.html in Resources */ = {isa = PBXBuildFile; fileRef = 5103A9972421643300410853 /* blank.html */; }; + 5103A9992421643300410853 /* blank.html in Resources */ = {isa = PBXBuildFile; fileRef = 5103A9972421643300410853 /* blank.html */; }; + 5103A9B424216A4200410853 /* blank.html in Resources */ = {isa = PBXBuildFile; fileRef = 5103A9B324216A4200410853 /* blank.html */; }; 5108F6B62375E612001ABC45 /* CacheCleaner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5108F6B52375E612001ABC45 /* CacheCleaner.swift */; }; 5108F6B72375E612001ABC45 /* CacheCleaner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5108F6B52375E612001ABC45 /* CacheCleaner.swift */; }; 5108F6D22375EED2001ABC45 /* TimelineCustomizerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5108F6D12375EED2001ABC45 /* TimelineCustomizerViewController.swift */; }; @@ -1250,6 +1253,8 @@ 3B826DB02385C84800FC1ADB /* AccountsFeedWrangler.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AccountsFeedWrangler.xib; sourceTree = ""; }; 3B826DCA2385C84800FC1ADB /* AccountsFeedWranglerWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountsFeedWranglerWindowController.swift; sourceTree = ""; }; 49F40DEF2335B71000552BF4 /* newsfoot.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = newsfoot.js; sourceTree = ""; }; + 5103A9972421643300410853 /* blank.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = blank.html; sourceTree = ""; }; + 5103A9B324216A4200410853 /* blank.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = blank.html; sourceTree = ""; }; 5108F6B52375E612001ABC45 /* CacheCleaner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheCleaner.swift; sourceTree = ""; }; 5108F6D12375EED2001ABC45 /* TimelineCustomizerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineCustomizerViewController.swift; sourceTree = ""; }; 5108F6D32375EEEF001ABC45 /* TimelinePreviewTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinePreviewTableViewController.swift; sourceTree = ""; }; @@ -2370,6 +2375,7 @@ 84E8E0EA202F693600562D8F /* DetailWebView.swift */, 84D52E941FE588BB00D14F5B /* DetailStatusBarView.swift */, 5141E7552374A2890013FF27 /* DetailIconSchemeHandler.swift */, + 5103A9972421643300410853 /* blank.html */, B528F81D23333C7E00E735DD /* page.html */, 5142194A2353C1CF00E07E2C /* main_mac.js */, 848362FC2262A30800DA1D35 /* styleSheet.css */, @@ -2677,6 +2683,7 @@ 51F85BF02272524100C787DC /* Credits.rtf */, 51F85BEE2272520B00C787DC /* Thanks.rtf */, 51F85BF22272531500C787DC /* Dedication.rtf */, + 5103A9B324216A4200410853 /* blank.html */, 51BB7C302335ACDE008E8144 /* page.html */, 514219572353C28900E07E2C /* main_ios.js */, 51C452B72265178500C03939 /* styleSheet.css */, @@ -3475,6 +3482,7 @@ 3B826DCD2385C89600FC1ADB /* AccountsFeedWrangler.xib in Resources */, 65ED4069235DEF6C0081F399 /* AccountsReaderAPI.xib in Resources */, 65ED406A235DEF6C0081F399 /* newsfoot.js in Resources */, + 5103A9992421643300410853 /* blank.html in Resources */, 65ED406B235DEF6C0081F399 /* CrashReporterWindow.xib in Resources */, 65ED406C235DEF6C0081F399 /* Credits.rtf in Resources */, 65ED406D235DEF6C0081F399 /* Inspector.storyboard in Resources */, @@ -3507,6 +3515,7 @@ 516A093723609A3600EAE89B /* SettingsAccountTableViewCell.xib in Resources */, 51F85BF32272531500C787DC /* Dedication.rtf in Resources */, 516A09422361248000EAE89B /* Inspector.storyboard in Resources */, + 5103A9B424216A4200410853 /* blank.html in Resources */, 84C9FCA42262A1B800D921D6 /* LaunchScreenPhone.storyboard in Resources */, 51F85BEB22724CB600C787DC /* About.rtf in Resources */, 516A093B2360A4A000EAE89B /* SettingsTableViewCell.xib in Resources */, @@ -3561,6 +3570,7 @@ 3B826DCB2385C84800FC1ADB /* AccountsFeedWrangler.xib in Resources */, 55E15BCB229D65A900D6602A /* AccountsReaderAPI.xib in Resources */, 49F40DF82335B71000552BF4 /* newsfoot.js in Resources */, + 5103A9982421643300410853 /* blank.html in Resources */, 84BAE64921CEDAF20046DB56 /* CrashReporterWindow.xib in Resources */, 84C9FC8E22629E8F00D921D6 /* Credits.rtf in Resources */, 84BBB12D20142A4700F054F5 /* Inspector.storyboard in Resources */, diff --git a/Shared/Article Rendering/ArticleRenderer.swift b/Shared/Article Rendering/ArticleRenderer.swift index a66568560..0be3508d3 100644 --- a/Shared/Article Rendering/ArticleRenderer.swift +++ b/Shared/Article Rendering/ArticleRenderer.swift @@ -17,15 +17,23 @@ import Account struct ArticleRenderer { typealias Rendering = (style: String, html: String, title: String, baseURL: String) - typealias Page = (url: URL, baseURL: URL) + + struct Page { + let url: URL + let baseURL: URL + let html: String + + init(name: String) { + url = Bundle.main.url(forResource: name, withExtension: "html")! + baseURL = url.deletingLastPathComponent() + html = try! NSString(contentsOfFile: url.path, encoding: String.Encoding.utf8.rawValue) as String + } + } static var imageIconScheme = "nnwImageIcon" - static var page: Page = { - let url = Bundle.main.url(forResource: "page", withExtension: "html")! - let baseURL = url.deletingLastPathComponent() - return Page(url: url, baseURL: baseURL) - }() + static var blank = Page(name: "blank") + static var page = Page(name: "page") private let article: Article? private let extractedArticle: ExtractedArticle? diff --git a/Shared/Article Rendering/main.js b/Shared/Article Rendering/main.js index d5751a1b3..29c6e30cd 100644 --- a/Shared/Article Rendering/main.js +++ b/Shared/Article Rendering/main.js @@ -106,25 +106,12 @@ function styleLocalFootnotes() { } } -function render(data, scrollY) { - document.getElementsByTagName("style")[0].innerHTML = data.style; - - let title = document.getElementsByTagName("title")[0]; - title.textContent = data.title - - let base = document.getElementsByTagName("base")[0]; - base.href = data.baseURL - - document.body.innerHTML = data.body; - - window.scrollTo(0, scrollY); - - wrapFrames() - wrapTables() - stripStyles() - convertImgSrc() - flattenPreElements() - styleLocalFootnotes() - - postRenderProcessing() +function processPage() { + wrapFrames(); + wrapTables(); + stripStyles(); + convertImgSrc(); + flattenPreElements(); + styleLocalFootnotes(); + postRenderProcessing(); } diff --git a/iOS/Article/PreloadedWebView.swift b/iOS/Article/PreloadedWebView.swift index 1573b6a3d..47a8aa29c 100644 --- a/iOS/Article/PreloadedWebView.swift +++ b/iOS/Article/PreloadedWebView.swift @@ -11,10 +11,6 @@ import WebKit class PreloadedWebView: WKWebView { - private struct MessageName { - static let domContentLoaded = "domContentLoaded" - } - private var isReady: Bool = false private var readyCompletion: ((PreloadedWebView) -> Void)? @@ -38,8 +34,8 @@ class PreloadedWebView: WKWebView { } func preload() { - configuration.userContentController.add(WrapperScriptMessageHandler(self), name: MessageName.domContentLoaded) - loadFileURL(ArticleRenderer.page.url, allowingReadAccessTo: ArticleRenderer.page.baseURL) + navigationDelegate = self + loadFileURL(ArticleRenderer.blank.url, allowingReadAccessTo: ArticleRenderer.blank.baseURL) } func ready(completion: @escaping (PreloadedWebView) -> Void) { @@ -54,18 +50,16 @@ class PreloadedWebView: WKWebView { // MARK: WKScriptMessageHandler -extension PreloadedWebView: WKScriptMessageHandler { +extension PreloadedWebView: WKNavigationDelegate { - func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { - if message.name == MessageName.domContentLoaded { - isReady = true - if let completion = readyCompletion { - completeRequest(completion: completion) - readyCompletion = nil - } + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + isReady = true + if let completion = readyCompletion { + completeRequest(completion: completion) + readyCompletion = nil } } - + } // MARK: Private @@ -74,7 +68,7 @@ private extension PreloadedWebView { func completeRequest(completion: @escaping (PreloadedWebView) -> Void) { isReady = false - configuration.userContentController.removeScriptMessageHandler(forName: MessageName.domContentLoaded) + navigationDelegate = nil completion(self) } diff --git a/iOS/Article/WebViewController.swift b/iOS/Article/WebViewController.swift index 5e04ea578..6b3fc0926 100644 --- a/iOS/Article/WebViewController.swift +++ b/iOS/Article/WebViewController.swift @@ -325,7 +325,7 @@ extension WebViewController: WKNavigationDelegate { } } - + } // MARK: WKUIDelegate @@ -393,13 +393,6 @@ extension WebViewController: UIScrollViewDelegate { // MARK: JSON -private struct TemplateData: Codable { - let style: String - let body: String - let title: String - let baseURL: String -} - private struct ImageClickMessage: Codable { let x: Float let y: Float @@ -416,11 +409,13 @@ private extension WebViewController { func loadWebView() { guard isViewLoaded else { return } + if let webView = webView { + self.renderPage(webView) + return + } + coordinator.webViewProvider.dequeueWebView() { webView in - let webViewToRecycle = self.webView - self.renderPage(webViewToRecycle) - // Add the webview webView.translatesAutoresizingMaskIntoConstraints = false self.view.insertSubview(webView, at: 0) @@ -451,9 +446,6 @@ private extension WebViewController { webView.configuration.userContentController.add(WrapperScriptMessageHandler(self), name: MessageName.imageWasShown) self.renderPage(webView) - DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { - self.recycleWebView(webViewToRecycle) - } } @@ -498,16 +490,16 @@ private extension WebViewController { rendering = ArticleRenderer.noSelectionHTML(style: style) } - let templateData = TemplateData(style: rendering.style, body: rendering.html, title: rendering.title, baseURL: rendering.baseURL) - - let encoder = JSONEncoder() - var render = "error();" - if let data = try? encoder.encode(templateData) { - let json = String(data: data, encoding: .utf8)! - render = "render(\(json), \(windowScrollY));" - } + let substitutions = [ + "title": rendering.title, + "baseURL": rendering.baseURL, + "style": rendering.style, + "body": rendering.html, + "windowScrollY": String(windowScrollY) + ] - webView.evaluateJavaScript(render) + let html = try! MacroProcessor.renderedText(withTemplate: ArticleRenderer.page.html, substitutions: substitutions) + webView.loadHTMLString(html, baseURL: ArticleRenderer.page.baseURL) } diff --git a/iOS/Resources/blank.html b/iOS/Resources/blank.html new file mode 100644 index 000000000..6e02cf3a6 --- /dev/null +++ b/iOS/Resources/blank.html @@ -0,0 +1,11 @@ + + + + + + + diff --git a/iOS/Resources/page.html b/iOS/Resources/page.html index 22bc5881c..edd9953fa 100644 --- a/iOS/Resources/page.html +++ b/iOS/Resources/page.html @@ -1,17 +1,22 @@ - - + [[title]] + + + [[body]] diff --git a/iOS/Resources/styleSheet.css b/iOS/Resources/styleSheet.css index 0190e1e69..d9eddcf15 100644 --- a/iOS/Resources/styleSheet.css +++ b/iOS/Resources/styleSheet.css @@ -1,4 +1,5 @@ :root { + color-scheme: light dark; font: -apple-system-body; font-size: [[font-size]]px; }