Implement macOS web view mouse over events
This commit is contained in:
parent
5abf222c8a
commit
107a8fd550
@ -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:
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
import SwiftUI
|
||||
import Articles
|
||||
|
||||
final class ArticleView: NSViewControllerRepresentable {
|
||||
struct ArticleView: NSViewControllerRepresentable {
|
||||
|
||||
var sceneModel: SceneModel
|
||||
var articleModel: ArticleModel
|
||||
|
102
Multiplatform/macOS/Article/WebStatusBarView.swift
Normal file
102
Multiplatform/macOS/Article/WebStatusBarView.swift
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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 */,
|
||||
|
Loading…
x
Reference in New Issue
Block a user