diff --git a/App/Browser View/BrowserViewController+Keyboard.swift b/App/Browser View/BrowserViewController+Keyboard.swift new file mode 100644 index 0000000..6abaee7 --- /dev/null +++ b/App/Browser View/BrowserViewController+Keyboard.swift @@ -0,0 +1,103 @@ +// +// BrowserViewController+Keyboard.swift +// App +// +// Created by James Magahern on 2/17/21. +// + +import Foundation + +extension BrowserViewController: ShortcutResponder +{ + internal func updateCommandKeyState(forPresses presses: Set) { + guard let press = presses.first else { return } + + if let key = press.key { + if key.modifierFlags == [.command] { + let isDown = press.phase == .began || press.phase == .changed || press.phase == .stationary + self.commandKeyHeld = isDown + } + } + } + + override func pressesBegan(_ presses: Set, with event: UIPressesEvent?) { + super.pressesBegan(presses, with: event) + updateCommandKeyState(forPresses: presses) + } + + override func pressesCancelled(_ presses: Set, with event: UIPressesEvent?) { + super.pressesCancelled(presses, with: event) + updateCommandKeyState(forPresses: presses) + } + + override func pressesEnded(_ presses: Set, with event: UIPressesEvent?) { + super.pressesEnded(presses, with: event) + updateCommandKeyState(forPresses: presses) + } + + // MARK: Keyboard Shortcuts + + func focusURLBar(_ sender: Any?) { + toolbarController.urlBar.textField.becomeFirstResponder() + } + + func goBack(_ sender: Any?) { + tab.webView.goBack() + } + + func goForward(_ sender: Any?) { + tab.webView.goForward() + } + + func createTab(_ sender: Any?) { + createNewTab(withURL: nil) + } + + func previousTab(_ sender: Any?) { + if let tabIndex = tabController.tabs.firstIndex(of: self.tab) { + if tabIndex - 1 >= 0 { + self.tab = tabController.tabs[tabIndex - 1] + } + } + } + + func nextTab(_ sender: Any?) { + if let tabIndex = tabController.tabs.firstIndex(of: self.tab) { + if tabIndex + 1 < tabController.tabs.count { + self.tab = tabController.tabs[tabIndex + 1] + } + } + } + + func closeTab(_ sender: Any?) { + if tabController.tabs.count > 1 { + tabController.closeTab(self.tab) + } else { + #if targetEnvironment(macCatalyst) + if let originWindowScene = self.view.window?.windowScene { + UIApplication.shared.requestSceneSessionDestruction(originWindowScene.session, options: nil) { error in + print("Error when requesting scene destruction: " + error.localizedDescription) + } + } + #endif + } + } + + func findOnPage(_ sender: Any?) { + browserView.setFindOnPageVisible(true, animated: true) + findOnPageController.findOnPageView.textField.becomeFirstResponder() + } + + func refresh(_ sender: Any?) { + webView.reload() + } + + override func increaseSize(_ sender: Any?) { + tab.webView._viewScale += 0.10 + } + + override func decreaseSize(_ sender: Any?) { + tab.webView._viewScale -= 0.10 + } + +} diff --git a/App/Browser View/BrowserViewController+WebKitDelegate.swift b/App/Browser View/BrowserViewController+WebKitDelegate.swift new file mode 100644 index 0000000..d1c8d2e --- /dev/null +++ b/App/Browser View/BrowserViewController+WebKitDelegate.swift @@ -0,0 +1,146 @@ +// +// 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!) { + loadError = nil + + // Check to make sure we have connected to the web content process + if !tab.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 + tab.allowedScriptOrigins.removeAll() + tab.blockedScriptOrigins.removeAll() + updateScriptBlockerButton() + + // Blur url bar if applicable + toolbarController.urlBar.textField.resignFirstResponder() + + updateTitleAndURL(forWebView: webView) + + if let url = webView.url { + // Start requesting favicon + tab.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) + } + } + + 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 + let tab = tabController.createNewTab(url: navigationAction.request.url) + self.tab = tab + + // Reset this flag. + commandKeyHeld = false + windowButtonHeld = false + + return + } + + var allowJavaScript = tab.javaScriptEnabled + if !allowJavaScript, let host = navigationAction.request.url?.host { + // Check origin policy + allowJavaScript = policyManager.allowedOriginsForScriptResources().contains(host) + } + + preferences.allowsContentJavaScript = allowJavaScript + + if let url = navigationAction.request.url, + let redirectedURL = redirectRules.redirectedURL(for: url) + { + tab.beginLoadingURL(redirectedURL) + decisionHandler(.cancel, preferences) + } else { + decisionHandler(.allow, preferences) + } + } + + func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { + self.loadError = error + } + + func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { + self.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.tab = 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 + let newTab = tabController.createNewTab(url: elementInfo.linkURL) + self.tab = newTab + } + + + return UIMenu(title: elementInfo.linkURL?.absoluteString ?? "Link", + image: nil, + identifier: nil, + options: .displayInline, + children: [ openInNewTab ] + menuElements) + } + + completionHandler(menuConfig) + } + +} diff --git a/App/Browser View/BrowserViewController.swift b/App/Browser View/BrowserViewController.swift index 120f697..ca68e35 100644 --- a/App/Browser View/BrowserViewController.swift +++ b/App/Browser View/BrowserViewController.swift @@ -9,23 +9,21 @@ import Combine import UIKit import UniformTypeIdentifiers -class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegate, ScriptPolicyViewControllerDelegate, - UIPopoverPresentationControllerDelegate, TabDelegate, TabPickerViewControllerDelegate, - AutocompleteViewControllerDelegate, ShortcutResponder +class BrowserViewController: UIViewController { let browserView = BrowserView() var tab: Tab { didSet { didChangeTab(tab) } } var webView: WKWebView { tab.webView } - private let tabController = TabController() - private let tabBarViewController: TabBarViewController - private let toolbarController = ToolbarViewController() - private let findOnPageController = FindOnPageViewController() + internal let tabController = TabController() + internal let tabBarViewController: TabBarViewController + internal let toolbarController = ToolbarViewController() + internal let findOnPageController = FindOnPageViewController() - private let autocompleteViewController = AutocompleteViewController() - private let redirectRules = PersonalRedirectRules() + internal let autocompleteViewController = AutocompleteViewController() + internal let redirectRules = PersonalRedirectRules() - private var policyManager: ResourcePolicyManager { tabController.policyManager } + internal var policyManager: ResourcePolicyManager { tabController.policyManager } override var canBecomeFirstResponder: Bool { true } @@ -36,10 +34,10 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat private var activeTabObservation: AnyCancellable? private var faviconObservation: AnyCancellable? - private var loadError: Error? + internal var loadError: Error? - private var commandKeyHeld: Bool = false - private var windowButtonHeld: Bool { + internal var commandKeyHeld: Bool = false + internal var windowButtonHeld: Bool { get { toolbarController.newTabButton.isTracking } set { toolbarController.newTabButton.cancelTracking(with: nil) } } @@ -305,7 +303,7 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat self.view = browserView } - private func updateLoadProgress(forWebView webView: WKWebView) { + internal func updateLoadProgress(forWebView webView: WKWebView) { if let loadError = loadError { toolbarController.urlBar.loadProgress = .error(error: loadError) } else if webView.estimatedProgress == 1.0 { @@ -315,7 +313,7 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat } } - private func updateTitleAndURL(forWebView webView: WKWebView) { + internal func updateTitleAndURL(forWebView webView: WKWebView) { if webView == browserView.webView { browserView.titlebarView.setTitle(webView.title ?? "") @@ -403,33 +401,7 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat toolbarController.traitCollectionDidChange(previousTraitCollection) } - private func updateCommandKeyState(forPresses presses: Set) { - guard let press = presses.first else { return } - - if let key = press.key { - if key.modifierFlags == [.command] { - let isDown = press.phase == .began || press.phase == .changed || press.phase == .stationary - self.commandKeyHeld = isDown - } - } - } - - override func pressesBegan(_ presses: Set, with event: UIPressesEvent?) { - super.pressesBegan(presses, with: event) - updateCommandKeyState(forPresses: presses) - } - - override func pressesCancelled(_ presses: Set, with event: UIPressesEvent?) { - super.pressesCancelled(presses, with: event) - updateCommandKeyState(forPresses: presses) - } - - override func pressesEnded(_ presses: Set, with event: UIPressesEvent?) { - super.pressesEnded(presses, with: event) - updateCommandKeyState(forPresses: presses) - } - - private func updateScriptBlockerButton() { + internal func updateScriptBlockerButton() { var numBlockedScripts: Int = tab.blockedScriptOrigins.count if tab.url != nil, tab.javaScriptEnabled == false { // Because the page is blocked too, notify. @@ -451,158 +423,46 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat let newTab = tabController.createNewTab(url: url) self.tab = newTab } - - // MARK: UIPopoverPresentationControllerDelegate - +} + +extension BrowserViewController: UIPopoverPresentationControllerDelegate +{ func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle { // Forces popovers to present on iPhone return .none } - - // MARK: Navigation Delegate - - func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { - loadError = nil - - // Check to make sure we have connected to the web content process - if !tab.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 - tab.allowedScriptOrigins.removeAll() - tab.blockedScriptOrigins.removeAll() - updateScriptBlockerButton() - - // Blur url bar if applicable - toolbarController.urlBar.textField.resignFirstResponder() - - updateTitleAndURL(forWebView: webView) - - if let url = webView.url { - // Start requesting favicon - tab.updateFaviconForURL(url) - } +} + +extension BrowserViewController: ScriptPolicyViewControllerDelegate +{ + func didChangeScriptPolicy() { + tab.bridge.policyDataSourceDidChange() + webView.reload() } - 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) - } + func setScriptsEnabledForTab(_ enabled: Bool) { + tab.javaScriptEnabled = enabled + toolbarController.scriptControllerIconView.shieldsDown = enabled } - - 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 - let tab = tabController.createNewTab(url: navigationAction.request.url) - self.tab = tab - - // Reset this flag. - commandKeyHeld = false - windowButtonHeld = false - - return - } - - var allowJavaScript = tab.javaScriptEnabled - if !allowJavaScript, let host = navigationAction.request.url?.host { - // Check origin policy - allowJavaScript = policyManager.allowedOriginsForScriptResources().contains(host) - } - - preferences.allowsContentJavaScript = allowJavaScript - - if let url = navigationAction.request.url, - let redirectedURL = redirectRules.redirectedURL(for: url) - { - tab.beginLoadingURL(redirectedURL) - decisionHandler(.cancel, preferences) - } else { - decisionHandler(.allow, preferences) - } +} + +extension BrowserViewController: AutocompleteViewControllerDelegate +{ + func autocompleteController(_: AutocompleteViewController, didSelectHistoryItem item: HistoryItem) { + tab.beginLoadingURL(item.url) + autocompleteViewController.view.isHidden = true } - - func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { - self.loadError = error - } - - func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { - self.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.tab = 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 - let newTab = tabController.createNewTab(url: elementInfo.linkURL) - self.tab = newTab - } - - - return UIMenu(title: elementInfo.linkURL?.absoluteString ?? "Link", - image: nil, - identifier: nil, - options: .displayInline, - children: [ openInNewTab ] + menuElements) - } - - completionHandler(menuConfig) - } - - // MARK: Tab Delegate - +} + +extension BrowserViewController: TabDelegate +{ func didBlockScriptOrigin(_ origin: String, forTab: Tab) { updateScriptBlockerButton() } - - // MARK: Tab Picker Delegate - +} + +extension BrowserViewController: TabPickerViewControllerDelegate +{ func tabPicker(_ picker: TabPickerViewController, didSelectTab tab: Tab) { self.tab = tab picker.dismiss(animated: true, completion: nil) @@ -614,90 +474,6 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat picker.dismiss(animated: true, completion: nil) } } - - // MARK: Script Policy View Controller Delegate - - func didChangeScriptPolicy() { - tab.bridge.policyDataSourceDidChange() - webView.reload() - } - - func setScriptsEnabledForTab(_ enabled: Bool) { - tab.javaScriptEnabled = enabled - toolbarController.scriptControllerIconView.shieldsDown = enabled - } - - // MARK: Autocomplete Controller Delegate - - func autocompleteController(_: AutocompleteViewController, didSelectHistoryItem item: HistoryItem) { - tab.beginLoadingURL(item.url) - autocompleteViewController.view.isHidden = true - } - - // MARK: Keyboard shortcuts - - func focusURLBar(_ sender: Any?) { - toolbarController.urlBar.textField.becomeFirstResponder() - } - - func goBack(_ sender: Any?) { - tab.webView.goBack() - } - - func goForward(_ sender: Any?) { - tab.webView.goForward() - } - - func createTab(_ sender: Any?) { - createNewTab(withURL: nil) - } - - func previousTab(_ sender: Any?) { - if let tabIndex = tabController.tabs.firstIndex(of: self.tab) { - if tabIndex - 1 >= 0 { - self.tab = tabController.tabs[tabIndex - 1] - } - } - } - - func nextTab(_ sender: Any?) { - if let tabIndex = tabController.tabs.firstIndex(of: self.tab) { - if tabIndex + 1 < tabController.tabs.count { - self.tab = tabController.tabs[tabIndex + 1] - } - } - } - - func closeTab(_ sender: Any?) { - if tabController.tabs.count > 1 { - tabController.closeTab(self.tab) - } else { - #if targetEnvironment(macCatalyst) - if let originWindowScene = self.view.window?.windowScene { - UIApplication.shared.requestSceneSessionDestruction(originWindowScene.session, options: nil) { error in - print("Error when requesting scene destruction: " + error.localizedDescription) - } - } - #endif - } - } - - func findOnPage(_ sender: Any?) { - browserView.setFindOnPageVisible(true, animated: true) - findOnPageController.findOnPageView.textField.becomeFirstResponder() - } - - func refresh(_ sender: Any?) { - webView.reload() - } - - override func increaseSize(_ sender: Any?) { - tab.webView._viewScale += 0.10 - } - - override func decreaseSize(_ sender: Any?) { - tab.webView._viewScale -= 0.10 - } } extension BrowserViewController: UITextFieldDelegate diff --git a/SBrowser.xcodeproj/project.pbxproj b/SBrowser.xcodeproj/project.pbxproj index db99ff3..19326f2 100644 --- a/SBrowser.xcodeproj/project.pbxproj +++ b/SBrowser.xcodeproj/project.pbxproj @@ -42,6 +42,8 @@ 1ADFF4D024CBBCD1006DC7AE /* ScriptPolicyControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ADFF4CF24CBBCD1006DC7AE /* ScriptPolicyControl.swift */; }; CD01D5A5254A10BB00189CDC /* TabBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD01D5A4254A10BB00189CDC /* TabBarView.swift */; }; CD01D5AB254A206D00189CDC /* TabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD01D5AA254A206D00189CDC /* TabBarViewController.swift */; }; + CD470C4225DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD470C4125DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift */; }; + CD470C4425DE070400AFBE0E /* BrowserViewController+Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD470C4325DE070400AFBE0E /* BrowserViewController+Keyboard.swift */; }; CD7A8915251975B70075991E /* AutocompleteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7A8914251975B70075991E /* AutocompleteViewController.swift */; }; CD7A89172519872D0075991E /* KeyboardShortcuts.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7A89162519872D0075991E /* KeyboardShortcuts.swift */; }; CD7A8919251989C90075991E /* UIKeyCommand+ConvInit.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7A8918251989C90075991E /* UIKeyCommand+ConvInit.swift */; }; @@ -127,6 +129,8 @@ 1ADFF4CF24CBBCD1006DC7AE /* ScriptPolicyControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptPolicyControl.swift; sourceTree = ""; }; CD01D5A4254A10BB00189CDC /* TabBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarView.swift; sourceTree = ""; }; CD01D5AA254A206D00189CDC /* TabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarViewController.swift; sourceTree = ""; }; + CD470C4125DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BrowserViewController+WebKitDelegate.swift"; sourceTree = ""; }; + CD470C4325DE070400AFBE0E /* BrowserViewController+Keyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BrowserViewController+Keyboard.swift"; sourceTree = ""; }; CD7A8914251975B70075991E /* AutocompleteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteViewController.swift; sourceTree = ""; }; CD7A89162519872D0075991E /* KeyboardShortcuts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardShortcuts.swift; sourceTree = ""; }; CD7A8918251989C90075991E /* UIKeyCommand+ConvInit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIKeyCommand+ConvInit.swift"; sourceTree = ""; }; @@ -274,8 +278,10 @@ 1ADFF47724C7DFE8006DC7AE /* Browser View */ = { isa = PBXGroup; children = ( - 1ADFF47324C7DE9C006DC7AE /* BrowserViewController.swift */, 1ADFF47824C7DFF8006DC7AE /* BrowserView.swift */, + 1ADFF47324C7DE9C006DC7AE /* BrowserViewController.swift */, + CD470C4325DE070400AFBE0E /* BrowserViewController+Keyboard.swift */, + CD470C4125DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift */, ); path = "Browser View"; sourceTree = ""; @@ -490,6 +496,7 @@ CDCE2666251AA840007FE92A /* StackView.swift in Sources */, CD853BD124E778B800D2BDCC /* History.xcdatamodeld in Sources */, 1AD31040252545BF00A4A952 /* FindOnPageView.swift in Sources */, + CD470C4225DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift in Sources */, CDEDD8AA25D62ADB00862605 /* UITraitCollection+MacLike.swift in Sources */, CD7A8919251989C90075991E /* UIKeyCommand+ConvInit.swift in Sources */, 1ADFF4C724CA6DEB006DC7AE /* UIEdgeInsets+Layout.swift in Sources */, @@ -499,6 +506,7 @@ CD01D5A5254A10BB00189CDC /* TabBarView.swift in Sources */, 1ADFF4D024CBBCD1006DC7AE /* ScriptPolicyControl.swift in Sources */, 1A03810D24E71CA700826501 /* ToolbarView.swift in Sources */, + CD470C4425DE070400AFBE0E /* BrowserViewController+Keyboard.swift in Sources */, CD853BD424E77BF900D2BDCC /* HistoryItem.swift in Sources */, 1ADFF48D24C8C176006DC7AE /* SBRProcessBundleBridge.m in Sources */, 1AD3103D252541E600A4A952 /* PersonalRedirectRules.swift in Sources */,