From 4d55933229fc096a11ebb1dd4a5ccd28773d923b Mon Sep 17 00:00:00 2001 From: Chris Li Date: Fri, 9 Sep 2016 16:04:41 -0400 Subject: [PATCH] MainController task get TOC if needed --- Kiwix-iOS/Controller/Main/JSInjection.swift | 55 ++++++ .../Controller/Main/MainController.swift | 24 ++- .../Main/MainControllerDelegates.swift | 164 ++++++++---------- .../Main/MainControllerShowHide.swift | 2 +- .../Controller/Main/WebViewDelegate.swift | 46 ----- Kiwix-iOS/Info.plist | 2 +- Kiwix.xcodeproj/project.pbxproj | 12 +- Kiwix/URLProtocol/KiwixURL.swift | 20 +++ Kiwix/URLProtocol/KiwixURLProtocol.swift | 2 + 9 files changed, 174 insertions(+), 153 deletions(-) create mode 100644 Kiwix-iOS/Controller/Main/JSInjection.swift delete mode 100644 Kiwix-iOS/Controller/Main/WebViewDelegate.swift create mode 100644 Kiwix/URLProtocol/KiwixURL.swift diff --git a/Kiwix-iOS/Controller/Main/JSInjection.swift b/Kiwix-iOS/Controller/Main/JSInjection.swift new file mode 100644 index 00000000..8a07c680 --- /dev/null +++ b/Kiwix-iOS/Controller/Main/JSInjection.swift @@ -0,0 +1,55 @@ +// +// JSInjection.swift +// Kiwix +// +// Created by Chris Li on 9/9/16. +// Copyright © 2016 Chris. All rights reserved. +// + +import UIKit +import JavaScriptCore + +class JSInjection { + + class func injectTableWrappingJavaScriptIfNeeded(webView: UIWebView, traitCollection: UITraitCollection) { + if Preference.webViewInjectJavascriptToAdjustPageLayout { + if traitCollection.horizontalSizeClass == .Compact { + guard let path = NSBundle.mainBundle().pathForResource("adjustlayoutiPhone", ofType: "js") else {return} + guard let jString = try? String(contentsOfFile: path) else {return} + webView.stringByEvaluatingJavaScriptFromString(jString) + } else { + guard let path = NSBundle.mainBundle().pathForResource("adjustlayoutiPad", ofType: "js") else {return} + guard let jString = try? String(contentsOfFile: path) else {return} + webView.stringByEvaluatingJavaScriptFromString(jString) + } + } + } + + class func adjustFontSizeIfNeeded(webView: UIWebView) { + let zoomScale = Preference.webViewZoomScale + guard zoomScale != 100.0 else {return} + let jString = String(format: "document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '%.0f%%'", zoomScale) + webView.stringByEvaluatingJavaScriptFromString(jString) + } + + class func getTableOfContents(webView: UIWebView) -> [HTMLHeading] { + guard let context = webView.valueForKeyPath("documentView.webView.mainFrame.javaScriptContext") as? JSContext, + let path = NSBundle.mainBundle().pathForResource("getTableOfContents", ofType: "js"), + let jString = try? String(contentsOfFile: path), + let elements = context.evaluateScript(jString).toArray() as? [[String: String]] else {return [HTMLHeading]()} + var headings = [HTMLHeading]() + for element in elements { + guard let heading = HTMLHeading(rawValue: element) else {continue} + headings.append(heading) + } + return headings + } + + class func getSnippet(webView: UIWebView) -> String? { + guard let context = webView.valueForKeyPath("documentView.webView.mainFrame.javaScriptContext") as? JSContext, + let path = NSBundle.mainBundle().pathForResource("getSnippet", ofType: "js"), + let jString = try? String(contentsOfFile: path), + let snippet = context.evaluateScript(jString).toString() else {return nil} + return snippet + } +} diff --git a/Kiwix-iOS/Controller/Main/MainController.swift b/Kiwix-iOS/Controller/Main/MainController.swift index 157a2ab0..102aad77 100644 --- a/Kiwix-iOS/Controller/Main/MainController.swift +++ b/Kiwix-iOS/Controller/Main/MainController.swift @@ -9,6 +9,7 @@ import UIKit import Operations +import SafariServices class MainController: UIViewController { @@ -23,7 +24,6 @@ class MainController: UIViewController { // MARK: - Properties - let webViewDelegate = WebViewDelegate() var tableOfContentsController: TableOfContentsController? let searchBar = SearchBar() @@ -49,8 +49,7 @@ class MainController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - webView.delegate = webViewDelegate - webViewDelegate.delegate = self + webView.delegate = self @@ -120,6 +119,19 @@ class MainController: UIViewController { load(mainPageURL) } + func loadExternalResource(url: NSURL) { + let controller = SFSafariViewController(URL: url) + controller.delegate = self + presentViewController(controller, animated: true, completion: nil) + } + + // MARK: - Tasks + + func setTableOfContentIfNeeded() { + guard traitCollection.horizontalSizeClass == .Regular && isShowingTableOfContents else {return} + tableOfContentsController?.headings = JSInjection.getTableOfContents(webView) + } + // MARK: - Configure func configureUIElements(horizontalSizeClass: UIUserInterfaceSizeClass) { @@ -223,11 +235,7 @@ class MainController: UIViewController { func showTableOfContentButtonTapped(sender: UIBarButtonItem) { guard let _ = article else {return} - if isShowingTableOfContents { - animateOutTableOfContentsController() - } else { - animateInTableOfContentsController() - } + isShowingTableOfContents ? animateOutTableOfContentsController() :animateInTableOfContentsController() } func showLibraryButtonTapped() { diff --git a/Kiwix-iOS/Controller/Main/MainControllerDelegates.swift b/Kiwix-iOS/Controller/Main/MainControllerDelegates.swift index a3f4f7f4..3dad28da 100644 --- a/Kiwix-iOS/Controller/Main/MainControllerDelegates.swift +++ b/Kiwix-iOS/Controller/Main/MainControllerDelegates.swift @@ -11,7 +11,34 @@ import SafariServices import JavaScriptCore import DZNEmptyDataSet -extension MainController: LPTBarButtonItemDelegate, TableOfContentsDelegate, ZimMultiReaderDelegate, UISearchBarDelegate, UIPopoverPresentationControllerDelegate, UIWebViewDelegate, SFSafariViewControllerDelegate, UIScrollViewDelegate, UIViewControllerTransitioningDelegate { +extension MainController: UIWebViewDelegate, SFSafariViewControllerDelegate, + LPTBarButtonItemDelegate, TableOfContentsDelegate, ZimMultiReaderDelegate, UISearchBarDelegate, UIPopoverPresentationControllerDelegate, UIScrollViewDelegate, UIViewControllerTransitioningDelegate { + + // MARK: - UIWebViewDelegate + + func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool { + guard let url = request.URL else {return false} + guard url.isKiwixURL else {loadExternalResource(url); return false} + return true + } + + func webViewDidStartLoad(webView: UIWebView) { + + } + + func webViewDidFinishLoad(webView: UIWebView) { + + } + + func webView(webView: UIWebView, didFailLoadWithError error: NSError) { + print(error) + } + + // MARK: - SFSafariViewControllerDelegate + + func safariViewControllerDidFinish(controller: SFSafariViewController) { + controller.dismissViewControllerAnimated(true, completion: nil) + } // MARK: - LPTBarButtonItemDelegate @@ -27,7 +54,7 @@ extension MainController: LPTBarButtonItemDelegate, TableOfContentsDelegate, Zim article.isBookmarked = !article.isBookmarked if article.isBookmarked {article.bookmarkDate = NSDate()} - if article.snippet == nil {article.snippet = getSnippet(webView)} + if article.snippet == nil {article.snippet = JSInjection.getSnippet(webView)} let operation = UpdateWidgetDataSourceOperation() GlobalQueue.shared.addOperation(operation) @@ -91,96 +118,47 @@ extension MainController: LPTBarButtonItemDelegate, TableOfContentsDelegate, Zim return .None } - // MARK: - UIWebViewDelegate - - func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool { - guard let url = request.URL else {return true} - if url.scheme == "kiwix" { - return true - } else { - let svc = SFSafariViewController(URL: url) - svc.delegate = self - presentViewController(svc, animated: true, completion: nil) - return false - } - } - - func webViewDidStartLoad(webView: UIWebView) { - PacketAnalyzer.sharedInstance.startListening() - } - - func webViewDidFinishLoad(webView: UIWebView) { - guard let url = webView.request?.URL else {return} - guard url.scheme!.caseInsensitiveCompare("Kiwix") == .OrderedSame else {return} - - let title = webView.stringByEvaluatingJavaScriptFromString("document.title") - let managedObjectContext = UIApplication.appDelegate.managedObjectContext - guard let bookID = url.host else {return} - guard let book = Book.fetch(bookID, context: managedObjectContext) else {return} - guard let article = Article.addOrUpdate(title, url: url, book: book, context: managedObjectContext) else {return} - - self.article = article - if let image = PacketAnalyzer.sharedInstance.chooseImage() { - article.thumbImageURL = image.url.absoluteString - } - - configureSearchBarPlaceHolder() - injectTableWrappingJavaScriptIfNeeded() - adjustFontSizeIfNeeded() - configureNavigationButtonTint() - configureBookmarkButton() - - if traitCollection.horizontalSizeClass == .Regular && isShowingTableOfContents { - tableOfContentsController?.headings = getTableOfContents(webView) - } - - PacketAnalyzer.sharedInstance.stopListening() - } - - // MARK: - Javascript - - func injectTableWrappingJavaScriptIfNeeded() { - if Preference.webViewInjectJavascriptToAdjustPageLayout { - if traitCollection.horizontalSizeClass == .Compact { - guard let path = NSBundle.mainBundle().pathForResource("adjustlayoutiPhone", ofType: "js") else {return} - guard let jString = try? String(contentsOfFile: path) else {return} - webView.stringByEvaluatingJavaScriptFromString(jString) - } else { - guard let path = NSBundle.mainBundle().pathForResource("adjustlayoutiPad", ofType: "js") else {return} - guard let jString = try? String(contentsOfFile: path) else {return} - webView.stringByEvaluatingJavaScriptFromString(jString) - } - } - } - - func adjustFontSizeIfNeeded() { - let zoomScale = Preference.webViewZoomScale - guard zoomScale != 100.0 else {return} - let jString = String(format: "document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '%.0f%%'", zoomScale) - webView.stringByEvaluatingJavaScriptFromString(jString) - } - - func getTableOfContents(webView: UIWebView) -> [HTMLHeading] { - guard let context = webView.valueForKeyPath("documentView.webView.mainFrame.javaScriptContext") as? JSContext, - let path = NSBundle.mainBundle().pathForResource("getTableOfContents", ofType: "js"), - let jString = try? String(contentsOfFile: path), - let elements = context.evaluateScript(jString).toArray() as? [[String: String]] else {return [HTMLHeading]()} - var headings = [HTMLHeading]() - for element in elements { - guard let heading = HTMLHeading(rawValue: element) else {continue} - headings.append(heading) - } - return headings - } - - func getSnippet(webView: UIWebView) -> String? { - guard let context = webView.valueForKeyPath("documentView.webView.mainFrame.javaScriptContext") as? JSContext, - let path = NSBundle.mainBundle().pathForResource("getSnippet", ofType: "js"), - let jString = try? String(contentsOfFile: path), - let snippet = context.evaluateScript(jString).toString() else {return nil} - return snippet - } - - +// +// func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool { +// guard let url = request.URL else {return true} +// if url.scheme == "kiwix" { +// return true +// } else { +// let svc = SFSafariViewController(URL: url) +// svc.delegate = self +// presentViewController(svc, animated: true, completion: nil) +// return false +// } +// } +// +// func webViewDidStartLoad(webView: UIWebView) { +// PacketAnalyzer.sharedInstance.startListening() +// } +// +// func webViewDidFinishLoad(webView: UIWebView) { +// guard let url = webView.request?.URL else {return} +// guard url.scheme!.caseInsensitiveCompare("Kiwix") == .OrderedSame else {return} +// +// let title = webView.stringByEvaluatingJavaScriptFromString("document.title") +// let managedObjectContext = UIApplication.appDelegate.managedObjectContext +// guard let bookID = url.host else {return} +// guard let book = Book.fetch(bookID, context: managedObjectContext) else {return} +// guard let article = Article.addOrUpdate(title, url: url, book: book, context: managedObjectContext) else {return} +// +// self.article = article +// if let image = PacketAnalyzer.sharedInstance.chooseImage() { +// article.thumbImageURL = image.url.absoluteString +// } +// +// configureSearchBarPlaceHolder() +// injectTableWrappingJavaScriptIfNeeded() +// adjustFontSizeIfNeeded() +// configureNavigationButtonTint() +// configureBookmarkButton() +// + +// +// PacketAnalyzer.sharedInstance.stopListening() +// } } diff --git a/Kiwix-iOS/Controller/Main/MainControllerShowHide.swift b/Kiwix-iOS/Controller/Main/MainControllerShowHide.swift index 5b3959a3..74f2b97d 100644 --- a/Kiwix-iOS/Controller/Main/MainControllerShowHide.swift +++ b/Kiwix-iOS/Controller/Main/MainControllerShowHide.swift @@ -110,7 +110,7 @@ extension MainController { dimView.hidden = false dimView.alpha = 0.0 view.layoutIfNeeded() - tableOfContentsController?.headings = getTableOfContents(webView) + tableOfContentsController?.headings = JSInjection.getTableOfContents(webView) configureTOCViewConstraints() UIView.animateWithDuration(0.3, delay: 0.0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.0, options: .CurveEaseOut, animations: { self.view.layoutIfNeeded() diff --git a/Kiwix-iOS/Controller/Main/WebViewDelegate.swift b/Kiwix-iOS/Controller/Main/WebViewDelegate.swift deleted file mode 100644 index 4268041b..00000000 --- a/Kiwix-iOS/Controller/Main/WebViewDelegate.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// WebViewDelegate.swift -// Kiwix -// -// Created by Chris Li on 9/9/16. -// Copyright © 2016 Chris. All rights reserved. -// - -import UIKit -import SafariServices - -class WebViewDelegate: NSObject, UIWebViewDelegate, SFSafariViewControllerDelegate { - - weak var delegate: MainController? - - // MARK: - UIWebViewDelegate - - func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool { - guard let url = request.URL else {return false} - guard url.scheme?.caseInsensitiveCompare("kiwix") == .OrderedSame else { - let svc = SFSafariViewController(URL: url) - svc.delegate = self - delegate?.presentViewController(svc, animated: true, completion: nil) - return false - } - return true - } - - func webViewDidStartLoad(webView: UIWebView) { - - } - - func webViewDidFinishLoad(webView: UIWebView) { - - } - - func webView(webView: UIWebView, didFailLoadWithError error: NSError) { - print(error) - } - - // MARK: - SFSafariViewControllerDelegate - - func safariViewControllerDidFinish(controller: SFSafariViewController) { - controller.dismissViewControllerAnimated(true, completion: nil) - } -} diff --git a/Kiwix-iOS/Info.plist b/Kiwix-iOS/Info.plist index 444253f7..fde59af5 100644 --- a/Kiwix-iOS/Info.plist +++ b/Kiwix-iOS/Info.plist @@ -49,7 +49,7 @@ CFBundleVersion - 1.8.20 + 1.8.39 ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS diff --git a/Kiwix.xcodeproj/project.pbxproj b/Kiwix.xcodeproj/project.pbxproj index 67bbb03f..015713ff 100644 --- a/Kiwix.xcodeproj/project.pbxproj +++ b/Kiwix.xcodeproj/project.pbxproj @@ -76,7 +76,8 @@ 9764CBD11D806AD800072D6A /* RefreshLibControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9764CBD01D806AD800072D6A /* RefreshLibControl.swift */; }; 9764CBD31D8083AA00072D6A /* ArticleOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9764CBD21D8083AA00072D6A /* ArticleOperation.swift */; }; 9764F5931D830EF200E0B1C4 /* liblzma.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 9764F5921D830EF200E0B1C4 /* liblzma.tbd */; }; - 9764F5951D832D2000E0B1C4 /* WebViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9764F5941D832D2000E0B1C4 /* WebViewDelegate.swift */; }; + 9764F5971D8339D500E0B1C4 /* JSInjection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9764F5961D8339D500E0B1C4 /* JSInjection.swift */; }; + 9764F5991D833F2B00E0B1C4 /* KiwixURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9764F5981D833F2B00E0B1C4 /* KiwixURL.swift */; }; 9779C3141D4575AD0064CC8E /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97E609F01D103DED00EBCB9D /* NotificationCenter.framework */; }; 9779C3171D4575AE0064CC8E /* TodayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9779C3161D4575AE0064CC8E /* TodayViewController.swift */; }; 9779C31A1D4575AE0064CC8E /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9779C3181D4575AE0064CC8E /* MainInterface.storyboard */; }; @@ -295,7 +296,8 @@ 9764CBD01D806AD800072D6A /* RefreshLibControl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefreshLibControl.swift; sourceTree = ""; }; 9764CBD21D8083AA00072D6A /* ArticleOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArticleOperation.swift; sourceTree = ""; }; 9764F5921D830EF200E0B1C4 /* liblzma.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = liblzma.tbd; path = usr/lib/liblzma.tbd; sourceTree = SDKROOT; }; - 9764F5941D832D2000E0B1C4 /* WebViewDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebViewDelegate.swift; path = Main/WebViewDelegate.swift; sourceTree = ""; }; + 9764F5961D8339D500E0B1C4 /* JSInjection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSInjection.swift; path = Main/JSInjection.swift; sourceTree = ""; }; + 9764F5981D833F2B00E0B1C4 /* KiwixURL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KiwixURL.swift; sourceTree = ""; }; 976A0C801D41619C0006A742 /* DZNEmptyDataSet.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DZNEmptyDataSet.framework; path = "../../../../Users/chrisli/Library/Developer/Xcode/DerivedData/Kiwix-ayxrfhaqnfxzendihdolvkklkmhk/Build/Products/Debug-iphoneos/DZNEmptyDataSet/DZNEmptyDataSet.framework"; sourceTree = ""; }; 9779C3131D4575AD0064CC8E /* Bookmarks.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Bookmarks.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 9779C3161D4575AE0064CC8E /* TodayViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodayViewController.swift; sourceTree = ""; }; @@ -635,7 +637,7 @@ 970E68B71D3809A3001E8514 /* MainController.swift */, 9722122A1D3FCCE200C0DCF2 /* MainControllerShowHide.swift */, 970E68B81D3809A3001E8514 /* MainControllerDelegates.swift */, - 9764F5941D832D2000E0B1C4 /* WebViewDelegate.swift */, + 9764F5961D8339D500E0B1C4 /* JSInjection.swift */, ); name = Main; sourceTree = ""; @@ -917,6 +919,7 @@ isa = PBXGroup; children = ( 97A1FD1A1D6F71D800A80EE2 /* KiwixURLProtocol.swift */, + 9764F5981D833F2B00E0B1C4 /* KiwixURL.swift */, 97A1FD1B1D6F71D800A80EE2 /* PacketAnalyzer.swift */, ); path = URLProtocol; @@ -1531,6 +1534,7 @@ 97D681271D6F70AC00E5FA99 /* UIOperations.swift in Sources */, 975B90FE1CEB909100D13906 /* iOSExtensions.swift in Sources */, 971A10521D022D9D007FC62C /* AppDelegate.swift in Sources */, + 9764F5991D833F2B00E0B1C4 /* KiwixURL.swift in Sources */, 97A127CC1D777CF100FB204D /* SearchResultTBVC.swift in Sources */, 97A8AD841D6C951A00584ED1 /* LocalBooksController.swift in Sources */, 97D452BE1D1723FF0033666F /* CollectionViewCells.swift in Sources */, @@ -1551,9 +1555,9 @@ 97A461B71D74819000AC3DED /* DownloadProgress.swift in Sources */, 971A10341D022AEC007FC62C /* BookmarkTBVC.swift in Sources */, 97A1FD1D1D6F71D800A80EE2 /* PacketAnalyzer.swift in Sources */, + 9764F5971D8339D500E0B1C4 /* JSInjection.swift in Sources */, 97A1FD441D6F728200A80EE2 /* Preference.swift in Sources */, 97D681311D6F70EC00E5FA99 /* 1.5.xcmappingmodel in Sources */, - 9764F5951D832D2000E0B1C4 /* WebViewDelegate.swift in Sources */, 97D681441D6F713200E5FA99 /* CoreDataExtension.swift in Sources */, 97DF259C1D6F7613001648A3 /* BookOperation.swift in Sources */, 97A1FD181D6F71CE00A80EE2 /* SearchResult.swift in Sources */, diff --git a/Kiwix/URLProtocol/KiwixURL.swift b/Kiwix/URLProtocol/KiwixURL.swift new file mode 100644 index 00000000..1cbae817 --- /dev/null +++ b/Kiwix/URLProtocol/KiwixURL.swift @@ -0,0 +1,20 @@ +// +// KiwixURL.swift +// Kiwix +// +// Created by Chris Li on 9/9/16. +// Copyright © 2016 Chris. All rights reserved. +// + +import UIKit + +extension NSURL { + convenience init?(bookID: String, contentPath: String) { + let baseURLString = "kiwix://" + bookID + self.init(string: contentPath, relativeToURL: NSURL(string: baseURLString)) + } + + var isKiwixURL: Bool { + return scheme?.caseInsensitiveCompare("kiwix") == .OrderedSame + } +} diff --git a/Kiwix/URLProtocol/KiwixURLProtocol.swift b/Kiwix/URLProtocol/KiwixURLProtocol.swift index 5f8db041..b172e166 100644 --- a/Kiwix/URLProtocol/KiwixURLProtocol.swift +++ b/Kiwix/URLProtocol/KiwixURLProtocol.swift @@ -50,6 +50,8 @@ class KiwixURLProtocol: NSURLProtocol { } extension NSURL { + + class func kiwixURLWithZimFileid(id: String, contentURLString: String) -> NSURL? { guard let escapedContentURLString = contentURLString.stringByAddingPercentEncodingWithAllowedCharacters(.URLPathAllowedCharacterSet()) else {return nil} let baseURLString = "kiwix://" + id