// // BrowserViewController+WebKitDelegate.swift // App // // Created by James Magahern on 2/17/21. // import WebKit extension BrowserViewController: WKNavigationDelegate, WKUIDelegate { func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { currentTab.loadError = nil // Check to make sure we have connected to the web content process if !currentTab.bridge.webContentProcessConnected { // This means we started loading a page but the web content process hasn't loaded, which means // scripts are not getting blocked. // If you're ad-hoc signing this, you'll need to disable library validation: // sudo defaults write /Library/Preferences/com.apple.security.libraryvalidation DisableLibraryValidation -bool YES DispatchQueue.main.async { [unowned self] in // Stop loading now webView.stopLoading() // Show an alert let alert = UIAlertController(title: "Web Process Not Loaded", message: "The web content process never contacted the host application", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in alert.dismiss(animated: true, completion: nil) })) present(alert, animated: true, completion: nil) } } // Reset tracking this currentTab.allowedScriptOrigins.removeAll() currentTab.blockedScriptOrigins.removeAll() updateScriptBlockerButton() // Blur url bar if applicable toolbarController.urlBar.textField.resignFirstResponder() updateTitleAndURL(forWebView: webView) if let url = webView.url { // Start requesting favicon currentTab.updateFaviconForURL(url) } } func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) { // We got rugged!!!!!! Update the favicon again. if let url = webView.url { // Start requesting favicon currentTab.updateFaviconForURL(url) } } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { toolbarController.urlBar.loadProgress = .complete // Update history if let url = webView.url { let title = webView.title ?? "" BrowserHistory.shared.didNavigate(toURL: url, title: title) } // Publish Tabs AttractorServer.shared.publishTabInfo(tabController.tabs.map { $0.tabInfo }) } func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, preferences: WKWebpagePreferences, decisionHandler: @escaping (WKNavigationActionPolicy, WKWebpagePreferences) -> Void) { // Handle command+click if (commandKeyHeld || windowButtonHeld) && navigationAction.navigationType == .linkActivated { // Cancel navigation in this tab decisionHandler(.cancel, preferences) // Start navigation in a new tab createNewTab(withURL: navigationAction.request.url, loadInBackground: self.shiftKeyHeld) // Reset this flag. commandKeyHeld = false windowButtonHeld = false return } var allowJavaScript = currentTab.javaScriptEnabled if !allowJavaScript, let host = navigationAction.request.url?.host { // Check origin policy allowJavaScript = policyManager.scriptPolicy(forOrigin: host).allowsEmbeddedJavaScript() } preferences.allowsContentJavaScript = allowJavaScript if let url = navigationAction.request.url, let redirectedURL = Settings.shared.redirectRule(for: url) { currentTab.beginLoadingURL(redirectedURL) decisionHandler(.cancel, preferences) } else { decisionHandler(.allow, preferences) } } func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { if webView == currentTab.webView { currentTab.loadError = error } } func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { if webView == currentTab.webView { currentTab.loadError = error } } // MARK: WKUIDelegate func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { let newTab = tabController.createNewTab(url: nil, webViewConfiguration: configuration) newTab.webView.load(navigationAction.request) self.currentTab = newTab return newTab.webView } func webView(_ webView: WKWebView, contextMenuConfigurationForElement elementInfo: WKContextMenuElementInfo, completionHandler: @escaping (UIContextMenuConfiguration?) -> Void) { let menuConfig = UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { (menuElements: [UIMenuElement]) -> UIMenu? in let openInNewTab = UIAction(title: "Open in New Tab", image: UIImage(systemName: "plus.app"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [unowned self] _ in self.createNewTab(withURL: elementInfo.linkURL, loadInBackground: false) } let openInBackground = UIAction(title: "Open in Background", image: UIImage(systemName: "plus.rectangle.on.rectangle"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [unowned self] _ in self.createNewTab(withURL: elementInfo.linkURL, loadInBackground: true) } return UIMenu(title: elementInfo.linkURL?.absoluteString ?? "Link", image: nil, identifier: nil, options: .displayInline, children: [ openInNewTab, openInBackground ] + menuElements) } completionHandler(menuConfig) } }