MainController task

get TOC if needed
This commit is contained in:
Chris Li 2016-09-09 16:04:41 -04:00
parent f6fb050601
commit 4d55933229
9 changed files with 174 additions and 153 deletions

View File

@ -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
}
}

View File

@ -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() {

View File

@ -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()
// }
}

View File

@ -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()

View File

@ -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)
}
}

View File

@ -49,7 +49,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.8.20</string>
<string>1.8.39</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSRequiresIPhoneOS</key>

View File

@ -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 = "<group>"; };
9764CBD21D8083AA00072D6A /* ArticleOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArticleOperation.swift; sourceTree = "<group>"; };
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 = "<group>"; };
9764F5961D8339D500E0B1C4 /* JSInjection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSInjection.swift; path = Main/JSInjection.swift; sourceTree = "<group>"; };
9764F5981D833F2B00E0B1C4 /* KiwixURL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KiwixURL.swift; sourceTree = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
@ -635,7 +637,7 @@
970E68B71D3809A3001E8514 /* MainController.swift */,
9722122A1D3FCCE200C0DCF2 /* MainControllerShowHide.swift */,
970E68B81D3809A3001E8514 /* MainControllerDelegates.swift */,
9764F5941D832D2000E0B1C4 /* WebViewDelegate.swift */,
9764F5961D8339D500E0B1C4 /* JSInjection.swift */,
);
name = Main;
sourceTree = "<group>";
@ -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 */,

View File

@ -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
}
}

View File

@ -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