diff --git a/Mac/AppDefaults.swift b/Mac/AppDefaults.swift index f7d8a8217..175d75dc8 100644 --- a/Mac/AppDefaults.swift +++ b/Mac/AppDefaults.swift @@ -36,6 +36,9 @@ struct AppDefaults { static let timelineShowsSeparators = "CorreiaSeparators" static let showTitleOnMainWindow = "KafasisTitleMode" static let hideDockUnreadCount = "JustinMillerHideDockUnreadCount" + + static let webInspectorEnabled = "WebInspectorEnabled" + static let webInspectorStartsAttached = "__WebInspectorPageGroupLevel1__.WebKit2InspectorStartsAttached" } private static let smallestFontSizeRawValue = FontSize.small.rawValue @@ -138,6 +141,24 @@ struct AppDefaults { return bool(for: Key.hideDockUnreadCount) } + static var webInspectorEnabled: Bool { + get { + return bool(for: Key.webInspectorEnabled) + } + set { + setBool(for: Key.webInspectorEnabled, newValue) + } + } + + static var webInspectorStartsAttached: Bool { + get { + return bool(for: Key.webInspectorStartsAttached) + } + set { + setBool(for: Key.webInspectorStartsAttached, newValue) + } + } + static var timelineSortDirection: ComparisonResult { get { return sortDirection(for: Key.timelineSortDirection) diff --git a/Mac/AppDelegate.swift b/Mac/AppDelegate.swift index f1a3673ef..dd0276976 100644 --- a/Mac/AppDelegate.swift +++ b/Mac/AppDelegate.swift @@ -309,6 +309,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, if item.action == #selector(showAddFeedWindow(_:)) || item.action == #selector(showAddFolderWindow(_:)) { return !isDisplayingSheet && !AccountManager.shared.activeAccounts.isEmpty } + if item.action == #selector(toggleWebInspectorEnabled(_:)) { + (item as! NSMenuItem).state = AppDefaults.webInspectorEnabled ? .on : .off + } return true } @@ -525,6 +528,18 @@ extension AppDelegate { @IBAction func debugSearch(_ sender: Any?) { AccountManager.shared.defaultAccount.debugRunSearch() } + + @IBAction func toggleWebInspectorEnabled(_ sender: Any?) { + let newValue = !AppDefaults.webInspectorEnabled + AppDefaults.webInspectorEnabled = newValue + + // An attached inspector can display incorrectly on certain setups (like mine); default to displaying in a separate window, + // and reset the default to a separate window when the preference is toggled off and on again in case the inspector is + // accidentally reattached. + + AppDefaults.webInspectorStartsAttached = false + NotificationCenter.default.post(name: .WebInspectorEnabledDidChange, object: newValue) + } } private extension AppDelegate { diff --git a/Mac/Base.lproj/Main.storyboard b/Mac/Base.lproj/Main.storyboard index 8d270183a..e12b64504 100644 --- a/Mac/Base.lproj/Main.storyboard +++ b/Mac/Base.lproj/Main.storyboard @@ -469,6 +469,13 @@ + + + + + + + diff --git a/Mac/MainWindow/Detail/DetailWebViewController.swift b/Mac/MainWindow/Detail/DetailWebViewController.swift index b4b92ad52..9e889db4b 100644 --- a/Mac/MainWindow/Detail/DetailWebViewController.swift +++ b/Mac/MainWindow/Detail/DetailWebViewController.swift @@ -27,6 +27,15 @@ final class DetailWebViewController: NSViewController, WKUIDelegate { } } } + + private var webInspectorEnabled: Bool { + get { + return webView.configuration.preferences._developerExtrasEnabled + } + set { + webView.configuration.preferences._developerExtrasEnabled = newValue + } + } private var waitingForFirstReload = false private let keyboardDelegate = DetailKeyboardDelegate() @@ -87,6 +96,10 @@ final class DetailWebViewController: NSViewController, WKUIDelegate { webView.isHidden = true waitingForFirstReload = true + webInspectorEnabled = AppDefaults.webInspectorEnabled + + NotificationCenter.default.addObserver(self, selector: #selector(webInspectorEnabledDidChange(_:)), name: .WebInspectorEnabledDidChange, object: nil) + reloadHTML() } @@ -185,6 +198,10 @@ private extension DetailWebViewController { callback(scrollInfo) } } + + @objc func webInspectorEnabledDidChange(_ notification: Notification) { + self.webInspectorEnabled = notification.object! as! Bool + } } // MARK: - ScrollInfo diff --git a/Mac/NetNewsWire-Bridging-Header.h b/Mac/NetNewsWire-Bridging-Header.h new file mode 100644 index 000000000..3f547bcf1 --- /dev/null +++ b/Mac/NetNewsWire-Bridging-Header.h @@ -0,0 +1,9 @@ +// +// NetNewsWire-Bridging-Header.h +// NetNewsWire +// +// Created by Nate Weaver on 2019-09-17. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +#import "WKPreferencesPrivate.h" diff --git a/Mac/WKPreferencesPrivate.h b/Mac/WKPreferencesPrivate.h new file mode 100644 index 000000000..232e10fc1 --- /dev/null +++ b/Mac/WKPreferencesPrivate.h @@ -0,0 +1,15 @@ +// +// WKPreferencesPrivate.h +// NetNewsWire +// +// Created by Nate Weaver on 2019-09-17. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +#import + +@interface WKPreferences (Private) + +@property (nonatomic, setter=_setDeveloperExtrasEnabled:) BOOL _developerExtrasEnabled API_AVAILABLE(macos(10.11), ios(9.0)); + +@end diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 9cedff112..d7a7360bd 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -917,6 +917,8 @@ 84F9EAE4213660A100CF2DE4 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 84FB9A2D1EDCD6B8003D53B9 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = Frameworks/Vendor/Sparkle.framework; sourceTree = SOURCE_ROOT; }; 84FF69B01FC3793300DC198E /* FaviconURLFinder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconURLFinder.swift; sourceTree = ""; }; + B24EFD482330FF99006C6242 /* NetNewsWire-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NetNewsWire-Bridging-Header.h"; sourceTree = ""; }; + B24EFD5923310109006C6242 /* WKPreferencesPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WKPreferencesPrivate.h; sourceTree = ""; }; D553737C20186C1F006D8857 /* Article+Scriptability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Article+Scriptability.swift"; sourceTree = ""; }; D57BE6DF204CD35F00D11AAC /* NSScriptCommand+NetNewsWire.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSScriptCommand+NetNewsWire.swift"; sourceTree = ""; }; D5907CDC2002F0BE005947E5 /* NetNewsWire_project_release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetNewsWire_project_release.xcconfig; sourceTree = ""; }; @@ -1585,6 +1587,8 @@ 6581C73620CED60100F4AD34 /* SafariExtension */, 84C9FC8322629E8F00D921D6 /* Resources */, 84FB9A2C1EDCD6A4003D53B9 /* Frameworks */, + B24EFD482330FF99006C6242 /* NetNewsWire-Bridging-Header.h */, + B24EFD5923310109006C6242 /* WKPreferencesPrivate.h */, ); path = Mac; sourceTree = ""; @@ -3087,6 +3091,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.14.4; PRODUCT_BUNDLE_IDENTIFIER = "com.ranchero.NetNewsWire-Evergreen"; PRODUCT_NAME = NetNewsWire; + SWIFT_OBJC_BRIDGING_HEADER = "Mac/NetNewsWire-Bridging-Header.h"; }; name = Debug; }; @@ -3102,6 +3107,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.14.4; PRODUCT_BUNDLE_IDENTIFIER = "com.ranchero.NetNewsWire-Evergreen"; PRODUCT_NAME = NetNewsWire; + SWIFT_OBJC_BRIDGING_HEADER = "Mac/NetNewsWire-Bridging-Header.h"; }; name = Release; }; diff --git a/Shared/AppNotifications.swift b/Shared/AppNotifications.swift index b847f1988..3fd03355a 100644 --- a/Shared/AppNotifications.swift +++ b/Shared/AppNotifications.swift @@ -13,6 +13,7 @@ extension Notification.Name { static let InspectableObjectsDidChange = Notification.Name("TimelineSelectionDidChangeNotification") static let UserDidAddFeed = Notification.Name("UserDidAddFeedNotification") static let UserDidRequestSidebarSelection = Notification.Name("UserDidRequestSidebarSelectionNotification") + static let WebInspectorEnabledDidChange = Notification.Name("WebInspectorEnabledDidChange") } typealias UserInfoDictionary = [AnyHashable: Any]