How to call a function inside WebView from the menu bar item in SwiftUI?

347 Views Asked by At

so I'll keep it short. I have the following function inside my WKNavigationDelegate:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    
    DispatchQueue.main.asyncAfter(deadline: .now() + 7.5) {

        webView.evaluateJavaScript("document.getElementById('notes').innerHTML") { [self] (string, error) in
            print(string)
       writeFile(outputFile: "yourfile.doc", stringData: string as! String)
    }}
    
    func writeFile(outputFile:String, stringData: String){
        
        let savePanel = NSSavePanel()
           savePanel.allowedFileTypes = ["doc"]
           savePanel.canCreateDirectories = true
           savePanel.isExtensionHidden = false
         
           
           // Present the save panel as a modal window.
           let response = savePanel.runModal()
           guard response == .OK, let saveURL = savePanel.url else { return }
        
        guard let data = stringData.data(using: .utf8) else{
            print("unable to convert string to data")
            return
        }
        
           try? data.write(to: saveURL)
        
    }
    

}

However I don't wanna call this function automatically through DispatchQueue (I just tried that for testing purposes to see if my function works or not). I want to call this entire function though a menu bar items that I have listed as follows:

   var body: some Scene {
      WindowGroup {
        ContentView()
        
    
        }.windowStyle(HiddenTitleBarWindowStyle())
        .commands {
              CommandMenu("Export") {
                Button("Export as Doc") {
      \\ I WANNA CALL IT HERE
                    print("You Export as Doc") }

                  
              }
            
            }
   

So can anyone help me with how to call a function inside web view through menu bar? I know it might sound like a trivial question because it comes down to basic swift operations but I'm still relatively new to SwiftUI and learning every single day. Thanks in advance!

EDIT: Content View code as follow:

struct ContentView: View {
  private var url: URL? = URL(string
   "https://mywebsite.com/")

  init() {
 print("Hello World")
   }

   var body: some View {  
WebView(data: WebViewData(url: self.url!))
      .frame(minWidth: 1400, idealWidth: 1500, minHeight: 850,   idealHeight: 850)
  
     }

     }

PS: This is a macOS app btw if it's not clear already.

1

There are 1 best solutions below

2
On

A possible approach is to use responder chain (because WKWebView is-a NSView on macOS and so is-a NSResponder), so action sent from main menu goes down to responder chain till some responder handles it.

I cannot test your code part with your loaded page, but at least can guaranty that action is called and you get control there.

Tested with Xcode 14 / macOS 12.5

  1. menu command just send action in responder chain
 Button("Export as Doc") {
    print("You Export as Doc")

    // selector can be declared in NSObject extension and
    // overridden in WKWebView, but here is direct for simplicity
    NSApp.sendAction(#selector(WKWebView.export(_:)), to: nil, from: nil)
 }
  1. implement support of action in WKWebView extension
extension WKWebView {
    @objc func export(_ sender: Any) {
        self.evaluateJavaScript("document.getElementById('notes').innerHTML") { [self] (string, error) in
            print(string)
            writeFile(outputFile: "yourfile.doc", stringData: string as! String)
        }
    }

    func writeFile(outputFile:String, stringData: String) {
      // other code ...
    }
}

*assuming menu validation and export code is out of scope