From 457bdccf6a28fa469b2b657da881a76ec6ecace9 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Tue, 14 Mar 2023 01:17:21 -0500 Subject: [PATCH 01/18] Comment out some well meaning, but broken code --- iOS/MasterFeed/MasterFeedViewController.swift | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/iOS/MasterFeed/MasterFeedViewController.swift b/iOS/MasterFeed/MasterFeedViewController.swift index 422c3f71f..5734e061a 100644 --- a/iOS/MasterFeed/MasterFeedViewController.swift +++ b/iOS/MasterFeed/MasterFeedViewController.swift @@ -563,11 +563,12 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner, Ma completion?() return } - - if tableView.window == nil { - completion?() - return - } + +// This change made the Sidebar completely unusable +// if tableView.window == nil { +// completion?() +// return +// } tableView.performBatchUpdates { if let deletes = changes.deletes, !deletes.isEmpty { From 2efef5ec1ce806dff60a87b98b9c8cf9dfd830b8 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sat, 1 Apr 2023 21:00:21 -0500 Subject: [PATCH 02/18] Allow fullscreen video --- Mac/MainWindow/Detail/DetailWebViewController.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Mac/MainWindow/Detail/DetailWebViewController.swift b/Mac/MainWindow/Detail/DetailWebViewController.swift index 6d669cf5f..b558b04dc 100644 --- a/Mac/MainWindow/Detail/DetailWebViewController.swift +++ b/Mac/MainWindow/Detail/DetailWebViewController.swift @@ -83,6 +83,9 @@ final class DetailWebViewController: NSViewController { let preferences = WKPreferences() preferences.minimumFontSize = 12.0 preferences.javaScriptCanOpenWindowsAutomatically = false + if #available(macOS 12.3, *) { + preferences.isElementFullscreenEnabled = true + } let webpagePrefs = WKWebpagePreferences() From cc499bdbbe5a1d6b77aacde99b2bbbcd2e0ccb5a Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sat, 1 Apr 2023 21:01:09 -0500 Subject: [PATCH 03/18] Automatically add the YouTube embedded video viewer --- Shared/Article Rendering/main.js | 75 +++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/Shared/Article Rendering/main.js b/Shared/Article Rendering/main.js index 13f90b638..e485eec5c 100644 --- a/Shared/Article Rendering/main.js +++ b/Shared/Article Rendering/main.js @@ -156,6 +156,78 @@ function removeWpSmiley() { } } +function addYouTubeVideos() { + const titleURL = document.querySelector(".articleTitle A").getAttribute("href") + const youTubeLink = "https://www.youtube.com/watch?v=" + if (!titleURL.startsWith(youTubeLink)) { + return; + } + + // Dynamically add the YouTube frame + const bodyContainer = document.querySelector("#bodyContainer"); + bodyContainer.setAttribute("style", "position: relative; padding-bottom: 56.25%; height: 100%; overflow: hidden;") + + var youTubeFrame = document.createElement("iFrame"); + youTubeFrame.setAttribute("src", "https://www.youtube.com/embed/" + titleURL.substring(youTubeLink.length)); + youTubeFrame.setAttribute("style", "position: absolute; top: 0; left: 0; width: 100%; height: 100%;"); + youTubeFrame.setAttribute("title", "YouTube video player"); + youTubeFrame.setAttribute("frameborder", "0"); + youTubeFrame.setAttribute("allow", "encrypted-media; picture-in-picture; web-share"); + youTubeFrame.setAttribute("allowfullscreen", "true"); + bodyContainer.appendChild(youTubeFrame); + + // No YouTube ADS - YouTube https://github.com/GSRHackZ/No-ADS-YouTube + let ogVolume=1; + let pbRate = 1; + + setInterval(function(){ + if(document.getElementsByClassName("video-stream html5-main-video")[0]!==undefined){ + let ad = document.getElementsByClassName("video-ads ytp-ad-module")[0]; + let vid = document.getElementsByClassName("video-stream html5-main-video")[0]; + if(ad==undefined){ + pbRate = vid.playbackRate; + } + let closeAble = document.getElementsByClassName("ytp-ad-overlay-close-button"); + for(let i=0;i0){ + if(document.getElementsByClassName("ytp-ad-text ytp-ad-preview-text")[0]!==undefined){ + vid.playbackRate=16; + //console.log("Incrementally skipped unskippable ad!") + } + } + } + } + },100) +} + function processPage() { wrapFrames(); wrapTables(); @@ -165,6 +237,7 @@ function processPage() { convertImgSrc(); flattenPreElements(); styleLocalFootnotes(); - removeWpSmiley() + removeWpSmiley(); + addYouTubeVideos(); postRenderProcessing(); } From 5fd5a7a185ffcd5b72dd270f04c732fdbd4de805 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sat, 1 Apr 2023 21:55:15 -0500 Subject: [PATCH 04/18] Add fullscreen video support --- iOS/Article/PreloadedWebView.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iOS/Article/PreloadedWebView.swift b/iOS/Article/PreloadedWebView.swift index 16d2cbf73..99a3e258b 100644 --- a/iOS/Article/PreloadedWebView.swift +++ b/iOS/Article/PreloadedWebView.swift @@ -29,6 +29,9 @@ class PreloadedWebView: WKWebView { configuration.setValue(true, forKey: "allowUniversalAccessFromFileURLs") configuration.allowsInlineMediaPlayback = true configuration.mediaTypesRequiringUserActionForPlayback = .audio + if #available(iOS 15.4, *) { + configuration.preferences.isElementFullscreenEnabled = true + } configuration.setURLSchemeHandler(articleIconSchemeHandler, forURLScheme: ArticleRenderer.imageIconScheme) super.init(frame: .zero, configuration: configuration) From cac4ffd37e3347f8842978c0a0353f71a57687ed Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sat, 1 Apr 2023 21:55:15 -0500 Subject: [PATCH 05/18] Add fullscreen video support --- iOS/Article/PreloadedWebView.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iOS/Article/PreloadedWebView.swift b/iOS/Article/PreloadedWebView.swift index 16d2cbf73..99a3e258b 100644 --- a/iOS/Article/PreloadedWebView.swift +++ b/iOS/Article/PreloadedWebView.swift @@ -29,6 +29,9 @@ class PreloadedWebView: WKWebView { configuration.setValue(true, forKey: "allowUniversalAccessFromFileURLs") configuration.allowsInlineMediaPlayback = true configuration.mediaTypesRequiringUserActionForPlayback = .audio + if #available(iOS 15.4, *) { + configuration.preferences.isElementFullscreenEnabled = true + } configuration.setURLSchemeHandler(articleIconSchemeHandler, forURLScheme: ArticleRenderer.imageIconScheme) super.init(frame: .zero, configuration: configuration) From 8253fce7ba83e05580504583afa2fd28d624ccfa Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sun, 2 Apr 2023 15:18:48 -0500 Subject: [PATCH 06/18] Remove code that didn't do anything when embedding YouTube videos --- Shared/Article Rendering/main.js | 52 -------------------------------- 1 file changed, 52 deletions(-) diff --git a/Shared/Article Rendering/main.js b/Shared/Article Rendering/main.js index e485eec5c..49bfd0804 100644 --- a/Shared/Article Rendering/main.js +++ b/Shared/Article Rendering/main.js @@ -172,60 +172,8 @@ function addYouTubeVideos() { youTubeFrame.setAttribute("style", "position: absolute; top: 0; left: 0; width: 100%; height: 100%;"); youTubeFrame.setAttribute("title", "YouTube video player"); youTubeFrame.setAttribute("frameborder", "0"); - youTubeFrame.setAttribute("allow", "encrypted-media; picture-in-picture; web-share"); youTubeFrame.setAttribute("allowfullscreen", "true"); bodyContainer.appendChild(youTubeFrame); - - // No YouTube ADS - YouTube https://github.com/GSRHackZ/No-ADS-YouTube - let ogVolume=1; - let pbRate = 1; - - setInterval(function(){ - if(document.getElementsByClassName("video-stream html5-main-video")[0]!==undefined){ - let ad = document.getElementsByClassName("video-ads ytp-ad-module")[0]; - let vid = document.getElementsByClassName("video-stream html5-main-video")[0]; - if(ad==undefined){ - pbRate = vid.playbackRate; - } - let closeAble = document.getElementsByClassName("ytp-ad-overlay-close-button"); - for(let i=0;i0){ - if(document.getElementsByClassName("ytp-ad-text ytp-ad-preview-text")[0]!==undefined){ - vid.playbackRate=16; - //console.log("Incrementally skipped unskippable ad!") - } - } - } - } - },100) } function processPage() { From ba39bd45f82a07fa0e3b056fd47aada0965170f9 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sun, 2 Apr 2023 15:46:41 -0500 Subject: [PATCH 07/18] Remove user agent from WKWebView --- Mac/MainWindow/Detail/DetailWebViewController.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/Mac/MainWindow/Detail/DetailWebViewController.swift b/Mac/MainWindow/Detail/DetailWebViewController.swift index b558b04dc..71cca81c8 100644 --- a/Mac/MainWindow/Detail/DetailWebViewController.swift +++ b/Mac/MainWindow/Detail/DetailWebViewController.swift @@ -105,9 +105,6 @@ final class DetailWebViewController: NSViewController { webView.navigationDelegate = self webView.keyboardDelegate = keyboardDelegate webView.translatesAutoresizingMaskIntoConstraints = false - if let userAgent = UserAgent.fromInfoPlist() { - webView.customUserAgent = userAgent - } view = webView From 2a13d6cf8160e5cc6acd9e7c2b2c8dde8034bfc6 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sun, 2 Apr 2023 15:46:41 -0500 Subject: [PATCH 08/18] Remove user agent from WKWebView --- Mac/MainWindow/Detail/DetailWebViewController.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/Mac/MainWindow/Detail/DetailWebViewController.swift b/Mac/MainWindow/Detail/DetailWebViewController.swift index b558b04dc..71cca81c8 100644 --- a/Mac/MainWindow/Detail/DetailWebViewController.swift +++ b/Mac/MainWindow/Detail/DetailWebViewController.swift @@ -105,9 +105,6 @@ final class DetailWebViewController: NSViewController { webView.navigationDelegate = self webView.keyboardDelegate = keyboardDelegate webView.translatesAutoresizingMaskIntoConstraints = false - if let userAgent = UserAgent.fromInfoPlist() { - webView.customUserAgent = userAgent - } view = webView From 366916571ef27be528baf8b33bd727f926266b18 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Tue, 4 Apr 2023 06:16:50 -0500 Subject: [PATCH 09/18] Don't use constraints since they interfere with the fullscreen transition --- iOS/Article/WebViewController.swift | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/iOS/Article/WebViewController.swift b/iOS/Article/WebViewController.swift index 8215abbc1..375a7d926 100644 --- a/iOS/Article/WebViewController.swift +++ b/iOS/Article/WebViewController.swift @@ -521,16 +521,11 @@ private extension WebViewController { webView.ready { - // Add the webview - webView.translatesAutoresizingMaskIntoConstraints = false + // Add the webview - using autolayout will cause fullscreen video to fail and lose the web view + webView.frame = self.view.bounds + webView.autoresizingMask = [.flexibleWidth, .flexibleHeight] self.view.insertSubview(webView, at: 0) - NSLayoutConstraint.activate([ - self.view.leadingAnchor.constraint(equalTo: webView.leadingAnchor), - self.view.trailingAnchor.constraint(equalTo: webView.trailingAnchor), - self.view.topAnchor.constraint(equalTo: webView.topAnchor), - self.view.bottomAnchor.constraint(equalTo: webView.bottomAnchor) - ]) - + // UISplitViewController reports the wrong size to WKWebView which can cause horizontal // rubberbanding on the iPad. This interferes with our UIPageViewController preventing // us from easily swiping between WKWebViews. This hack fixes that. From f21cd774db13b5e6f55e8a329e5a877a0052f8a0 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Tue, 4 Apr 2023 07:26:28 -0500 Subject: [PATCH 10/18] Make YouTube bigger than normal --- Shared/Article Rendering/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Shared/Article Rendering/main.js b/Shared/Article Rendering/main.js index 49bfd0804..f072c9bdd 100644 --- a/Shared/Article Rendering/main.js +++ b/Shared/Article Rendering/main.js @@ -165,7 +165,7 @@ function addYouTubeVideos() { // Dynamically add the YouTube frame const bodyContainer = document.querySelector("#bodyContainer"); - bodyContainer.setAttribute("style", "position: relative; padding-bottom: 56.25%; height: 100%; overflow: hidden;") + bodyContainer.setAttribute("style", "position: relative; padding-bottom: 56.25%; height: 100%; max-width: 100% !important; overflow: hidden;") var youTubeFrame = document.createElement("iFrame"); youTubeFrame.setAttribute("src", "https://www.youtube.com/embed/" + titleURL.substring(youTubeLink.length)); From eefd5d79dabc3d8733ebf1ddd2a8a35e7582e87a Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Thu, 13 Apr 2023 15:59:36 -0500 Subject: [PATCH 11/18] Fix YouTube fullscreen on iOS devices --- .../Detail/DetailWebViewController.swift | 2 + NetNewsWire.xcodeproj/project.pbxproj | 28 +++++++++--- Shared/Article Rendering/inject.js | 44 +++++++++++++++++++ Shared/Article Rendering/main.js | 11 +++-- .../WKUserContentController-Extensions.swift | 21 +++++++++ iOS/Article/WebViewController.swift | 1 + 6 files changed, 95 insertions(+), 12 deletions(-) create mode 100644 Shared/Article Rendering/inject.js create mode 100644 Shared/Extensions/WKUserContentController-Extensions.swift diff --git a/Mac/MainWindow/Detail/DetailWebViewController.swift b/Mac/MainWindow/Detail/DetailWebViewController.swift index 71cca81c8..f1e5b2afe 100644 --- a/Mac/MainWindow/Detail/DetailWebViewController.swift +++ b/Mac/MainWindow/Detail/DetailWebViewController.swift @@ -98,6 +98,8 @@ final class DetailWebViewController: NSViewController { userContentController.add(self, name: MessageName.windowDidScroll) userContentController.add(self, name: MessageName.mouseDidEnter) userContentController.add(self, name: MessageName.mouseDidExit) + userContentController.addUserScript(forResource: "inject", withExtension: "js") + configuration.userContentController = userContentController webView = DetailWebView(frame: NSRect.zero, configuration: configuration) diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 56fae063f..567cad45d 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -207,6 +207,12 @@ 514C16DE24D2EF15009A3AFA /* RSTree in Frameworks */ = {isa = PBXBuildFile; productRef = 514C16DD24D2EF15009A3AFA /* RSTree */; }; 514C16DF24D2EF15009A3AFA /* RSTree in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 514C16DD24D2EF15009A3AFA /* RSTree */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 514C16E124D2EF38009A3AFA /* RSCoreResources in Frameworks */ = {isa = PBXBuildFile; productRef = 514C16E024D2EF38009A3AFA /* RSCoreResources */; }; + 514DE4C129DDFD16001B0D79 /* WKUserContentController-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514DE4C029DDFD16001B0D79 /* WKUserContentController-Extensions.swift */; }; + 514DE4C329DE0609001B0D79 /* inject.js in Resources */ = {isa = PBXBuildFile; fileRef = 514DE4C229DE0609001B0D79 /* inject.js */; }; + 514DE4C429DE0609001B0D79 /* inject.js in Resources */ = {isa = PBXBuildFile; fileRef = 514DE4C229DE0609001B0D79 /* inject.js */; }; + 514DE4C529DE0609001B0D79 /* inject.js in Resources */ = {isa = PBXBuildFile; fileRef = 514DE4C229DE0609001B0D79 /* inject.js */; }; + 514DE4C629DE4536001B0D79 /* WKUserContentController-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514DE4C029DDFD16001B0D79 /* WKUserContentController-Extensions.swift */; }; + 514DE4C729DE4537001B0D79 /* WKUserContentController-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514DE4C029DDFD16001B0D79 /* WKUserContentController-Extensions.swift */; }; 5153A35428DC5CEB0036C545 /* RSCore in Frameworks */ = {isa = PBXBuildFile; productRef = DF2A8F32289BFBD9002455AD /* RSCore */; }; 5154368B229404D1005E1CDF /* FaviconGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F76227716200050506E /* FaviconGenerator.swift */; }; 515A50E6243D07A90089E588 /* ExtensionPointManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A50E5243D07A90089E588 /* ExtensionPointManager.swift */; }; @@ -1228,6 +1234,8 @@ 5148F44A2336DB4700F8CD8B /* MasterTimelineTitleView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MasterTimelineTitleView.xib; sourceTree = ""; }; 5148F4542336DB7000F8CD8B /* MasterTimelineTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterTimelineTitleView.swift; sourceTree = ""; }; 514B7C8223205EFB00BAC947 /* RootSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootSplitViewController.swift; sourceTree = ""; }; + 514DE4C029DDFD16001B0D79 /* WKUserContentController-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WKUserContentController-Extensions.swift"; sourceTree = ""; }; + 514DE4C229DE0609001B0D79 /* inject.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = inject.js; sourceTree = ""; }; 515A50E5243D07A90089E588 /* ExtensionPointManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointManager.swift; sourceTree = ""; }; 515A5147243E64BA0089E588 /* ExtensionPointEnableWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointEnableWindowController.swift; sourceTree = ""; }; 515A516D243E7F950089E588 /* ExtensionPointDetail.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ExtensionPointDetail.xib; sourceTree = ""; }; @@ -2145,13 +2153,14 @@ 51C452A822650DA100C03939 /* Article Rendering */ = { isa = PBXGroup; children = ( - 51D0214526ED617100FF2E0F /* core.css */, - B27EEBDF244D15F2000932E6 /* stylesheet.css */, - 848362FE2262A30E00DA1D35 /* template.html */, - 517630032336215100E15FFF /* main.js */, - 49F40DEF2335B71000552BF4 /* newsfoot.js */, 849A977D1ED9EC42007D329B /* ArticleRenderer.swift */, 51DC07972552083500A3F79F /* ArticleTextSize.swift */, + 51D0214526ED617100FF2E0F /* core.css */, + 514DE4C229DE0609001B0D79 /* inject.js */, + 517630032336215100E15FFF /* main.js */, + 49F40DEF2335B71000552BF4 /* newsfoot.js */, + B27EEBDF244D15F2000932E6 /* stylesheet.css */, + 848362FE2262A30E00DA1D35 /* template.html */, ); path = "Article Rendering"; sourceTree = ""; @@ -2374,6 +2383,7 @@ 51F85BF42273625800C787DC /* Bundle-Extensions.swift */, 5108F6B52375E612001ABC45 /* CacheCleaner.swift */, 516AE9DE2372269A007DEEAA /* IconImage.swift */, + 51D205EE28E3CF8D007C46EF /* LinkTextField.swift */, 849A97971ED9EFAA007D329B /* Node-Extensions.swift */, B24E9ABA245AB88300DA5718 /* NSAttributedString+NetNewsWire.swift */, 519279F728E23F5F000AE856 /* NSEvent-Extensions.swift */, @@ -2382,7 +2392,7 @@ 51126DA3225FDE2F00722696 /* RSImage-Extensions.swift */, 84411E701FE5FBFA004B527F /* SmallIconProvider.swift */, 51BC4ADD247277DF000A6ED8 /* URL-Extensions.swift */, - 51D205EE28E3CF8D007C46EF /* LinkTextField.swift */, + 514DE4C029DDFD16001B0D79 /* WKUserContentController-Extensions.swift */, ); path = Extensions; sourceTree = ""; @@ -3386,6 +3396,7 @@ 65ED406A235DEF6C0081F399 /* newsfoot.js in Resources */, 5103A9992421643300410853 /* blank.html in Resources */, 65ED406B235DEF6C0081F399 /* CrashReporterWindow.xib in Resources */, + 514DE4C429DE0609001B0D79 /* inject.js in Resources */, 65ED406C235DEF6C0081F399 /* Credits.rtf in Resources */, 65ED406D235DEF6C0081F399 /* Inspector.storyboard in Resources */, 65ED406E235DEF6C0081F399 /* AddWebFeedSheet.xib in Resources */, @@ -3426,6 +3437,7 @@ 51DEE81A26FBFF84006DAA56 /* Promenade.nnwtheme in Resources */, 1768140B2564BB8300D98635 /* NetNewsWire_iOSwidgetextension_target.xcconfig in Resources */, 5103A9B424216A4200410853 /* blank.html in Resources */, + 514DE4C529DE0609001B0D79 /* inject.js in Resources */, 51D0214826ED617100FF2E0F /* core.css in Resources */, 84C9FCA42262A1B800D921D6 /* LaunchScreenPhone.storyboard in Resources */, 516A093B2360A4A000EAE89B /* SettingsTableViewCell.xib in Resources */, @@ -3468,6 +3480,7 @@ 5142194B2353C1CF00E07E2C /* main_mac.js in Resources */, DFCE4F9128EF26F100405869 /* About.plist in Resources */, 84C9FC8C22629E8F00D921D6 /* KeyboardShortcuts.html in Resources */, + 514DE4C329DE0609001B0D79 /* inject.js in Resources */, B27EEBF9244D15F3000932E6 /* stylesheet.css in Resources */, 5144EA3B227A379E00D19003 /* ImportOPMLSheet.xib in Resources */, 844B5B691FEA20DF00C7C76A /* SidebarKeyboardShortcuts.plist in Resources */, @@ -3928,6 +3941,7 @@ 519279F928E23F5F000AE856 /* NSEvent-Extensions.swift in Sources */, 65ED4015235DEF6C0081F399 /* AccountsDetailViewController.swift in Sources */, 65ED4016235DEF6C0081F399 /* DetailViewController.swift in Sources */, + 514DE4C729DE4537001B0D79 /* WKUserContentController-Extensions.swift in Sources */, 5117715624E1EA0F00A2A836 /* ArticleExtractorButton.swift in Sources */, 65ED4017235DEF6C0081F399 /* AppDelegate.swift in Sources */, 65ED4018235DEF6C0081F399 /* PreferencesTableViewBackgroundView.swift in Sources */, @@ -4151,6 +4165,7 @@ 84DEE56622C32CA4005FC42C /* SmartFeedDelegate.swift in Sources */, 512E09012268907400BDCFDD /* MasterFeedTableViewSectionHeader.swift in Sources */, 512392BF24E33A3C00F11704 /* RedditSelectSortTableViewController.swift in Sources */, + 514DE4C629DE4536001B0D79 /* WKUserContentController-Extensions.swift in Sources */, 516AE9E02372269A007DEEAA /* IconImage.swift in Sources */, 519ED456244828C3007F8E94 /* AddExtensionPointViewController.swift in Sources */, 51C45268226508F600C03939 /* MasterFeedUnreadCountView.swift in Sources */, @@ -4347,6 +4362,7 @@ 510C418124E5D1AE008226FD /* ExtensionContainers.swift in Sources */, 51EC114C2149FE3300B296E3 /* FolderTreeMenu.swift in Sources */, 849ADEE42359817E000E1B81 /* NNW3ImportController.swift in Sources */, + 514DE4C129DDFD16001B0D79 /* WKUserContentController-Extensions.swift in Sources */, 179C39EB26F76B3800D4E741 /* ArticleThemePlist.swift in Sources */, 849A97A31ED9F180007D329B /* FolderTreeControllerDelegate.swift in Sources */, 51126DA4225FDE2F00722696 /* RSImage-Extensions.swift in Sources */, diff --git a/Shared/Article Rendering/inject.js b/Shared/Article Rendering/inject.js new file mode 100644 index 000000000..957c23af6 --- /dev/null +++ b/Shared/Article Rendering/inject.js @@ -0,0 +1,44 @@ +function fixYouTube() { + var checkForVideoTimer = null; + + function callback(event) { + var fullScreenButtonOld = document.querySelector("button.ytp-fullscreen-button"); + var fullScreenButton = fullScreenButtonOld.cloneNode(true); + fullScreenButton.style = false; + fullScreenButton.setAttribute("aria-disabled", "false"); + fullScreenButton.onclick = function() { + var player = document.querySelector("video"); + player.webkitRequestFullScreen(); + }; + fullScreenButtonOld.parentNode.replaceChild(fullScreenButton, fullScreenButtonOld); + } + + function checkForVideo() { + var video = document.querySelector("video"); + if (video) { + clearInterval(checkForVideoTimer); + + var goFullScreen = function() { + video.webkitRequestFullScreen(); + }; + + var fullScreenButtonOld = document.querySelector("button.ytp-fullscreen-button"); + var fullScreenButton = fullScreenButtonOld.cloneNode(true); + fullScreenButton.style = false; + fullScreenButton.setAttribute("aria-disabled", "false"); + fullScreenButton.onclick = goFullScreen; + fullScreenButtonOld.parentNode.replaceChild(fullScreenButton, fullScreenButtonOld); + } + } + + const hostname = window.location.hostname; + if (hostname.endsWith(".youtube.com") || hostname.endsWith(".youtube-nocookie.com")) { + checkForVideoTimer = setInterval(checkForVideo, 100); + } + + document.addEventListener('webkitfullscreenchange', fullScreenChange, true); +} + +document.addEventListener("DOMContentLoaded", function(event) { + fixYouTube(); +}); diff --git a/Shared/Article Rendering/main.js b/Shared/Article Rendering/main.js index f072c9bdd..53c8f93b3 100644 --- a/Shared/Article Rendering/main.js +++ b/Shared/Article Rendering/main.js @@ -156,19 +156,18 @@ function removeWpSmiley() { } } -function addYouTubeVideos() { +function addYouTubeVideo() { const titleURL = document.querySelector(".articleTitle A").getAttribute("href") const youTubeLink = "https://www.youtube.com/watch?v=" if (!titleURL.startsWith(youTubeLink)) { return; } - - // Dynamically add the YouTube frame + const bodyContainer = document.querySelector("#bodyContainer"); bodyContainer.setAttribute("style", "position: relative; padding-bottom: 56.25%; height: 100%; max-width: 100% !important; overflow: hidden;") - + var youTubeFrame = document.createElement("iFrame"); - youTubeFrame.setAttribute("src", "https://www.youtube.com/embed/" + titleURL.substring(youTubeLink.length)); + youTubeFrame.setAttribute("src", "https://www.youtube.com/embed/" + titleURL.substring(youTubeLink.length) + "?fs=0&rel=0"); youTubeFrame.setAttribute("style", "position: absolute; top: 0; left: 0; width: 100%; height: 100%;"); youTubeFrame.setAttribute("title", "YouTube video player"); youTubeFrame.setAttribute("frameborder", "0"); @@ -186,6 +185,6 @@ function processPage() { flattenPreElements(); styleLocalFootnotes(); removeWpSmiley(); - addYouTubeVideos(); + addYouTubeVideo(); postRenderProcessing(); } diff --git a/Shared/Extensions/WKUserContentController-Extensions.swift b/Shared/Extensions/WKUserContentController-Extensions.swift new file mode 100644 index 000000000..635449185 --- /dev/null +++ b/Shared/Extensions/WKUserContentController-Extensions.swift @@ -0,0 +1,21 @@ +// +// WKUserContentController-Extensions.swift +// NetNewsWire +// +// Created by Maurice Parker on 4/5/23. +// Copyright © 2023 Ranchero Software. All rights reserved. +// + +import Foundation +import WebKit + +extension WKUserContentController { + + func addUserScript(forResource res: String, withExtension ext: String) { + if let url = Bundle.main.url(forResource: res, withExtension: ext), let source = try? String(contentsOf: url) { + let userScript = WKUserScript(source: source, injectionTime: WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: false) + addUserScript(userScript) + } + } + +} diff --git a/iOS/Article/WebViewController.swift b/iOS/Article/WebViewController.swift index 375a7d926..295e2e2ca 100644 --- a/iOS/Article/WebViewController.swift +++ b/iOS/Article/WebViewController.swift @@ -545,6 +545,7 @@ private extension WebViewController { webView.configuration.userContentController.add(WrapperScriptMessageHandler(self), name: MessageName.imageWasClicked) webView.configuration.userContentController.add(WrapperScriptMessageHandler(self), name: MessageName.imageWasShown) webView.configuration.userContentController.add(WrapperScriptMessageHandler(self), name: MessageName.showFeedInspector) + webView.configuration.userContentController.addUserScript(forResource: "inject", withExtension: "js") self.renderPage(webView) From 8b1d892dd717b0cb5e73e420ae6af8e09c2cb00f Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Thu, 13 Apr 2023 16:24:29 -0500 Subject: [PATCH 12/18] Removed unneeded resize event code that isn't needed now that NNW is using the modern UISplitViewController --- iOS/Resources/main_ios.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/iOS/Resources/main_ios.js b/iOS/Resources/main_ios.js index 7c0e56076..3e2b594f2 100644 --- a/iOS/Resources/main_ios.js +++ b/iOS/Resources/main_ios.js @@ -155,18 +155,6 @@ function postRenderProcessing() { showFeedInspectorSetup(); } -function onResize() { - const meta = document.querySelector("meta[name=viewport]"); - - if (!meta) return; - - const originalContent = meta.content; - meta.setAttribute("content", originalContent + ", maximum-scale=1.0"); - meta.setAttribute("content", originalContent); -} -window.addEventListener("resize", onResize); - - function makeHighlightRect({left, top, width, height}, offsetTop=0, offsetLeft=0) { const overlay = document.createElement('a'); From 455fd082ea05c960cbfdf901bb4d6364bd830d3f Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sun, 16 Apr 2023 14:15:53 -0500 Subject: [PATCH 13/18] Fix merge conflict --- iOS/Article/WebViewController.swift | 38 ----------------------------- 1 file changed, 38 deletions(-) diff --git a/iOS/Article/WebViewController.swift b/iOS/Article/WebViewController.swift index 5a2d369ed..52cf28037 100644 --- a/iOS/Article/WebViewController.swift +++ b/iOS/Article/WebViewController.swift @@ -509,47 +509,9 @@ private extension WebViewController { self.renderPage(webView) return } - -<<<<<<< Updated upstream - coordinator.webViewProvider.dequeueWebView() { webView in - - webView.ready { - - // Add the webview - using autolayout will cause fullscreen video to fail and lose the web view - webView.frame = self.view.bounds - webView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - self.view.insertSubview(webView, at: 0) - // UISplitViewController reports the wrong size to WKWebView which can cause horizontal - // rubberbanding on the iPad. This interferes with our UIPageViewController preventing - // us from easily swiping between WKWebViews. This hack fixes that. - webView.scrollView.contentInset = UIEdgeInsets(top: 0, left: -1, bottom: 0, right: 0) - - webView.scrollView.setZoomScale(1.0, animated: false) - - self.view.setNeedsLayout() - self.view.layoutIfNeeded() - - // Configure the webview - webView.navigationDelegate = self - webView.uiDelegate = self - webView.scrollView.delegate = self - self.configureContextMenuInteraction() - - webView.configuration.userContentController.add(WrapperScriptMessageHandler(self), name: MessageName.imageWasClicked) - webView.configuration.userContentController.add(WrapperScriptMessageHandler(self), name: MessageName.imageWasShown) - webView.configuration.userContentController.add(WrapperScriptMessageHandler(self), name: MessageName.showFeedInspector) - webView.configuration.userContentController.addUserScript(forResource: "inject", withExtension: "js") - - self.renderPage(webView) - - } - - } -======= let preferences = WKPreferences() preferences.javaScriptCanOpenWindowsAutomatically = false ->>>>>>> Stashed changes /// The defaults for `preferredContentMode` and `allowsContentJavaScript` are suitable /// and don't need to be explicitly set. From 269d0535bd454e665b8c25d342a3d07f582dea06 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Tue, 10 Oct 2023 20:28:26 -0500 Subject: [PATCH 14/18] Fix for scroll indicators on iOS when using Dark Mode --- iOS/Article/WebViewController.swift | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/iOS/Article/WebViewController.swift b/iOS/Article/WebViewController.swift index 52cf28037..df4b46549 100644 --- a/iOS/Article/WebViewController.swift +++ b/iOS/Article/WebViewController.swift @@ -82,6 +82,28 @@ class WebViewController: UIViewController { } + override func viewWillAppear(_ animated: Bool) { + updateScrollIndicatorStyle() + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + updateScrollIndicatorStyle() + } + + + // See https://shadowfacts.net/2022/wkwebview-scroll-indicators-again/ for why this is necessary. + private func updateScrollIndicatorStyle() { + guard #available(iOS 15.4, *) else { + return + } + + if traitCollection.userInterfaceStyle == .dark { + webView?.scrollView.indicatorStyle = .white + } else { + webView?.scrollView.indicatorStyle = .black + } + } + // MARK: Notifications @objc func webFeedIconDidBecomeAvailable(_ note: Notification) { From 4ab45f09bf412bcaa5fd82b2888084e19a398a55 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Tue, 10 Oct 2023 20:39:08 -0500 Subject: [PATCH 15/18] Remove old view before adding a new webview when doing a full reload. Fixes #3988. --- iOS/Article/WebViewController.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/iOS/Article/WebViewController.swift b/iOS/Article/WebViewController.swift index df4b46549..da3da8ed5 100644 --- a/iOS/Article/WebViewController.swift +++ b/iOS/Article/WebViewController.swift @@ -557,6 +557,7 @@ private extension WebViewController { // Add the webview - using autolayout will cause fullscreen video to fail and lose the web view webView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + self.webView?.removeFromSuperview() self.view.insertSubview(webView, at: 0) // UISplitViewController reports the wrong size to WKWebView which can cause horizontal From 196778f82cd466b2f3f4296e6adebc0a275181ab Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sat, 11 Nov 2023 12:48:49 -0600 Subject: [PATCH 16/18] Remove MainActor since we aren't yet up to date with the latest stuff in main --- Mac/ErrorHandler.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mac/ErrorHandler.swift b/Mac/ErrorHandler.swift index 1d332359c..cd23324f0 100644 --- a/Mac/ErrorHandler.swift +++ b/Mac/ErrorHandler.swift @@ -10,7 +10,7 @@ import AppKit import Account import RSCore -@MainActor struct ErrorHandler: Logging { +struct ErrorHandler: Logging { public static func present(_ error: Error) { NSApplication.shared.presentError(error) From 11ef598201f40be9014e41f744e47c758a9e4d6c Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sat, 11 Nov 2023 12:52:00 -0600 Subject: [PATCH 17/18] Fix right click for ArticleExtractor button on Sonoma. --- Mac/MainWindow/MainWindow.swift | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/Mac/MainWindow/MainWindow.swift b/Mac/MainWindow/MainWindow.swift index 18409f76a..6dd8abf8f 100644 --- a/Mac/MainWindow/MainWindow.swift +++ b/Mac/MainWindow/MainWindow.swift @@ -14,19 +14,31 @@ import Foundation // Since the Toolbar intercepts right clicks we need to stop it from doing that here // so that the ArticleExtractorButton can receive right click events. - if event.isRightClick, - let frameView = contentView?.superview, - let view = frameView.hitTest(frameView.convert(event.locationInWindow, from: nil)), - type(of: view).description() == "NSToolbarView" { + if #available(macOS 14.0, *) { + if event.isRightClick, + let frameView = contentView?.superview, + let view = frameView.hitTest(frameView.convert(event.locationInWindow, from: nil)), + let articleExtractorButton = view as? ArticleExtractorButton { - for subview in view.subviews { - for subsubview in subview.subviews { - let candidateView = subsubview.hitTest(subsubview.convert(event.locationInWindow, from: nil)) - if candidateView is ArticleExtractorButton { - candidateView?.rightMouseDown(with: event) - return + articleExtractorButton.rightMouseDown(with: event) + return + } + } else { + if event.isRightClick, + let frameView = contentView?.superview, + let view = frameView.hitTest(frameView.convert(event.locationInWindow, from: nil)), + type(of: view).description() == "NSToolbarView" { + + for subview in view.subviews { + for subsubview in subview.subviews { + let candidateView = subsubview.hitTest(subsubview.convert(event.locationInWindow, from: nil)) + if candidateView is ArticleExtractorButton { + candidateView?.rightMouseDown(with: event) + return + } } } + } } From 434b495ffd11c4e9584394ba25279ff88b5bcd8e Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sat, 16 Dec 2023 09:32:17 -0600 Subject: [PATCH 18/18] Change Mac state preservation to be NSSecureCoding compliant --- Mac/MainWindow/Detail/DetailWindowState.swift | 9 +++++++++ Mac/MainWindow/MainWindowState.swift | 9 +++++++++ Mac/MainWindow/Sidebar/SidebarWindowState.swift | 9 +++++++++ Mac/MainWindow/Timeline/TimelineWindowState.swift | 9 +++++++++ 4 files changed, 36 insertions(+) create mode 100644 Mac/MainWindow/Detail/DetailWindowState.swift create mode 100644 Mac/MainWindow/MainWindowState.swift create mode 100644 Mac/MainWindow/Sidebar/SidebarWindowState.swift create mode 100644 Mac/MainWindow/Timeline/TimelineWindowState.swift diff --git a/Mac/MainWindow/Detail/DetailWindowState.swift b/Mac/MainWindow/Detail/DetailWindowState.swift new file mode 100644 index 000000000..9f4aced10 --- /dev/null +++ b/Mac/MainWindow/Detail/DetailWindowState.swift @@ -0,0 +1,9 @@ +// +// DetailWindowState.swift +// NetNewsWire +// +// Created by Maurice Parker on 12/16/23. +// Copyright © 2023 Ranchero Software. All rights reserved. +// + +import Foundation diff --git a/Mac/MainWindow/MainWindowState.swift b/Mac/MainWindow/MainWindowState.swift new file mode 100644 index 000000000..2954204aa --- /dev/null +++ b/Mac/MainWindow/MainWindowState.swift @@ -0,0 +1,9 @@ +// +// MainWindowState.swift +// NetNewsWire +// +// Created by Maurice Parker on 12/16/23. +// Copyright © 2023 Ranchero Software. All rights reserved. +// + +import Foundation diff --git a/Mac/MainWindow/Sidebar/SidebarWindowState.swift b/Mac/MainWindow/Sidebar/SidebarWindowState.swift new file mode 100644 index 000000000..ddae52394 --- /dev/null +++ b/Mac/MainWindow/Sidebar/SidebarWindowState.swift @@ -0,0 +1,9 @@ +// +// SidebarWindowState.swift +// NetNewsWire +// +// Created by Maurice Parker on 12/16/23. +// Copyright © 2023 Ranchero Software. All rights reserved. +// + +import Foundation diff --git a/Mac/MainWindow/Timeline/TimelineWindowState.swift b/Mac/MainWindow/Timeline/TimelineWindowState.swift new file mode 100644 index 000000000..18e61b7cd --- /dev/null +++ b/Mac/MainWindow/Timeline/TimelineWindowState.swift @@ -0,0 +1,9 @@ +// +// TimelineWindowState.swift +// NetNewsWire +// +// Created by Maurice Parker on 12/16/23. +// Copyright © 2023 Ranchero Software. All rights reserved. +// + +import Foundation