Skip to content
This repository has been archived by the owner on Nov 26, 2020. It is now read-only.

Commit

Permalink
Merge pull request #137 from smartmobilefactory/issue/132
Browse files Browse the repository at this point in the history
Custom click listener - closes #132
  • Loading branch information
hebertialmeida authored Sep 15, 2016
2 parents 71795b2 + 2649840 commit 3ee4176
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 9 deletions.
11 changes: 10 additions & 1 deletion Example/StoryboardExample/ExampleFolioReaderContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,16 @@ class ExampleFolioReaderContainer: FolioReaderContainer {

let config = FolioReaderConfig()
config.scrollDirection = .horizontalWithVerticalContent

config.shouldHideNavigationOnTap = false

// Print the chapter ID if one was clicked
// A chapter in "The Silver Chair" looks like this "<section class="chapter" title="Chapter I" epub:type="chapter" id="id70364673704880">"
// To knwo if a user tapped on a chapter we can listen to events on the class "chapter" and receive the id value
let listener = ClassBasedOnClickListener(schemeName: "chaptertapped", querySelector: ".chapter", attributeName: "id", onClickAction: { (parameterContent: String?) in
print("chapter with id: " + (parameterContent ?? "-") + " clicked")
})
config.classBasedOnClickListeners.append(listener)

guard let bookPath = NSBundle.mainBundle().pathForResource("The Silver Chair", ofType: "epub") else { return }
setupConfig(config, epubPath: bookPath)
}
Expand Down
50 changes: 49 additions & 1 deletion Source/FolioReaderConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

import UIKit

// MARK: - FolioReaderScrollDirection

/**
Defines the Reader scrolling direction
*/
Expand Down Expand Up @@ -37,12 +39,58 @@ public enum FolioReaderScrollDirection: Int {
}
}

// MARK: - ClassBasedOnClickListener

/**
A `ClassBasedOnClickListener` takes a closure which is performed if a given html `class` is clicked. The closure will reveice the content of the specified parameter.

Eg. A ClassBasedOnClickListener with the className "quote" and parameterName "id" with the given epub html content "<section class="quote" id="12345">" would call the given closure on a click on this section with the String "12345" as parameter.

*/
public struct ClassBasedOnClickListener {

/// The name of the URL scheme which should be used. Note: Make sure that the given `String` is a valid as scheme name.
public var schemeName : String

/// The query selector for the elements which the listener should be added to. See https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector for further information about query selectors.
public var querySelector : String

/// The name of the attribute whose content should be passed to the `onClickAction` action.
public var attributeName : String

/// Whether the listener should be added to all found elements or only to the first one. See https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelectorAll for further information. The default value is `true`.
public var selectAll : Bool

/// The closure which will be called if the specified class was clicked.
public var onClickAction : ((parameterContent: String?) -> Void)

/// Initializes a `ClassBasedOnClickListener` instance. Append it to the `classBasedOnClickListeners` property from the `FolioReaderConfig` to receive on click events. The default `selectAll` value is `true`.
public init(schemeName: String, querySelector: String, attributeName: String, selectAll: Bool = true, onClickAction: ((attributeContent: String?) -> Void)) {
self.schemeName = schemeName.lowercaseString
self.querySelector = querySelector
self.attributeName = attributeName
self.selectAll = selectAll
self.onClickAction = onClickAction
}
}

// MARK: - FolioReaderConfig

/**
Defines the Reader custom configuration
*/
public class FolioReaderConfig: NSObject {


// MARK: ClassBasedOnClickListener

/**
Array of `ClassBasedOnClickListener` objects. A `ClassBasedOnClickListener` takes a closure which is performed if a given html `class` is clicked. The closure will reveice the content of the specified parameter.

Eg. A ClassBasedOnClickListener with the className "quote" and parameterName "id" with the given epub html content "<section class="quote" id="12345">" would call the given closure on a click on this section with the String "12345" as parameter.

*/
public var classBasedOnClickListeners = [ClassBasedOnClickListener]()

// MARK: Colors

/// Base header custom TintColor
Expand Down
40 changes: 35 additions & 5 deletions Source/FolioReaderPage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ public class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGesture
// MARK: - UIWebView Delegate

public func webViewDidFinishLoad(webView: UIWebView) {

// Add the custom class based onClick listener
self.setupClassBasedOnClickListeners()

refreshPageMode()

if readerConfig.enableTTS && !book.hasAudio() {
Expand Down Expand Up @@ -233,11 +237,28 @@ public class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGesture
FolioReader.sharedInstance.readerCenter.presentViewController(nav, animated: true, completion: nil)
}
return false
} else if UIApplication.sharedApplication().canOpenURL(url) {
UIApplication.sharedApplication().openURL(url)
return false
}

} else {
// Check if the url is a custom class based onClick listerner
var isClassBasedOnClickListenerScheme = false
for listener in readerConfig.classBasedOnClickListeners {
if url.scheme == listener.schemeName {
let parameterContentString = (request.URL?.absoluteString.stringByReplacingOccurrencesOfString("\(url.scheme)://", withString: "").stringByRemovingPercentEncoding)
listener.onClickAction(parameterContent: parameterContentString)
isClassBasedOnClickListenerScheme = true
}
}

if isClassBasedOnClickListenerScheme == false {
// Try to open the url with the system if it wasn't a custom class based click listener
if UIApplication.sharedApplication().canOpenURL(url) {
UIApplication.sharedApplication().openURL(url)
return false
}
} else {
return false
}
}

return true
}

Expand Down Expand Up @@ -393,6 +414,15 @@ public class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGesture
colorView.frame = CGRectZero
}
}

// MARK: - Class based click listener

private func setupClassBasedOnClickListeners() {

for listener in readerConfig.classBasedOnClickListeners {
self.webView.js("addClassBasedOnClickListener(\"\(listener.schemeName)\", \"\(listener.querySelector)\", \"\(listener.attributeName)\", \"\(listener.selectAll)\")");
}
}
}

// MARK: - WebView Highlight and share implementation
Expand Down
32 changes: 30 additions & 2 deletions Source/Resources/Bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,14 @@ var getRectForSelectedText = function(elm) {
// Method that call that a hightlight was clicked
// with URL scheme and rect informations
var callHighlightURL = function(elm) {
var URLBase = "highlight://";
event.stopPropagation();
var URLBase = "highlight://";
var currentHighlightRect = getRectForSelectedText(elm);
thisHighlight = elm;

window.location = URLBase + encodeURIComponent(currentHighlightRect);
}


// Reading time
function getReadingTime() {
var text = document.body.innerText;
Expand Down Expand Up @@ -579,4 +579,32 @@ function wrappingSentencesWithinPTags(){
}

guessSenetences();
}

// Class based onClick listener

function addClassBasedOnClickListener(schemeName, querySelector, attributeName, selectAll) {
if (selectAll) {
// Get all elements with the given query selector
var elements = document.querySelectorAll(querySelector);
for (elementIndex = 0; elementIndex < elements.length; elementIndex++) {
var element = elements[elementIndex];
addClassBasedOnClickListenerToElement(element, schemeName, attributeName);
}
} else {
// Get the first element with the given query selector
var element = document.querySelector(querySelector);
addClassBasedOnClickListenerToElement(element, schemeName, attributeName);
}
}

function addClassBasedOnClickListenerToElement(element, schemeName, attributeName) {
// Get the content from the given attribute name
var attributeContent = element.getAttribute(attributeName);
// Add the on click logic
element.setAttribute("onclick", "onClassBasedListenerClick(\"" + schemeName + "\", \"" + encodeURIComponent(attributeContent) + "\");");
}

var onClassBasedListenerClick = function(schemeName, parameterContent) {
window.location = schemeName + "://" + parameterContent;
}

0 comments on commit 3ee4176

Please sign in to comment.