As a follow-up to How do I get the selected text from a WKWebView from objective-C, I have a related question but using Swift.
I need to obtain the URL on mouse over, in prelude to contextual menu appearance, so I can inject it into the menu item's respresentedObject - or otherwise save. The built-in action(s) for some items are not being properly handled.
I find that menu item action for 'Open Link' works fine but not for 'Open Link in New Window'; neither of these work via the built-in contextual menu item actions. I wanted to support a middle button click to be the latter menu item.
So, using the original post as a base I have this - I also sub-class WkWebView, adding
class MyWebView : WKWebView {
var selectedText : String?
var selectedURL : URL?
}
then in view controller
func viewDidLoad() {
// Watch javascript selection messages
let controller = webView.configuration.userContentController
controller.add(self, name: "newSelectionDetected")
let js = """
function getSelectionAndSendMessage()
{
var txt = document.getSelection().toString() ;
window.webkit.messageHandlers.newSelectionDetected.postMessage(txt) ;
}
document.onmouseup = getSelectionAndSendMessage ;
document.onkeyup = getSelectionAndSendMessage ;
"""
let script = WKUserScript.init(source: js, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
controller.addUserScript(script)
}
// MARK: Javascript
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
Swift.print("userContentController")
// A new selected text has been received
if let urlString : String = message.body as? String
{
webView.selectedText = urlString
Swift.print("ucc: str -> \(urlString)")
}
if let url = message.frameInfo.request.url {
webView.selectedURL = url
Swift.print("ucc: url -> \(url.absoluteString)")
}
}
// MARK: callbacks
override func willOpenMenu(_ menu: NSMenu, with event: NSEvent) {
// Pick off javascript items we want to ignore or handle
for title in ["Open Link", "Open Link in New Window", "Download Linked File"] {
if let item = menu.item(withTitle: title) {
if title == "Download Linked File" {
menu.removeItem(item)
}
else
if title == "Open Link"
{
item.representedObject = self.window
item.action = #selector(MyWebView.openLinkInWindow(_:))
item.target = self
}
else
{
item.action = #selector(MyWebView.openLinkNewWindow(_:))
item.target = self
}
}
}
}
In my action handler, I'm only getting the frame's URL, not what was highlighted on mouse over.
What I need, is to get the URL etc as shown in a web browser's status bar on mouse overs to be cached for a contextual menu item's action.