diff --git a/Mac/MainWindow/Detail/DetailViewController.swift b/Mac/MainWindow/Detail/DetailViewController.swift index 592322b0d..0e3def9e9 100644 --- a/Mac/MainWindow/Detail/DetailViewController.swift +++ b/Mac/MainWindow/Detail/DetailViewController.swift @@ -15,6 +15,7 @@ import RSWeb enum DetailState: Equatable { case noSelection case multipleSelection + case loading case article(Article) case extracted(Article, ExtractedArticle) } diff --git a/Mac/MainWindow/Detail/DetailWebViewController.swift b/Mac/MainWindow/Detail/DetailWebViewController.swift index 43d9ed835..cdcd744fd 100644 --- a/Mac/MainWindow/Detail/DetailWebViewController.swift +++ b/Mac/MainWindow/Detail/DetailWebViewController.swift @@ -104,13 +104,8 @@ 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 + webView.loadHTMLString(ArticleRenderer.page.html, baseURL: ArticleRenderer.page.baseURL) + } // MARK: Scrolling @@ -182,13 +177,15 @@ private extension DetailWebViewController { func reloadHTML() { let style = ArticleStylesManager.shared.currentStyle - let rendering: ArticleRendering + let rendering: ArticleRenderer.Rendering switch state { case .noSelection: rendering = ArticleRenderer.noSelectionHTML(style: style) case .multipleSelection: rendering = ArticleRenderer.multipleSelectionHTML(style: style) + case .loading: + rendering = ArticleRenderer.loadingHTML(style: style) case .article(let article): rendering = ArticleRenderer.articleHTML(article: article, style: style) case .extracted(let article, let extractedArticle): 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/Mac/MainWindow/Detail/styleSheet.css b/Mac/MainWindow/Detail/styleSheet.css index 97ab0e019..107a7cb7e 100644 --- a/Mac/MainWindow/Detail/styleSheet.css +++ b/Mac/MainWindow/Detail/styleSheet.css @@ -133,6 +133,20 @@ figcaption { line-height: 1.3em; } +.iframeWrap { + position: relative; + display: block; + padding-top: 56.25%; +} + +.iframeWrap iframe { + position: absolute; + top: 0; + left: 0; + height: 100% !important; + width: 100% !important; +} + /*Block ads and junk*/ iframe[src*="feedads"], diff --git a/Mac/MainWindow/MainWindowController.swift b/Mac/MainWindow/MainWindowController.swift index 21cf866ff..f863b0160 100644 --- a/Mac/MainWindow/MainWindowController.swift +++ b/Mac/MainWindow/MainWindowController.swift @@ -329,11 +329,7 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations { detailViewController?.setState(detailState, mode: timelineSourceMode) } } else { - if let extractor = ArticleExtractor(currentLink) { - extractor.delegate = self - extractor.process() - articleExtractor = extractor - } + startArticleExtractorForCurrentLink() } } @@ -453,18 +449,24 @@ extension MainWindowController: SidebarDelegate { extension MainWindowController: TimelineContainerViewControllerDelegate { func timelineSelectionDidChange(_: TimelineContainerViewController, articles: [Article]?, mode: TimelineSourceMode) { - articleExtractor?.cancel() articleExtractor = nil isShowingExtractedArticle = false - makeToolbarValidate() let detailState: DetailState if let articles = articles { - detailState = articles.count == 1 ? .article(articles.first!) : .multipleSelection - } - else { + if articles.count == 1 { + if articles.first?.feed?.isArticleExtractorAlwaysOn ?? false { + detailState = .loading + startArticleExtractorForCurrentLink() + } else { + detailState = .article(articles.first!) + } + } else { + detailState = .multipleSelection + } + } else { detailState = .noSelection } @@ -833,6 +835,14 @@ private extension MainWindowController { } } + + func startArticleExtractorForCurrentLink() { + if let link = currentLink, let extractor = ArticleExtractor(link) { + extractor.delegate = self + extractor.process() + articleExtractor = extractor + } + } func saveSplitViewState() { // TODO: Update this for multiple windows. diff --git a/Mac/Resources/Assets.xcassets/articleExtractor.imageset/ArticleExtractor.pdf b/Mac/Resources/Assets.xcassets/articleExtractor.imageset/ArticleExtractor.pdf index 3dd2e82cc..4806aaecb 100644 Binary files a/Mac/Resources/Assets.xcassets/articleExtractor.imageset/ArticleExtractor.pdf and b/Mac/Resources/Assets.xcassets/articleExtractor.imageset/ArticleExtractor.pdf differ diff --git a/Mac/Resources/Assets.xcassets/articleExtractorError.imageset/ArticleExtractorError.pdf b/Mac/Resources/Assets.xcassets/articleExtractorError.imageset/ArticleExtractorError.pdf index 79e7f35aa..02114937b 100644 Binary files a/Mac/Resources/Assets.xcassets/articleExtractorError.imageset/ArticleExtractorError.pdf and b/Mac/Resources/Assets.xcassets/articleExtractorError.imageset/ArticleExtractorError.pdf differ diff --git a/Mac/Resources/Assets.xcassets/articleExtractorProgress1.imageset/ArticleExtractorProgress1.pdf b/Mac/Resources/Assets.xcassets/articleExtractorProgress1.imageset/ArticleExtractorProgress1.pdf index effa04f3d..b1737c594 100644 Binary files a/Mac/Resources/Assets.xcassets/articleExtractorProgress1.imageset/ArticleExtractorProgress1.pdf and b/Mac/Resources/Assets.xcassets/articleExtractorProgress1.imageset/ArticleExtractorProgress1.pdf differ diff --git a/Mac/Resources/Assets.xcassets/articleExtractorProgress2.imageset/ArticleExtractorProgress2.pdf b/Mac/Resources/Assets.xcassets/articleExtractorProgress2.imageset/ArticleExtractorProgress2.pdf index f4167ffd2..939dcc5cc 100644 Binary files a/Mac/Resources/Assets.xcassets/articleExtractorProgress2.imageset/ArticleExtractorProgress2.pdf and b/Mac/Resources/Assets.xcassets/articleExtractorProgress2.imageset/ArticleExtractorProgress2.pdf differ diff --git a/Mac/Resources/Assets.xcassets/articleExtractorProgress3.imageset/ArticleExtractorProgress3.pdf b/Mac/Resources/Assets.xcassets/articleExtractorProgress3.imageset/ArticleExtractorProgress3.pdf index 54a621431..d27a6269b 100644 Binary files a/Mac/Resources/Assets.xcassets/articleExtractorProgress3.imageset/ArticleExtractorProgress3.pdf and b/Mac/Resources/Assets.xcassets/articleExtractorProgress3.imageset/ArticleExtractorProgress3.pdf differ diff --git a/Mac/Resources/Assets.xcassets/articleExtractorProgress4.imageset/ArticleExtractorProgress4.pdf b/Mac/Resources/Assets.xcassets/articleExtractorProgress4.imageset/ArticleExtractorProgress4.pdf index 670a4baab..2e27e98c6 100644 Binary files a/Mac/Resources/Assets.xcassets/articleExtractorProgress4.imageset/ArticleExtractorProgress4.pdf and b/Mac/Resources/Assets.xcassets/articleExtractorProgress4.imageset/ArticleExtractorProgress4.pdf differ diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 7181d159c..d57ac1872 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -78,6 +78,9 @@ 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 */; }; + 517630232336657E00E15FFF /* DetailViewControllerWebViewProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 517630222336657E00E15FFF /* DetailViewControllerWebViewProvider.swift */; }; 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 */; }; @@ -813,6 +816,8 @@ 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 = ""; }; + 517630222336657E00E15FFF /* DetailViewControllerWebViewProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewControllerWebViewProvider.swift; 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 = ""; }; @@ -1370,6 +1375,7 @@ isa = PBXGroup; children = ( 51C4527E2265092C00C03939 /* DetailViewController.swift */, + 517630222336657E00E15FFF /* DetailViewControllerWebViewProvider.swift */, 515ADE3F22E11FAE006B2460 /* SystemMessageViewController.swift */, ); path = Detail; @@ -1393,6 +1399,7 @@ 49F40DEF2335B71000552BF4 /* newsfoot.js */, 849A977D1ED9EC42007D329B /* ArticleRenderer.swift */, 848362FE2262A30E00DA1D35 /* template.html */, + 517630032336215100E15FFF /* main.js */, ); path = "Article Rendering"; sourceTree = ""; @@ -2502,6 +2509,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 */, @@ -2537,6 +2545,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 */, @@ -2702,6 +2711,7 @@ 51C452A722650A3D00C03939 /* RSImage-Extensions.swift in Sources */, 51C45269226508F600C03939 /* MasterFeedTableViewCell.swift in Sources */, 51F85BFD2275DCA800C787DC /* SingleLineUILabelSizer.swift in Sources */, + 517630232336657E00E15FFF /* DetailViewControllerWebViewProvider.swift in Sources */, 51C4528F226509BD00C03939 /* UnreadFeed.swift in Sources */, 51AF460E232488C6001742EF /* Account-Extensions.swift in Sources */, 5183CCDD226F1F5C0010922C /* NavigationProgressView.swift in Sources */, diff --git a/Shared/Article Rendering/ArticleRenderer.swift b/Shared/Article Rendering/ArticleRenderer.swift index 5903b69f1..37f90a440 100644 --- a/Shared/Article Rendering/ArticleRenderer.swift +++ b/Shared/Article Rendering/ArticleRenderer.swift @@ -11,10 +11,18 @@ import RSCore import Articles import Account -typealias ArticleRendering = (style: String, html: String) - struct ArticleRenderer { + typealias Rendering = (style: String, html: String) + typealias Page = (html: String, baseURL: URL) + + static var page: Page = { + let pageURL = Bundle.main.url(forResource: "page", withExtension: "html")! + let html = try! String(contentsOf: pageURL) + let baseURL = pageURL.deletingLastPathComponent() + return Page(html: html, baseURL: baseURL) + }() + private let article: Article? private let extractedArticle: ExtractedArticle? private let articleStyle: ArticleStyle @@ -38,22 +46,27 @@ struct ArticleRenderer { // MARK: - API - static func articleHTML(article: Article, extractedArticle: ExtractedArticle? = nil, style: ArticleStyle) -> ArticleRendering { + static func articleHTML(article: Article, extractedArticle: ExtractedArticle? = nil, style: ArticleStyle) -> Rendering { let renderer = ArticleRenderer(article: article, extractedArticle: extractedArticle, style: style) return (renderer.styleString(), renderer.articleHTML) } - static func multipleSelectionHTML(style: ArticleStyle) -> ArticleRendering { + static func multipleSelectionHTML(style: ArticleStyle) -> Rendering { let renderer = ArticleRenderer(article: nil, extractedArticle: nil, style: style) return (renderer.styleString(), renderer.multipleSelectionHTML) } - static func noSelectionHTML(style: ArticleStyle) -> ArticleRendering { + static func loadingHTML(style: ArticleStyle) -> Rendering { + let renderer = ArticleRenderer(article: nil, extractedArticle: nil, style: style) + return (renderer.styleString(), renderer.loadingHTML) + } + + static func noSelectionHTML(style: ArticleStyle) -> Rendering { let renderer = ArticleRenderer(article: nil, extractedArticle: nil, style: style) return (renderer.styleString(), renderer.noSelectionHTML) } - static func noContentHTML(style: ArticleStyle) -> ArticleRendering { + static func noContentHTML(style: ArticleStyle) -> Rendering { let renderer = ArticleRenderer(article: nil, extractedArticle: nil, style: style) return (renderer.styleString(), renderer.noContentHTML) } @@ -73,6 +86,11 @@ private extension ArticleRenderer { return renderHTML(withBody: body) } + private var loadingHTML: String { + let body = "

Loading...

" + return renderHTML(withBody: body) + } + private var noSelectionHTML: String { let body = "

No selection

" return renderHTML(withBody: body) 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..9878be601 100644 --- a/iOS/Detail/DetailViewController.swift +++ b/iOS/Detail/DetailViewController.swift @@ -40,27 +40,23 @@ class DetailViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - webView = DetailViewControllerWebViewProvider.shared.dequeueWebView() - webView.translatesAutoresizingMaskIntoConstraints = false - webView.navigationDelegate = self - - webViewContainer.addSubview(webView) - - let constraints: [NSLayoutConstraint] = [ - webView.leadingAnchor.constraint(equalTo: webViewContainer.safeAreaLayoutGuide.leadingAnchor), - webView.trailingAnchor.constraint(equalTo: webViewContainer.safeAreaLayoutGuide.trailingAnchor), - webView.topAnchor.constraint(equalTo: webViewContainer.safeAreaLayoutGuide.topAnchor), - webView.bottomAnchor.constraint(equalTo: webViewContainer.safeAreaLayoutGuide.bottomAnchor), - ] - - NSLayoutConstraint.activate(constraints) - - updateArticleSelection() - NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(statusesDidChange(_:)), name: .StatusesDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(progressDidChange(_:)), name: .AccountRefreshProgressDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange(_:)), name: UIContentSizeCategory.didChangeNotification, object: nil) + + DetailViewControllerWebViewProvider.shared.dequeueWebView() { webView in + + self.webView = webView + self.webViewContainer.addChildAndPin(webView) + webView.navigationDelegate = self + + // Even though page.html should be loaded into this webview, we have to do it again + // to work around this bug: http://www.openradar.me/22855188 + webView.loadHTMLString(ArticleRenderer.page.html, baseURL: ArticleRenderer.page.baseURL) + + } + } override func viewDidAppear(_ animated: Bool) { @@ -243,6 +239,11 @@ extension DetailViewController: WKNavigationDelegate { } } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + self.updateArticleSelection() + } + } // MARK: Private @@ -261,60 +262,3 @@ 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() - return webView - } - - assertionFailure("Creating WKWebView in \(#function); queue has run dry.") - let webView = WKWebView(frame: .zero) - return webView - } - - func enqueueWebView(_ webView: WKWebView) { - guard queue.count < maximumQueueDepth else { - return - } - - webView.uiDelegate = nil - webView.navigationDelegate = nil - - webView.loadHTMLString(DetailViewControllerWebViewProvider.template, baseURL: nil) - - queue.insert(webView, at: 0) - } - - // MARK: Private - - private let minimumQueueDepth = 3 - private let maximumQueueDepth = 6 - private var queue: [WKWebView] = [] - - private init() { - replenishQueueIfNeeded() - } - - private func replenishQueueIfNeeded() { - while queue.count < minimumQueueDepth { - let webView = WKWebView(frame: .zero) - enqueueWebView(webView) - } - } -} diff --git a/iOS/Detail/DetailViewControllerWebViewProvider.swift b/iOS/Detail/DetailViewControllerWebViewProvider.swift new file mode 100644 index 000000000..35bf79b04 --- /dev/null +++ b/iOS/Detail/DetailViewControllerWebViewProvider.swift @@ -0,0 +1,84 @@ +// +// DetailViewControllerWebViewProvider.swift +// NetNewsWire-iOS +// +// Created by Maurice Parker on 9/21/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import Foundation +import WebKit + +/// 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: NSObject, WKNavigationDelegate { + + static let shared = DetailViewControllerWebViewProvider() + + private let minimumQueueDepth = 3 + private let maximumQueueDepth = 6 + private var queue: [WKWebView] = [] + + private var waitingForFirstLoad = true + private var waitingCompletionHandler: ((WKWebView) -> ())? + + func dequeueWebView(completion: @escaping (WKWebView) -> ()) { + if waitingForFirstLoad { + waitingCompletionHandler = completion + } else { + completeRequest(completion: completion) + } + } + + func enqueueWebView(_ webView: WKWebView) { + guard queue.count < maximumQueueDepth else { + return + } + + webView.navigationDelegate = self + queue.insert(webView, at: 0) + + webView.loadHTMLString(ArticleRenderer.page.html, baseURL: ArticleRenderer.page.baseURL) + + } + + // MARK: WKNavigationDelegate + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + if waitingForFirstLoad { + waitingForFirstLoad = false + if let completion = waitingCompletionHandler { + completeRequest(completion: completion) + waitingCompletionHandler = nil + } + } + } + + // MARK: Private + + private override init() { + super.init() + replenishQueueIfNeeded() + } + + private func replenishQueueIfNeeded() { + while queue.count < minimumQueueDepth { + let webView = WKWebView(frame: .zero) + enqueueWebView(webView) + } + } + + private func completeRequest(completion: @escaping (WKWebView) -> ()) { + if let webView = queue.popLast() { + webView.navigationDelegate = nil + replenishQueueIfNeeded() + completion(webView) + return + } + + assertionFailure("Creating WKWebView in \(#function); queue has run dry.") + let webView = WKWebView(frame: .zero) + completion(webView) + } + +} 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; } - + - diff --git a/iOS/Resources/styleSheet.css b/iOS/Resources/styleSheet.css index fd77f1cbd..2b14a2684 100644 --- a/iOS/Resources/styleSheet.css +++ b/iOS/Resources/styleSheet.css @@ -133,6 +133,20 @@ figcaption { line-height: 1.3em; } +.iframeWrap { + position: relative; + display: block; + padding-top: 56.25%; +} + +.iframeWrap iframe { + position: absolute; + top: 0; + left: 0; + height: 100% !important; + width: 100% !important; +} + /*Block ads and junk*/ iframe[src*="feedads"], diff --git a/submodules/RSCore b/submodules/RSCore index 4dbd31b09..960eaf603 160000 --- a/submodules/RSCore +++ b/submodules/RSCore @@ -1 +1 @@ -Subproject commit 4dbd31b090ab15c3966e9810a65edbf4abdbdd33 +Subproject commit 960eaf60336f592306fb1bf6f5a62800a9c5050f