diff --git a/Source/FolioReaderAddHighlightNote.swift b/Source/FolioReaderAddHighlightNote.swift
index a4b7af710..b7cbc9e1b 100644
--- a/Source/FolioReaderAddHighlightNote.swift
+++ b/Source/FolioReaderAddHighlightNote.swift
@@ -67,7 +67,7 @@ class FolioReaderAddHighlightNote: UIViewController {
if !highlightSaved && !isEditHighlight {
guard let currentPage = folioReader.readerCenter?.currentPage else { return }
- currentPage.webView?.js("removeThisHighlight()")
+ currentPage.webView?.js("removeThisHighlight()") { _ in }
}
}
diff --git a/Source/FolioReaderAudioPlayer.swift b/Source/FolioReaderAudioPlayer.swift
index 053fc929f..e59a8fd0f 100644
--- a/Source/FolioReaderAudioPlayer.swift
+++ b/Source/FolioReaderAudioPlayer.swift
@@ -176,7 +176,7 @@ open class FolioReaderAudioPlayer: NSObject {
@objc func play() {
if book.hasAudio {
guard let currentPage = self.folioReader.readerCenter?.currentPage else { return }
- currentPage.webView?.js("playAudio()")
+ currentPage.webView?.js("playAudio()") { _ in }
} else {
self.readCurrentSentence()
}
@@ -382,22 +382,27 @@ open class FolioReaderAudioPlayer: NSObject {
}
let playbackActiveClass = book.playbackActiveClass
- guard let sentence = currentPage.webView?.js("getSentenceWithIndex('\(playbackActiveClass)')") else {
- if (readerCenter.isLastPage() == true) {
- self.stop()
- } else {
- readerCenter.changePageToNext()
+
+ currentPage.webView?.js("getSentenceWithIndex('\(playbackActiveClass)')") { sentence in
+ guard let sentence = sentence else {
+ if (readerCenter.isLastPage() == true) {
+ self.stop()
+ } else {
+ readerCenter.changePageToNext()
+ }
+ return
+
}
-
- return
- }
-
- guard let href = readerCenter.getCurrentChapter()?.href else {
- return
+
+ guard let href = readerCenter.getCurrentChapter()?.href else {
+ return
+ }
+
+ // TODO QUESTION: The previous code made it possible to call `playText` with the parameter `href` being an empty string. Was that valid? should this logic be kept?
+ self.playText(href, text: sentence)
+
}
-
- // TODO QUESTION: The previous code made it possible to call `playText` with the parameter `href` being an empty string. Was that valid? should this logic be kept?
- self.playText(href, text: sentence)
+
}
func readCurrentSentence() {
@@ -410,7 +415,7 @@ open class FolioReaderAudioPlayer: NSObject {
if synthesizer.isSpeaking {
stopSynthesizer(immediate: false, completion: {
if let currentPage = self.folioReader.readerCenter?.currentPage {
- currentPage.webView?.js("resetCurrentSentenceIndex()")
+ currentPage.webView?.js("resetCurrentSentenceIndex()") { _ in }
}
self.speakSentence()
})
diff --git a/Source/FolioReaderCenter.swift b/Source/FolioReaderCenter.swift
index 6c889f036..f8b5c5a66 100644
--- a/Source/FolioReaderCenter.swift
+++ b/Source/FolioReaderCenter.swift
@@ -648,12 +648,21 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
}
scrollScrubber?.setSliderVal()
-
- if let readingTime = currentPage.webView?.js("getReadingTime()") {
- pageIndicatorView?.totalMinutes = Int(readingTime)!
- } else {
- pageIndicatorView?.totalMinutes = 0
+
+ currentPage.webView?.js("getReadingTime()") { readingTime in
+
+ guard let readingTime = readingTime
+ else {
+ self.pageIndicatorView?.totalMinutes = 0
+ return
+
+ }
+
+ self.pageIndicatorView?.totalMinutes = Int(readingTime)!
+
}
+
+
pagesForCurrentPage(currentPage)
delegate?.pageDidAppear?(currentPage)
@@ -1075,60 +1084,66 @@ open class FolioReaderCenter: UIViewController, UICollectionViewDelegate, UIColl
@objc func shareChapter(_ sender: UIBarButtonItem) {
guard let currentPage = currentPage else { return }
- if let chapterText = currentPage.webView?.js("getBodyText()") {
+
+ currentPage.webView?.js("getBodyText()") { chapterText in
+
+ guard let chapterText = chapterText else { return }
+
let htmlText = chapterText.replacingOccurrences(of: "[\\n\\r]+", with: "
", options: .regularExpression)
- var subject = readerConfig.localizedShareChapterSubject
+ var subject = self.readerConfig.localizedShareChapterSubject
var html = ""
var text = ""
var bookTitle = ""
var chapterName = ""
var authorName = ""
var shareItems = [AnyObject]()
-
+
// Get book title
if let title = self.book.title {
bookTitle = title
subject += " “\(title)”"
}
-
+
// Get chapter name
- if let chapter = getCurrentChapterName() {
+ if let chapter = self.getCurrentChapterName() {
chapterName = chapter
}
-
+
// Get author name
if let author = self.book.metadata.creators.first {
authorName = author.name
}
-
+
// Sharing html and text
html = "
"
html += "
\(htmlText)
"
- html += ""+readerConfig.localizedShareAllExcerptsFrom+"
"
+ html += ""+self.readerConfig.localizedShareAllExcerptsFrom+"
"
html += "\(bookTitle)
"
- html += readerConfig.localizedShareBy+" \(authorName)
"
-
- if let bookShareLink = readerConfig.localizedShareWebLink {
+ html += self.readerConfig.localizedShareBy+" \(authorName)
"
+
+ if let bookShareLink = self.readerConfig.localizedShareWebLink {
html += "\(bookShareLink.absoluteString)"
shareItems.append(bookShareLink as AnyObject)
}
-
+
html += ""
- text = "\(chapterName)\n\n“\(chapterText)” \n\n\(bookTitle) \n\(readerConfig.localizedShareBy) \(authorName)"
-
+ text = "\(chapterName)\n\n“\(chapterText)” \n\n\(bookTitle) \n\(self.readerConfig.localizedShareBy) \(authorName)"
+
let act = FolioReaderSharingProvider(subject: subject, text: text, html: html)
shareItems.insert(contentsOf: [act, "" as AnyObject], at: 0)
-
+
let activityViewController = UIActivityViewController(activityItems: shareItems, applicationActivities: nil)
activityViewController.excludedActivityTypes = [UIActivity.ActivityType.print, UIActivity.ActivityType.postToVimeo]
-
+
// Pop style on iPad
if let actv = activityViewController.popoverPresentationController {
actv.barButtonItem = sender
}
-
- present(activityViewController, animated: true, completion: nil)
+
+ self.present(activityViewController, animated: true, completion: nil)
+
}
+
}
/**
diff --git a/Source/FolioReaderHighlightList.swift b/Source/FolioReaderHighlightList.swift
index 16986a4c8..b2a804ee7 100644
--- a/Source/FolioReaderHighlightList.swift
+++ b/Source/FolioReaderHighlightList.swift
@@ -190,7 +190,7 @@ class FolioReaderHighlightList: UITableViewController {
if (highlight.page == self.folioReader.readerCenter?.currentPageNumber),
let page = self.folioReader.readerCenter?.currentPage {
- Highlight.removeFromHTMLById(withinPage: page, highlightId: highlight.highlightId) // Remove from HTML
+ Highlight.removeFromHTMLById(withinPage: page, highlightId: highlight.highlightId) { _ in } // Remove from HTML
}
highlight.remove(withConfiguration: self.readerConfig) // Remove from Database
diff --git a/Source/FolioReaderKit.swift b/Source/FolioReaderKit.swift
index 96914b6ef..f6cd5bc79 100755
--- a/Source/FolioReaderKit.swift
+++ b/Source/FolioReaderKit.swift
@@ -185,7 +185,7 @@ extension FolioReader {
if let readerCenter = self.readerCenter {
UIView.animate(withDuration: 0.6, animations: {
- _ = readerCenter.currentPage?.webView?.js("nightMode(\(self.nightMode))")
+ _ = readerCenter.currentPage?.webView?.js("nightMode(\(self.nightMode))") { _ in }
readerCenter.pageIndicatorView?.reloadColors()
readerCenter.configureNavBar()
readerCenter.scrollScrubber?.reloadColors()
@@ -210,7 +210,7 @@ extension FolioReader {
}
set (font) {
self.defaults.set(font.rawValue, forKey: kCurrentFontFamily)
- _ = self.readerCenter?.currentPage?.webView?.js("setFontName('\(font.cssIdentifier)')")
+ _ = self.readerCenter?.currentPage?.webView?.js("setFontName('\(font.cssIdentifier)')") { _ in }
}
}
@@ -232,7 +232,7 @@ extension FolioReader {
return
}
- currentPage.webView?.js("setFontSize('\(currentFontSize.cssIdentifier)')")
+ currentPage.webView?.js("setFontSize('\(currentFontSize.cssIdentifier)')") { _ in }
}
}
diff --git a/Source/FolioReaderPage.swift b/Source/FolioReaderPage.swift
index 5b013a0fd..3833bcfc2 100755
--- a/Source/FolioReaderPage.swift
+++ b/Source/FolioReaderPage.swift
@@ -9,6 +9,7 @@
import UIKit
import SafariServices
import MenuItemKit
+import WebKit
/// Protocol which is used from `FolioReaderPage`s.
@objc public protocol FolioReaderPageDelegate: class {
@@ -35,9 +36,9 @@ import MenuItemKit
@objc optional func pageTap(_ recognizer: UITapGestureRecognizer)
}
-open class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGestureRecognizerDelegate {
+open class FolioReaderPage: UICollectionViewCell, WKNavigationDelegate, UIGestureRecognizerDelegate {
weak var delegate: FolioReaderPageDelegate?
- weak var readerContainer: FolioReaderContainer?
+ var readerContainer: FolioReaderContainer?
/// The index of the current page. Note: The index start at 1!
open var pageNumber: Int!
@@ -80,13 +81,12 @@ open class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGestureRe
if webView == nil {
webView = FolioReaderWebView(frame: webViewFrame(), readerContainer: readerContainer)
webView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
- webView?.dataDetectorTypes = .link
webView?.scrollView.showsVerticalScrollIndicator = false
webView?.scrollView.showsHorizontalScrollIndicator = false
webView?.backgroundColor = .clear
self.contentView.addSubview(webView!)
}
- webView?.delegate = self
+ webView?.navigationDelegate = self
if colorView == nil {
colorView = UIView()
@@ -110,7 +110,7 @@ open class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGestureRe
deinit {
webView?.scrollView.delegate = nil
- webView?.delegate = nil
+ webView?.navigationDelegate = nil
NotificationCenter.default.removeObserver(self)
}
@@ -186,129 +186,156 @@ open class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGestureRe
}
return tempHtmlContent as String
}
-
- // MARK: - UIWebView Delegate
-
- open func webViewDidFinishLoad(_ webView: UIWebView) {
+
+ // MARK: - WKNavigationDelegate
+
+ public func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
guard let webView = webView as? FolioReaderWebView else {
return
}
-
+
delegate?.pageWillLoad?(self)
-
+
// Add the custom class based onClick listener
self.setupClassBasedOnClickListeners()
-
+
refreshPageMode()
-
+
if self.readerConfig.enableTTS && !self.book.hasAudio {
- webView.js("wrappingSentencesWithinPTags()")
-
+ webView.js("wrappingSentencesWithinPTags()") { _ in }
+
if let audioPlayer = self.folioReader.readerAudioPlayer, (audioPlayer.isPlaying() == true) {
audioPlayer.readCurrentSentence()
}
}
-
+
let direction: ScrollDirection = self.folioReader.needsRTLChange ? .positive(withConfiguration: self.readerConfig) : .negative(withConfiguration: self.readerConfig)
-
+
if (self.folioReader.readerCenter?.pageScrollDirection == direction &&
self.folioReader.readerCenter?.isScrolling == true &&
self.readerConfig.scrollDirection != .horizontalWithVerticalContent) {
scrollPageToBottom()
}
-
+
UIView.animate(withDuration: 0.2, animations: {webView.alpha = 1}, completion: { finished in
webView.isColors = false
self.webView?.createMenu(options: false)
})
-
+
delegate?.pageDidLoad?(self)
+
+
}
-
- open func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebView.NavigationType) -> Bool {
+
+ public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
+
+ let request = navigationAction.request
guard
let webView = webView as? FolioReaderWebView,
let scheme = request.url?.scheme else {
- return true
+ decisionHandler(WKNavigationActionPolicy.allow)
+ return
}
-
- guard let url = request.url else { return false }
-
+
+ guard let url = request.url
+ else {
+ decisionHandler(WKNavigationActionPolicy.cancel)
+ return
+ }
+
if scheme == "highlight" || scheme == "highlight-with-note" {
shouldShowBar = false
-
- guard let decoded = url.absoluteString.removingPercentEncoding else { return false }
+
+ guard let decoded = url.absoluteString.removingPercentEncoding
+ else {
+ decisionHandler(WKNavigationActionPolicy.cancel)
+ return
+ }
let index = decoded.index(decoded.startIndex, offsetBy: 12)
let rect = NSCoder.cgRect(for: String(decoded[index...]))
-
+
webView.createMenu(options: true)
webView.setMenuVisible(true, andRect: rect)
menuIsVisible = true
-
- return false
+ decisionHandler(WKNavigationActionPolicy.cancel)
+ return
} else if scheme == "play-audio" {
- guard let decoded = url.absoluteString.removingPercentEncoding else { return false }
+ guard let decoded = url.absoluteString.removingPercentEncoding
+ else {
+ decisionHandler(WKNavigationActionPolicy.cancel)
+ return
+ }
let index = decoded.index(decoded.startIndex, offsetBy: 13)
let playID = String(decoded[index...])
let chapter = self.folioReader.readerCenter?.getCurrentChapter()
let href = chapter?.href ?? ""
self.folioReader.readerAudioPlayer?.playAudio(href, fragmentID: playID)
-
- return false
+
+ decisionHandler(WKNavigationActionPolicy.cancel)
+ return
} else if scheme == "file" {
-
+
let anchorFromURL = url.fragment
-
+
// Handle internal url
if !url.pathExtension.isEmpty {
let pathComponent = (self.book.opfResource.href as NSString?)?.deletingLastPathComponent
guard let base = ((pathComponent == nil || pathComponent?.isEmpty == true) ? self.book.name : pathComponent) else {
- return true
+ decisionHandler(WKNavigationActionPolicy.allow)
+ return
}
-
+
let path = url.path
let splitedPath = path.components(separatedBy: base)
-
+
// Return to avoid crash
if (splitedPath.count <= 1 || splitedPath[1].isEmpty) {
- return true
+ decisionHandler(WKNavigationActionPolicy.allow)
+ return
}
-
+
let href = splitedPath[1].trimmingCharacters(in: CharacterSet(charactersIn: "/"))
let hrefPage = (self.folioReader.readerCenter?.findPageByHref(href) ?? 0) + 1
-
+
if (hrefPage == pageNumber) {
// Handle internal #anchor
if anchorFromURL != nil {
handleAnchor(anchorFromURL!, avoidBeginningAnchors: false, animated: true)
- return false
+ decisionHandler(WKNavigationActionPolicy.cancel)
+ return
}
} else {
self.folioReader.readerCenter?.changePageWith(href: href, animated: true)
}
- return false
+ decisionHandler(WKNavigationActionPolicy.cancel)
+ return
}
-
+
// Handle internal #anchor
if anchorFromURL != nil {
handleAnchor(anchorFromURL!, avoidBeginningAnchors: false, animated: true)
- return false
+ decisionHandler(WKNavigationActionPolicy.cancel)
+ return
}
-
- return true
+
+ decisionHandler(WKNavigationActionPolicy.allow)
+ return
+
} else if scheme == "mailto" {
print("Email")
- return true
- } else if url.absoluteString != "about:blank" && scheme.contains("http") && navigationType == .linkClicked {
+ decisionHandler(WKNavigationActionPolicy.allow)
+ return
+ } else if url.absoluteString != "about:blank" && scheme.contains("http") && navigationAction.navigationType == .linkActivated {
let safariVC = SFSafariViewController(url: request.url!)
safariVC.view.tintColor = self.readerConfig.tintColor
self.folioReader.readerCenter?.present(safariVC, animated: true, completion: nil)
- return false
+ decisionHandler(WKNavigationActionPolicy.cancel)
+ return
} else {
// Check if the url is a custom class based onClick listerner
var isClassBasedOnClickListenerScheme = false
for listener in self.readerConfig.classBasedOnClickListeners {
-
+
if scheme == listener.schemeName,
let absoluteURLString = request.url?.absoluteString,
let range = absoluteURLString.range(of: "/clientX=") {
@@ -323,21 +350,24 @@ open class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGestureRe
}
}
}
-
+
if isClassBasedOnClickListenerScheme == false {
// Try to open the url with the system if it wasn't a custom class based click listener
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.openURL(url)
- return false
+ decisionHandler(WKNavigationActionPolicy.cancel)
+ return
}
} else {
- return false
+ decisionHandler(WKNavigationActionPolicy.cancel)
+ return
}
}
-
- return true
+
+ decisionHandler(WKNavigationActionPolicy.allow)
+
}
-
+
fileprivate func getEventTouchPoint(fromPositionParameterString positionParameterString: String) -> CGPoint? {
// Remove the parameter names: "/clientX=188&clientY=292" -> "188&292"
var positionParameterString = positionParameterString.replacingOccurrences(of: "/clientX=", with: "")
@@ -373,20 +403,24 @@ open class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGestureRe
self.delegate?.pageTap?(recognizer)
if let _navigationController = self.folioReader.readerCenter?.navigationController, (_navigationController.isNavigationBarHidden == true) {
- let selected = webView?.js("getSelectedText()")
- guard (selected == nil || selected?.isEmpty == true) else {
- return
- }
-
- let delay = 0.4 * Double(NSEC_PER_SEC) // 0.4 seconds * nanoseconds per seconds
- let dispatchTime = (DispatchTime.now() + (Double(Int64(delay)) / Double(NSEC_PER_SEC)))
- DispatchQueue.main.asyncAfter(deadline: dispatchTime, execute: {
- if (self.shouldShowBar == true && self.menuIsVisible == false) {
- self.folioReader.readerCenter?.toggleBars()
+ webView?.js("getSelectedText()") { selected in
+
+ guard (selected == nil || selected?.isEmpty == true) else {
+ return
}
- })
+
+ let delay = 0.4 * Double(NSEC_PER_SEC) // 0.4 seconds * nanoseconds per seconds
+ let dispatchTime = (DispatchTime.now() + (Double(Int64(delay)) / Double(NSEC_PER_SEC)))
+
+ DispatchQueue.main.asyncAfter(deadline: dispatchTime, execute: {
+ if (self.shouldShowBar == true && self.menuIsVisible == false) {
+ self.folioReader.readerCenter?.toggleBars()
+ }
+ })
+ }
+
} else if (self.readerConfig.shouldHideNavigationOnTap == true) {
self.folioReader.readerCenter?.hideBars()
self.menuIsVisible = false
@@ -433,19 +467,21 @@ open class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGestureRe
*/
open func handleAnchor(_ anchor: String, avoidBeginningAnchors: Bool, animated: Bool) {
if !anchor.isEmpty {
- let offset = getAnchorOffset(anchor)
-
- switch self.readerConfig.scrollDirection {
- case .vertical, .defaultVertical:
- let isBeginning = (offset < frame.forDirection(withConfiguration: self.readerConfig) * 0.5)
-
- if !avoidBeginningAnchors {
- scrollPageToOffset(offset, animated: animated)
- } else if avoidBeginningAnchors && !isBeginning {
- scrollPageToOffset(offset, animated: animated)
+ getAnchorOffset(anchor) { offset in
+
+ switch self.readerConfig.scrollDirection {
+ case .vertical, .defaultVertical:
+ let isBeginning = (offset < self.frame.forDirection(withConfiguration: self.readerConfig) * 0.5)
+
+ if !avoidBeginningAnchors {
+ self.scrollPageToOffset(offset, animated: animated)
+ } else if avoidBeginningAnchors && !isBeginning {
+ self.scrollPageToOffset(offset, animated: animated)
+ }
+ case .horizontal, .horizontalWithVerticalContent:
+ self.scrollPageToOffset(offset, animated: animated)
}
- case .horizontal, .horizontalWithVerticalContent:
- scrollPageToOffset(offset, animated: animated)
+
}
}
}
@@ -458,13 +494,16 @@ open class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGestureRe
- parameter anchor: The #anchor id
- returns: The element offset ready to scroll
*/
- func getAnchorOffset(_ anchor: String) -> CGFloat {
+ func getAnchorOffset(_ anchor: String, completion: @escaping ((CGFloat) -> ())) {
let horizontal = self.readerConfig.scrollDirection == .horizontal
- if let strOffset = webView?.js("getAnchorOffset('\(anchor)', \(horizontal.description))") {
- return CGFloat((strOffset as NSString).floatValue)
+
+ webView?.js("getAnchorOffset('\(anchor)', \(horizontal.description))") { strOffset in
+ guard let strOffset = strOffset else {
+ completion(CGFloat(0))
+ return }
+ completion(CGFloat((strOffset as NSString).floatValue))
}
-
- return CGFloat(0)
+
}
// MARK: Mark ID
@@ -480,7 +519,7 @@ open class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGestureRe
}
let playbackActiveClass = self.book.playbackActiveClass
- currentPage.webView?.js("audioMarkID('\(playbackActiveClass)','\(identifier)')")
+ currentPage.webView?.js("audioMarkID('\(playbackActiveClass)','\(identifier)')") { _ in }
}
// MARK: UIMenu visibility
@@ -494,11 +533,17 @@ open class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGestureRe
}
if !webView.isShare && !webView.isColors {
- if let result = webView.js("getSelectedText()") , result.components(separatedBy: " ").count == 1 {
+
+ webView.js("getSelectedText()") { result in
+
+ guard let result = result, result.components(separatedBy: " ").count == 1 else {
+ webView.isOneWord = false
+ return
+ }
+
webView.isOneWord = true
webView.createMenu(options: false)
- } else {
- webView.isOneWord = false
+
}
}
@@ -508,35 +553,34 @@ open class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGestureRe
// MARK: ColorView fix for horizontal layout
@objc func refreshPageMode() {
guard let webView = webView else { return }
-
+
if (self.folioReader.nightMode == true) {
// omit create webView and colorView
let script = "document.documentElement.offsetHeight"
- let contentHeight = webView.stringByEvaluatingJavaScript(from: script)
- let frameHeight = webView.frame.height
- let lastPageHeight = frameHeight * CGFloat(webView.pageCount) - CGFloat(Double(contentHeight!)!)
- colorView.frame = CGRect(x: webView.frame.width * CGFloat(webView.pageCount-1), y: webView.frame.height - lastPageHeight, width: webView.frame.width, height: lastPageHeight)
- } else {
- colorView.frame = CGRect.zero
+
+ webView.js(script) { contentHeight in
+
+ guard let contentHeight = Int(contentHeight ?? "") else {
+ self.colorView.frame = CGRect.zero
+ return
+ }
+
+ let frameHeight = webView.frame.height
+// let lastPageHeight = frameHeight * CGFloat(webView.pageCount) - CGFloat(Double(contentHeight!)!)
+// colorView.frame = CGRect(x: webView.frame.width * CGFloat(webView.pageCount-1), y: webView.frame.height - lastPageHeight, width: webView.frame.width, height: lastPageHeight)
+
+ }
+
}
}
+
// MARK: - Class based click listener
fileprivate func setupClassBasedOnClickListeners() {
for listener in self.readerConfig.classBasedOnClickListeners {
- self.webView?.js("addClassBasedOnClickListener(\"\(listener.schemeName)\", \"\(listener.querySelector)\", \"\(listener.attributeName)\", \"\(listener.selectAll)\")");
+ self.webView?.js("addClassBasedOnClickListener(\"\(listener.schemeName)\", \"\(listener.querySelector)\", \"\(listener.attributeName)\", \"\(listener.selectAll)\")") { _ in }
}
}
- // MARK: - Public Java Script injection
-
- /**
- Runs a JavaScript script and returns it result. The result of running the JavaScript script passed in the script parameter, or nil if the script fails.
-
- - returns: The result of running the JavaScript script passed in the script parameter, or nil if the script fails.
- */
- open func performJavaScript(_ javaScriptCode: String) -> String? {
- return webView?.js(javaScriptCode)
- }
}
diff --git a/Source/FolioReaderPageIndicator.swift b/Source/FolioReaderPageIndicator.swift
index fc1960556..60fb1ca16 100644
--- a/Source/FolioReaderPageIndicator.swift
+++ b/Source/FolioReaderPageIndicator.swift
@@ -95,14 +95,14 @@ class FolioReaderPageIndicator: UIView {
pagesLabel.text = " \(pagesRemaining) " + self.readerConfig.localizedReaderManyPagesLeft
}
- let minutesRemaining = Int(ceil(CGFloat((pagesRemaining * totalMinutes)/totalPages)))
- if minutesRemaining > 1 {
- minutesLabel.text = "\(minutesRemaining) " + self.readerConfig.localizedReaderManyMinutes+" ·"
- } else if minutesRemaining == 1 {
- minutesLabel.text = self.readerConfig.localizedReaderOneMinute+" ·"
- } else {
- minutesLabel.text = self.readerConfig.localizedReaderLessThanOneMinute+" ·"
- }
+// let minutesRemaining = Int(ceil(CGFloat((pagesRemaining * totalMinutes)/totalPages)))
+// if minutesRemaining > 1 {
+// minutesLabel.text = "\(minutesRemaining) " + self.readerConfig.localizedReaderManyMinutes+" ·"
+// } else if minutesRemaining == 1 {
+// minutesLabel.text = self.readerConfig.localizedReaderOneMinute+" ·"
+// } else {
+// minutesLabel.text = self.readerConfig.localizedReaderLessThanOneMinute+" ·"
+// }
reloadView(updateShadow: false)
}
diff --git a/Source/FolioReaderPlayerMenu.swift b/Source/FolioReaderPlayerMenu.swift
index 8b2d24434..fb7fda350 100644
--- a/Source/FolioReaderPlayerMenu.swift
+++ b/Source/FolioReaderPlayerMenu.swift
@@ -267,7 +267,7 @@ class FolioReaderPlayerMenu: UIViewController, SMSegmentViewDelegate, UIGestureR
// update the current page style
if let currentPage = self.folioReader.readerCenter?.currentPage {
- currentPage.webView?.js("setMediaOverlayStyle(\"\(self.folioReader.currentMediaOverlayStyle.className())\")")
+ currentPage.webView?.js("setMediaOverlayStyle(\"\(self.folioReader.currentMediaOverlayStyle.className())\")") { _ in }
}
}
diff --git a/Source/FolioReaderWebView.swift b/Source/FolioReaderWebView.swift
index 9c3b7531a..0ec2f26a7 100644
--- a/Source/FolioReaderWebView.swift
+++ b/Source/FolioReaderWebView.swift
@@ -6,10 +6,13 @@
// Copyright (c) 2016 Folio Reader. All rights reserved.
//
-import UIKit
+import WebKit
+
+public typealias JSCallback = ((String?) ->())
/// The custom WebView used in each page
-open class FolioReaderWebView: UIWebView {
+open class FolioReaderWebView: WKWebView {
+
var isColors = false
var isShare = false
var isOneWord = false
@@ -30,15 +33,18 @@ open class FolioReaderWebView: UIWebView {
guard let readerContainer = readerContainer else { return FolioReader() }
return readerContainer.folioReader
}
-
- override init(frame: CGRect) {
- fatalError("use init(frame:readerConfig:book:) instead.")
- }
-
+
init(frame: CGRect, readerContainer: FolioReaderContainer) {
self.readerContainer = readerContainer
-
- super.init(frame: frame)
+
+ let configuration = WKWebViewConfiguration()
+ if #available(iOS 10.0, *) {
+ configuration.dataDetectorTypes = .link
+ } else {
+ // Fallback on earlier versions
+ assertionFailure("unsupported iOS version")
+ }
+ super.init(frame: frame, configuration: configuration)
}
required public init?(coder aDecoder: NSCoder) {
@@ -77,13 +83,15 @@ open class FolioReaderWebView: UIWebView {
let shareImage = UIAlertAction(title: self.readerConfig.localizedShareImageQuote, style: .default, handler: { (action) -> Void in
if self.isShare {
- if let textToShare = self.js("getHighlightContent()") {
+ self.js("getHighlightContent()") { textToShare in
+ guard let textToShare = textToShare else { return }
self.folioReader.readerCenter?.presentQuoteShare(textToShare)
}
} else {
- if let textToShare = self.js("getSelectedText()") {
+ self.js("getSelectedText()") { textToShare in
+ guard let textToShare = textToShare else { return }
self.folioReader.readerCenter?.presentQuoteShare(textToShare)
-
+
self.clearTextSelection()
}
}
@@ -92,11 +100,13 @@ open class FolioReaderWebView: UIWebView {
let shareText = UIAlertAction(title: self.readerConfig.localizedShareTextQuote, style: .default) { (action) -> Void in
if self.isShare {
- if let textToShare = self.js("getHighlightContent()") {
+ self.js("getHighlightContent()") { textToShare in
+ guard let textToShare = textToShare else { return }
self.folioReader.readerCenter?.shareHighlight(textToShare, rect: sender.menuFrame)
}
} else {
- if let textToShare = self.js("getSelectedText()") {
+ self.js("getSelectedText()") { textToShare in
+ guard let textToShare = textToShare else { return }
self.folioReader.readerCenter?.shareHighlight(textToShare, rect: sender.menuFrame)
}
}
@@ -124,92 +134,117 @@ open class FolioReaderWebView: UIWebView {
}
func remove(_ sender: UIMenuController?) {
- if let removedId = js("removeThisHighlight()") {
+
+ js("removeThisHighlight()") { removedId in
+ guard let removedId = removedId else { return }
Highlight.removeById(withConfiguration: self.readerConfig, highlightId: removedId)
}
+
setMenuVisible(false)
}
@objc func highlight(_ sender: UIMenuController?) {
- let highlightAndReturn = js("highlightString('\(HighlightStyle.classForStyle(self.folioReader.currentHighlightStyle))')")
- let jsonData = highlightAndReturn?.data(using: String.Encoding.utf8)
-
- do {
- let json = try JSONSerialization.jsonObject(with: jsonData!, options: []) as! NSArray
- let dic = json.firstObject as! [String: String]
- let rect = NSCoder.cgRect(for: dic["rect"]!)
- guard let startOffset = dic["startOffset"] else {
- return
- }
- guard let endOffset = dic["endOffset"] else {
- return
- }
-
- createMenu(options: true)
- setMenuVisible(true, andRect: rect)
-
- // Persist
- guard
- let html = js("getHTML()"),
- let identifier = dic["id"],
- let bookId = (self.book.name as NSString?)?.deletingPathExtension else {
+
+ js("highlightString('\(HighlightStyle.classForStyle(self.folioReader.currentHighlightStyle))')") { highlightAndReturn in
+ let jsonData = highlightAndReturn?.data(using: String.Encoding.utf8)
+
+ do {
+ let json = try JSONSerialization.jsonObject(with: jsonData!, options: []) as! NSArray
+ let dic = json.firstObject as! [String: String]
+ let rect = NSCoder.cgRect(for: dic["rect"]!)
+ guard let startOffset = dic["startOffset"] else {
+ return
+ }
+ guard let endOffset = dic["endOffset"] else {
return
+ }
+
+ self.createMenu(options: true)
+ self.setMenuVisible(true, andRect: rect)
+
+
+ // Persist
+ self.js("getHTML()") { html in
+
+ guard let html = html, let identifier = dic["id"], let bookId = (self.book.name as NSString?)?.deletingPathExtension
+ else {
+ return
+ }
+ let pageNumber = self.folioReader.readerCenter?.currentPageNumber ?? 0
+ let match = Highlight.MatchingHighlight(text: html, id: identifier, startOffset: startOffset, endOffset: endOffset, bookId: bookId, currentPage: pageNumber)
+ let highlight = Highlight.matchHighlight(match)
+ highlight?.persist(withConfiguration: self.readerConfig)
+ }
+
+ } catch {
+ print("Could not receive JSON")
}
-
- let pageNumber = folioReader.readerCenter?.currentPageNumber ?? 0
- let match = Highlight.MatchingHighlight(text: html, id: identifier, startOffset: startOffset, endOffset: endOffset, bookId: bookId, currentPage: pageNumber)
- let highlight = Highlight.matchHighlight(match)
- highlight?.persist(withConfiguration: self.readerConfig)
-
- } catch {
- print("Could not receive JSON")
+
}
+
}
@objc func highlightWithNote(_ sender: UIMenuController?) {
- let highlightAndReturn = js("highlightStringWithNote('\(HighlightStyle.classForStyle(self.folioReader.currentHighlightStyle))')")
- let jsonData = highlightAndReturn?.data(using: String.Encoding.utf8)
- do {
- let json = try JSONSerialization.jsonObject(with: jsonData!, options: []) as! NSArray
- let dic = json.firstObject as! [String: String]
- guard let startOffset = dic["startOffset"] else { return }
- guard let endOffset = dic["endOffset"] else { return }
-
- self.clearTextSelection()
+ js("highlightStringWithNote('\(HighlightStyle.classForStyle(self.folioReader.currentHighlightStyle))')") { highlightAndReturn in
- guard let html = js("getHTML()") else { return }
- guard let identifier = dic["id"] else { return }
- guard let bookId = (self.book.name as NSString?)?.deletingPathExtension else { return }
+ let jsonData = highlightAndReturn?.data(using: String.Encoding.utf8)
- let pageNumber = folioReader.readerCenter?.currentPageNumber ?? 0
- let match = Highlight.MatchingHighlight(text: html, id: identifier, startOffset: startOffset, endOffset: endOffset, bookId: bookId, currentPage: pageNumber)
- if let highlight = Highlight.matchHighlight(match) {
- self.folioReader.readerCenter?.presentAddHighlightNote(highlight, edit: false)
+ do {
+ let json = try JSONSerialization.jsonObject(with: jsonData!, options: []) as! NSArray
+ let dic = json.firstObject as! [String: String]
+ guard let startOffset = dic["startOffset"] else { return }
+ guard let endOffset = dic["endOffset"] else { return }
+
+ self.clearTextSelection()
+
+ self.js("getHTML()") { html in
+
+ guard let html = html, let identifier = dic["id"], let bookId = (self.book.name as NSString?)?.deletingPathExtension
+ else {
+ return
+ }
+
+ let pageNumber = self.folioReader.readerCenter?.currentPageNumber ?? 0
+ let match = Highlight.MatchingHighlight(text: html, id: identifier, startOffset: startOffset, endOffset: endOffset, bookId: bookId, currentPage: pageNumber)
+ if let highlight = Highlight.matchHighlight(match) {
+ self.folioReader.readerCenter?.presentAddHighlightNote(highlight, edit: false)
+
+ }
+
+ }
+ } catch {
+ print("Could not receive JSON")
}
- } catch {
- print("Could not receive JSON")
+
}
}
@objc func updateHighlightNote (_ sender: UIMenuController?) {
- guard let highlightId = js("getHighlightId()") else { return }
- guard let highlightNote = Highlight.getById(withConfiguration: readerConfig, highlightId: highlightId) else { return }
- self.folioReader.readerCenter?.presentAddHighlightNote(highlightNote, edit: true)
+
+ js("getHighlightId()") { highlightId in
+ guard let highlightId = highlightId, let highlightNote = Highlight.getById(withConfiguration: self.readerConfig, highlightId: highlightId) else { return }
+ self.folioReader.readerCenter?.presentAddHighlightNote(highlightNote, edit: true)
+ }
+
}
@objc func define(_ sender: UIMenuController?) {
- guard let selectedText = js("getSelectedText()") else {
- return
+
+ js("getSelectedText()") { selectedText in
+
+ guard let selectedText = selectedText else { return }
+
+ self.setMenuVisible(false)
+ self.clearTextSelection()
+
+ let vc = UIReferenceLibraryViewController(term: selectedText)
+ vc.view.tintColor = self.readerConfig.tintColor
+ guard let readerContainer = self.readerContainer else { return }
+ readerContainer.show(vc, sender: nil)
+
}
- self.setMenuVisible(false)
- self.clearTextSelection()
-
- let vc = UIReferenceLibraryViewController(term: selectedText)
- vc.view.tintColor = self.readerConfig.tintColor
- guard let readerContainer = readerContainer else { return }
- readerContainer.show(vc, sender: nil)
}
@objc func play(_ sender: UIMenuController?) {
@@ -241,7 +276,8 @@ open class FolioReaderWebView: UIWebView {
func changeHighlightStyle(_ sender: UIMenuController?, style: HighlightStyle) {
self.folioReader.currentHighlightStyle = style.rawValue
- if let updateId = js("setHighlightStyle('\(HighlightStyle.classForStyle(style.rawValue))')") {
+ js("setHighlightStyle('\(HighlightStyle.classForStyle(style.rawValue))')") { updateId in
+ guard let updateId = updateId else { return }
Highlight.updateById(withConfiguration: self.readerConfig, highlightId: updateId, type: style)
}
@@ -346,10 +382,12 @@ open class FolioReaderWebView: UIWebView {
// MARK: - Java Script Bridge
- @discardableResult open func js(_ script: String) -> String? {
- let callback = self.stringByEvaluatingJavaScript(from: script)
- if callback!.isEmpty { return nil }
- return callback
+ open func js(_ script: String, completion: @escaping JSCallback) {
+
+ self.evaluateJavaScript(script) { (result, error) in
+ completion(result as? String)
+ }
+
}
// MARK: WebView
@@ -366,13 +404,13 @@ open class FolioReaderWebView: UIWebView {
switch self.readerConfig.scrollDirection {
case .vertical, .defaultVertical, .horizontalWithVerticalContent:
scrollView.isPagingEnabled = false
- paginationMode = .unpaginated
+ //paginationMode = .unpaginated
scrollView.bounces = true
break
case .horizontal:
scrollView.isPagingEnabled = true
- paginationMode = .leftToRight
- paginationBreakingMode = .page
+ //paginationMode = .leftToRight
+ //paginationBreakingMode = .page
scrollView.bounces = false
break
}
diff --git a/Source/Models/Highlight+Helper.swift b/Source/Models/Highlight+Helper.swift
index ac6a9aaf5..e37f8dd52 100644
--- a/Source/Models/Highlight+Helper.swift
+++ b/Source/Models/Highlight+Helper.swift
@@ -289,15 +289,11 @@ extension Highlight {
/// - page: The page containing the HTML.
/// - highlightId: The ID to be removed
/// - Returns: The removed id
- @discardableResult public static func removeFromHTMLById(withinPage page: FolioReaderPage?, highlightId: String) -> String? {
- guard let currentPage = page else { return nil }
+ public static func removeFromHTMLById(withinPage page: FolioReaderPage?, highlightId: String, completion: @escaping JSCallback) {
+ guard let currentPage = page else { return }
+
+ currentPage.webView?.js("removeHighlightById('\(highlightId)')", completion: completion)
- if let removedId = currentPage.webView?.js("removeHighlightById('\(highlightId)')") {
- return removedId
- } else {
- print("Error removing Highlight from page")
- return nil
- }
}
/**