Implement macOS web view mouse over events

This commit is contained in:
Maurice Parker 2020-07-08 22:27:59 -05:00
parent 5abf222c8a
commit 107a8fd550
8 changed files with 186 additions and 16 deletions

View File

@ -282,6 +282,12 @@ struct AppAssets {
#endif
}
#if os(macOS)
static var webStatusBarBackground: NSColor = {
return NSColor(named: "WebStatusBarBackground")!
}()
#endif
static func image(for accountType: AccountType) -> RSImage? {
switch accountType {
case .onMyMac:

View File

@ -140,9 +140,26 @@ function showFeedInspectorSetup() {
}
}
function linkHover() {
window.onmouseover = function(event) {
var closestAnchor = event.target.closest('a')
if (closestAnchor) {
window.webkit.messageHandlers.mouseDidEnter.postMessage(closestAnchor.href);
}
}
window.onmouseout = function(event) {
var closestAnchor = event.target.closest('a')
if (closestAnchor) {
window.webkit.messageHandlers.mouseDidExit.postMessage(closestAnchor.href);
}
}
}
function postRenderProcessing() {
ImageViewer.init();
showFeedInspectorSetup();
linkHover();
}

View File

@ -10,7 +10,6 @@
<script src="newsfoot.js" async="async"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
window.scrollTo(0, [[windowScrollY]]);
processPage();
})
</script>

View File

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.940",
"green" : "0.940",
"red" : "0.940"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -9,7 +9,7 @@
import SwiftUI
import Articles
final class ArticleView: NSViewControllerRepresentable {
struct ArticleView: NSViewControllerRepresentable {
var sceneModel: SceneModel
var articleModel: ArticleModel

View File

@ -0,0 +1,102 @@
//
// WebStatusBarView.swift
// Multiplatform macOS
//
// Created by Maurice Parker on 7/8/20.
// Copyright © 2020 Ranchero Software. All rights reserved.
//
import AppKit
import Articles
final class WebStatusBarView: NSView {
var urlLabel = NSTextField(labelWithString: "")
var mouseoverLink: String? {
didSet {
updateLinkForDisplay()
}
}
private var linkForDisplay: String? {
didSet {
needsLayout = true
if let link = linkForDisplay {
urlLabel.stringValue = link
self.isHidden = false
}
else {
urlLabel.stringValue = ""
self.isHidden = true
}
}
}
private var didConfigureLayerRadius = false
override var isOpaque: Bool {
return false
}
override var isFlipped: Bool {
return true
}
override var wantsUpdateLayer: Bool {
return true
}
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
override func updateLayer() {
guard let layer = layer else {
return
}
if !didConfigureLayerRadius {
layer.cornerRadius = 4.0
didConfigureLayerRadius = true
}
let color = self.effectiveAppearance.isDarkMode ? NSColor.textBackgroundColor : AppAssets.webStatusBarBackground
layer.backgroundColor = color.cgColor
}
}
// MARK: - Private
private extension WebStatusBarView {
func commonInit() {
self.isHidden = true
urlLabel.translatesAutoresizingMaskIntoConstraints = false
urlLabel.lineBreakMode = .byTruncatingMiddle
urlLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
addSubview(urlLabel)
NSLayoutConstraint.activate([
leadingAnchor.constraint(equalTo: urlLabel.leadingAnchor, constant: -6),
trailingAnchor.constraint(equalTo: urlLabel.trailingAnchor, constant: 6),
centerYAnchor.constraint(equalTo: urlLabel.centerYAnchor)
])
}
func updateLinkForDisplay() {
if let mouseoverLink = mouseoverLink, !mouseoverLink.isEmpty {
linkForDisplay = mouseoverLink.strippingHTTPOrHTTPSScheme
}
else {
linkForDisplay = nil
}
}
}

View File

@ -27,9 +27,13 @@ class WebViewController: NSViewController {
private struct MessageName {
static let imageWasClicked = "imageWasClicked"
static let imageWasShown = "imageWasShown"
static let mouseDidEnter = "mouseDidEnter"
static let mouseDidExit = "mouseDidExit"
static let showFeedInspector = "showFeedInspector"
}
var statusBarView: WebStatusBarView!
private var webView: PreloadedWebView?
private var articleExtractor: ArticleExtractor? = nil
@ -60,6 +64,16 @@ class WebViewController: NSViewController {
DistributedNotificationCenter.default().addObserver(self, selector: #selector(appleColorPreferencesChanged(_:)), name: .appleColorPreferencesChangedNotification, object: nil)
DistributedNotificationCenter.default().addObserver(self, selector: #selector(appleInterfaceThemeChanged(_:)), name: .appleInterfaceThemeChangedNotification, object: nil)
statusBarView = WebStatusBarView()
statusBarView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(statusBarView)
NSLayoutConstraint.activate([
self.view.leadingAnchor.constraint(equalTo: statusBarView.leadingAnchor, constant: -6),
self.view.trailingAnchor.constraint(greaterThanOrEqualTo: statusBarView.trailingAnchor, constant: 6),
self.view.bottomAnchor.constraint(equalTo: statusBarView.bottomAnchor, constant: 2),
statusBarView.heightAnchor.constraint(equalToConstant: 20)
])
loadWebView()
}
@ -178,6 +192,12 @@ extension WebViewController: WKScriptMessageHandler {
return
case MessageName.imageWasClicked:
return
case MessageName.mouseDidEnter:
if let link = message.body as? String {
statusBarView.mouseoverLink = link
}
case MessageName.mouseDidExit:
statusBarView.mouseoverLink = nil
case MessageName.showFeedInspector:
return
default:
@ -201,7 +221,7 @@ private extension WebViewController {
// Add the webview
webView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(webView)
self.view.addSubview(webView, positioned: .below, relativeTo: self.statusBarView)
NSLayoutConstraint.activate([
self.view.leadingAnchor.constraint(equalTo: webView.leadingAnchor),
self.view.trailingAnchor.constraint(equalTo: webView.trailingAnchor),
@ -211,6 +231,8 @@ 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.mouseDidEnter)
webView.configuration.userContentController.add(WrapperScriptMessageHandler(self), name: MessageName.mouseDidExit)
webView.configuration.userContentController.add(WrapperScriptMessageHandler(self), name: MessageName.showFeedInspector)
self.renderPage(webView)

View File

@ -333,6 +333,7 @@
51B54AB324B5AC830014348B /* ArticleExtractorButtonState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5177472124B38CAE00EB0F74 /* ArticleExtractorButtonState.swift */; };
51B54AB624B5B33C0014348B /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B54AB524B5B33C0014348B /* WebViewController.swift */; };
51B54ABC24B5BEF20014348B /* ArticleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B54ABB24B5BEF20014348B /* ArticleView.swift */; };
51B54B6724B6A7960014348B /* WebStatusBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B54B6624B6A7960014348B /* WebStatusBarView.swift */; };
51B5C87723F22B8200032075 /* ExtensionContainers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B5C87623F22B8200032075 /* ExtensionContainers.swift */; };
51B5C87B23F2317700032075 /* ExtensionFeedAddRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B5C87A23F2317700032075 /* ExtensionFeedAddRequest.swift */; };
51B5C87D23F2346200032075 /* ExtensionContainersFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B5C87C23F2346200032075 /* ExtensionContainersFile.swift */; };
@ -1981,6 +1982,7 @@
51B54A6824B54A490014348B /* IconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconView.swift; sourceTree = "<group>"; };
51B54AB524B5B33C0014348B /* WebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = "<group>"; };
51B54ABB24B5BEF20014348B /* ArticleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleView.swift; sourceTree = "<group>"; };
51B54B6624B6A7960014348B /* WebStatusBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebStatusBarView.swift; sourceTree = "<group>"; };
51B5C87623F22B8200032075 /* ExtensionContainers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionContainers.swift; sourceTree = "<group>"; };
51B5C87A23F2317700032075 /* ExtensionFeedAddRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionFeedAddRequest.swift; sourceTree = "<group>"; };
51B5C87C23F2346200032075 /* ExtensionContainersFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionContainersFile.swift; sourceTree = "<group>"; };
@ -2734,9 +2736,10 @@
5177470C24B2FF3B00EB0F74 /* Article */ = {
isa = PBXGroup;
children = (
51B54AB524B5B33C0014348B /* WebViewController.swift */,
51B54A6824B54A490014348B /* IconView.swift */,
51B54ABB24B5BEF20014348B /* ArticleView.swift */,
51B54A6824B54A490014348B /* IconView.swift */,
51B54B6624B6A7960014348B /* WebStatusBarView.swift */,
51B54AB524B5B33C0014348B /* WebViewController.swift */,
);
path = Article;
sourceTree = "<group>";
@ -4135,46 +4138,46 @@
TargetAttributes = {
51314636235A7BBE00387FDC = {
CreatedOnToolsVersion = 11.2;
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
LastSwiftMigration = 1120;
ProvisioningStyle = Automatic;
};
513C5CE5232571C2003D4054 = {
CreatedOnToolsVersion = 11.0;
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
};
518B2ED12351B3DD00400001 = {
CreatedOnToolsVersion = 11.2;
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
TestTargetID = 840D617B2029031C009BC708;
};
51C0513C24A77DF800194D5E = {
CreatedOnToolsVersion = 12.0;
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
};
51C0514324A77DF800194D5E = {
CreatedOnToolsVersion = 12.0;
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
};
6581C73220CED60000F4AD34 = {
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
};
65ED3FA2235DEF6C0081F399 = {
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
};
65ED4090235DEF770081F399 = {
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
};
840D617B2029031C009BC708 = {
CreatedOnToolsVersion = 9.3;
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.BackgroundModes = {
@ -4184,7 +4187,7 @@
};
849C645F1ED37A5D003D8FC0 = {
CreatedOnToolsVersion = 8.2.1;
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.HardenedRuntime = {
@ -4194,7 +4197,7 @@
};
849C64701ED37A5D003D8FC0 = {
CreatedOnToolsVersion = 8.2.1;
DevelopmentTeam = FQLBNX3GP7;
DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic;
TestTargetID = 849C645F1ED37A5D003D8FC0;
};
@ -5184,6 +5187,7 @@
51E4991F24A8094300B667CB /* RSImage-AppIcons.swift in Sources */,
51A5769724AE617200078888 /* ArticleContainerView.swift in Sources */,
51E4991224A808FB00B667CB /* AddWebFeedDefaultContainer.swift in Sources */,
51B54B6724B6A7960014348B /* WebStatusBarView.swift in Sources */,
51E4993E24A870F900B667CB /* UserNotificationManager.swift in Sources */,
51E4992E24A8676300B667CB /* FetchRequestQueue.swift in Sources */,
51E498CF24A8085D00B667CB /* SmartFeed.swift in Sources */,