Intercept the click of the pdf link
For a link to a pdf file, the didProposeVisitToURL
mechanism is not triggered for the session delegate. Thus, one can't decide from there how to handle the linked pdf.
Instead, one could intercept clicking the link by becoming turbolinks' web view's navigation delegate as shown in the README:
extension NavigationController: SessionDelegate {
// ...
func sessionDidLoadWebView(session: Session) {
session.webView.navigationDelegate = self
}
}
extension NavigationController: WKNavigationDelegate {
func webView(webView: WKWebView,
decidePolicyForNavigationAction navigationAction: WKNavigationAction,
decisionHandler: (WKNavigationActionPolicy) -> ()) {
// This method is called whenever the webView within the
// visitableView attempts a navigation action. By default, the
// navigation has to be cancelled, since when clicking a
// turbolinks link, the content is shown in a **new**
// visitableView.
//
// But there are exceptions: When clicking on a PDF, which
// is not handled by turbolinks, we have to handle showing
// the pdf manually.
//
// We can't just allow the navigation since this would not
// create a new visitable controller, i.e. there would be
// no back button to the documents index. Therefore, we have
// to create a new view controller manually.
let url = navigationAction.request.URL!
if url.pathExtension == "pdf" {
presentPdfViewController(url)
}
decisionHandler(WKNavigationActionPolicy.Cancel)
}
}
Present the pdf view controller
Similarly to presenting the visitable view as shown in the turbolinks-ios demo application, present the pdf view controller:
extension NavigationController {
func presentPdfViewController(url: NSURL) {
let pdfViewController = PdfViewController(URL: url)
pushViewController(pdfViewController, animated: true)
}
}
Or, if you'd like to show other file types as well, call it fileViewController
rather than pdfViewController
.
PdfViewController
The new view controller inherits from turbolinks' VisitableViewController to make use of the initialization by url.
class PdfViewController: FileViewController {
}
class FileViewController: Turbolinks.VisitableViewController {
lazy var fileView: WKWebView = {
return WKWebView(frame: CGRectZero)
}()
lazy var filename: String? = {
return self.visitableURL?.pathComponents?.last
}()
override func viewDidLoad() {
view.addSubview(fileView)
fileView.bindFrameToSuperviewBounds() // https://stackoverflow.com/a/32824659/2066546
self.title = filename // https://stackoverflow.com/a/39022302/2066546
fileView.loadRequest(NSURLRequest(URL: visitableURL))
}
}
To get the web view to the correct size, I used bindFrameToSuperviewBounds
as shown in this stackoverflow answer, but I'm sure there are other methods.
Optional: Sharing cookies
If loading the pdf needs authentication, it's convenient to share the cookies with the turbolinks-ios webview as described in the README.
For example, create a webViewConfiguration
which can be passed to the pdfViewController
:
extension NavigationController {
let webViewProcessPool = WKProcessPool()
lazy var webViewConfiguration: WKWebViewConfiguration = {
let configuration = WKWebViewConfiguration()
configuration.processPool = self.webViewProcessPool
// ...
return configuration
}()
lazy var session: Session = {
let session = Session(webViewConfiguration: self.webViewConfiguration)
session.delegate = self
return session
}()
}
The same webViewConfiguration
needs to be passed to the session
(shown above) as well as to the new pdf view controller.
extension NavigationController {
func presentPdfViewController(url: NSURL) {
let pdfViewController = PdfViewController(URL: url)
pdfViewController.webViewConfiguration = self.webViewConfiguration
pushViewController(pdfViewController, animated: true)
}
}
class FileViewController: Turbolinks.VisitableViewController {
var webViewConfiguration: WKWebViewConfiguration
lazy var fileView: WKWebView = {
return WKWebView(frame: CGRectZero, configuration: self.webViewConfiguration)
}()
// ...
}
Demo
