From 9ac2d7d033c6ea4b9df151b1e91dafae5ae7f797 Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Sat, 10 Feb 2018 11:16:09 -0800 Subject: [PATCH] Create a WKWebView subclass (ugh) in order to hide items in its contextual menu. Fix #120. --- Evergreen.xcodeproj/project.pbxproj | 4 ++ .../Detail/DetailViewController.swift | 4 +- .../MainWindow/Detail/DetailWebView.swift | 66 +++++++++++++++++++ 3 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 Evergreen/MainWindow/Detail/DetailWebView.swift diff --git a/Evergreen.xcodeproj/project.pbxproj b/Evergreen.xcodeproj/project.pbxproj index ad0dbe098..f6bd047ff 100644 --- a/Evergreen.xcodeproj/project.pbxproj +++ b/Evergreen.xcodeproj/project.pbxproj @@ -137,6 +137,7 @@ 84E46C7D1F75EF7B005ECFB3 /* AppDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E46C7C1F75EF7B005ECFB3 /* AppDefaults.swift */; }; 84E850861FCB60CE0072EA88 /* AuthorAvatarDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E850851FCB60CE0072EA88 /* AuthorAvatarDownloader.swift */; }; 84E8E0DB202EC49300562D8F /* TimelineViewController+ContextualMenus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E8E0DA202EC49300562D8F /* TimelineViewController+ContextualMenus.swift */; }; + 84E8E0EB202F693600562D8F /* DetailWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E8E0EA202F693600562D8F /* DetailWebView.swift */; }; 84E95CF71FABB3C800552D99 /* FeedList.plist in Resources */ = {isa = PBXBuildFile; fileRef = 84E95CF61FABB3C800552D99 /* FeedList.plist */; }; 84E95D241FB1087500552D99 /* ArticlePasteboardWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E95D231FB1087500552D99 /* ArticlePasteboardWriter.swift */; }; 84EB381F1FBA8B9F000D2111 /* KeyboardShortcuts.html in Resources */ = {isa = PBXBuildFile; fileRef = 84EB38101FBA8B9F000D2111 /* KeyboardShortcuts.html */; }; @@ -631,6 +632,7 @@ 84E46C7C1F75EF7B005ECFB3 /* AppDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDefaults.swift; path = Evergreen/AppDefaults.swift; sourceTree = ""; }; 84E850851FCB60CE0072EA88 /* AuthorAvatarDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthorAvatarDownloader.swift; sourceTree = ""; }; 84E8E0DA202EC49300562D8F /* TimelineViewController+ContextualMenus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TimelineViewController+ContextualMenus.swift"; sourceTree = ""; }; + 84E8E0EA202F693600562D8F /* DetailWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailWebView.swift; sourceTree = ""; }; 84E95CF61FABB3C800552D99 /* FeedList.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = FeedList.plist; sourceTree = ""; }; 84E95D231FB1087500552D99 /* ArticlePasteboardWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticlePasteboardWriter.swift; sourceTree = ""; }; 84EB38101FBA8B9F000D2111 /* KeyboardShortcuts.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = KeyboardShortcuts.html; sourceTree = ""; }; @@ -972,6 +974,7 @@ isa = PBXGroup; children = ( 849A977E1ED9EC42007D329B /* DetailViewController.swift */, + 84E8E0EA202F693600562D8F /* DetailWebView.swift */, 849A977D1ED9EC42007D329B /* ArticleRenderer.swift */, 84D52E941FE588BB00D14F5B /* DetailStatusBarView.swift */, 849A979A1ED9EFEB007D329B /* styleSheet.css */, @@ -1910,6 +1913,7 @@ D5F4EDB920074D7C00B9E363 /* Folder+Scriptability.swift in Sources */, 842611A01FCB72600086A189 /* FeaturedImageDownloader.swift in Sources */, 849A97781ED9EC04007D329B /* TimelineCellLayout.swift in Sources */, + 84E8E0EB202F693600562D8F /* DetailWebView.swift in Sources */, 84CC08061FF5D2E000C0C0ED /* FeedListSplitViewController.swift in Sources */, 849A976C1ED9EBC8007D329B /* TimelineTableRowView.swift in Sources */, 849A977B1ED9EC04007D329B /* UnreadIndicatorView.swift in Sources */, diff --git a/Evergreen/MainWindow/Detail/DetailViewController.swift b/Evergreen/MainWindow/Detail/DetailViewController.swift index 6bcfe7645..64a6c82b9 100644 --- a/Evergreen/MainWindow/Detail/DetailViewController.swift +++ b/Evergreen/MainWindow/Detail/DetailViewController.swift @@ -16,7 +16,7 @@ final class DetailViewController: NSViewController, WKNavigationDelegate, WKUIDe @IBOutlet var containerView: DetailContainerView! - var webview: WKWebView! + var webview: DetailWebView! var noSelectionView: NoSelectionView! var article: Article? { @@ -54,7 +54,7 @@ final class DetailViewController: NSViewController, WKNavigationDelegate, WKUIDe userContentController.add(self, name: MessageName.mouseDidExit) configuration.userContentController = userContentController - webview = WKWebView(frame: self.view.bounds, configuration: configuration) + webview = DetailWebView(frame: self.view.bounds, configuration: configuration) webview.uiDelegate = self webview.navigationDelegate = self webview.translatesAutoresizingMaskIntoConstraints = false diff --git a/Evergreen/MainWindow/Detail/DetailWebView.swift b/Evergreen/MainWindow/Detail/DetailWebView.swift new file mode 100644 index 000000000..2492622d8 --- /dev/null +++ b/Evergreen/MainWindow/Detail/DetailWebView.swift @@ -0,0 +1,66 @@ +// +// DetailWebView.swift +// Evergreen +// +// Created by Brent Simmons on 2/10/18. +// Copyright © 2018 Ranchero Software. All rights reserved. +// + +import AppKit +import WebKit + +// There’s no API for affecting a WKWebView’s contextual menu. +// (WebView had API for this.) +// +// This a minor hack. It hides unwanted menu items. +// The menu item identifiers are not documented anywhere; +// they could change, and this code would need updating. + +final class DetailWebView: WKWebView { + + // MARK: NSView + + override func willOpenMenu(_ menu: NSMenu, with event: NSEvent) { + + for menuItem in menu.items { + if shouldHideMenuItem(menuItem) { + menuItem.isHidden = true + } + } + + super.willOpenMenu(menu, with: event) + } +} + +private extension NSUserInterfaceItemIdentifier { + + static let DetailMenuItemIdentifierReload = NSUserInterfaceItemIdentifier(rawValue: "WKMenuItemIdentifierReload") + static let DetailMenuItemIdentifierOpenLink = NSUserInterfaceItemIdentifier(rawValue: "WKMenuItemIdentifierOpenLink") +} + +private extension DetailWebView { + + static let menuItemIdentifiersToHide: [NSUserInterfaceItemIdentifier] = [.DetailMenuItemIdentifierReload, .DetailMenuItemIdentifierOpenLink] + static let menuItemIdentifierMatchStrings = ["newwindow", "download"] + + func shouldHideMenuItem(_ menuItem: NSMenuItem) -> Bool { + + guard let identifier = menuItem.identifier else { + return false + } + + if DetailWebView.menuItemIdentifiersToHide.contains(identifier) { + return true + } + + let lowerIdentifier = identifier.rawValue.lowercased() + for matchString in DetailWebView.menuItemIdentifierMatchStrings { + if lowerIdentifier.contains(matchString) { + return true + } + } + + return false + } +} +