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

Commit 3ee4176

Browse files
Merge pull request #137 from smartmobilefactory/issue/132
Custom click listener - closes #132
2 parents 71795b2 + 2649840 commit 3ee4176

4 files changed

Lines changed: 124 additions & 9 deletions

File tree

Example/StoryboardExample/ExampleFolioReaderContainer.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,16 @@ class ExampleFolioReaderContainer: FolioReaderContainer {
1616

1717
let config = FolioReaderConfig()
1818
config.scrollDirection = .horizontalWithVerticalContent
19-
19+
config.shouldHideNavigationOnTap = false
20+
21+
// Print the chapter ID if one was clicked
22+
// A chapter in "The Silver Chair" looks like this "<section class="chapter" title="Chapter I" epub:type="chapter" id="id70364673704880">"
23+
// To knwo if a user tapped on a chapter we can listen to events on the class "chapter" and receive the id value
24+
let listener = ClassBasedOnClickListener(schemeName: "chaptertapped", querySelector: ".chapter", attributeName: "id", onClickAction: { (parameterContent: String?) in
25+
print("chapter with id: " + (parameterContent ?? "-") + " clicked")
26+
})
27+
config.classBasedOnClickListeners.append(listener)
28+
2029
guard let bookPath = NSBundle.mainBundle().pathForResource("The Silver Chair", ofType: "epub") else { return }
2130
setupConfig(config, epubPath: bookPath)
2231
}

Source/FolioReaderConfig.swift

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
import UIKit
1010

11+
// MARK: - FolioReaderScrollDirection
12+
1113
/**
1214
Defines the Reader scrolling direction
1315
*/
@@ -37,12 +39,58 @@ public enum FolioReaderScrollDirection: Int {
3739
}
3840
}
3941

42+
// MARK: - ClassBasedOnClickListener
43+
44+
/**
45+
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.
46+
47+
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.
48+
49+
*/
50+
public struct ClassBasedOnClickListener {
51+
52+
/// The name of the URL scheme which should be used. Note: Make sure that the given `String` is a valid as scheme name.
53+
public var schemeName : String
54+
55+
/// 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.
56+
public var querySelector : String
57+
58+
/// The name of the attribute whose content should be passed to the `onClickAction` action.
59+
public var attributeName : String
60+
61+
/// 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`.
62+
public var selectAll : Bool
63+
64+
/// The closure which will be called if the specified class was clicked.
65+
public var onClickAction : ((parameterContent: String?) -> Void)
66+
67+
/// Initializes a `ClassBasedOnClickListener` instance. Append it to the `classBasedOnClickListeners` property from the `FolioReaderConfig` to receive on click events. The default `selectAll` value is `true`.
68+
public init(schemeName: String, querySelector: String, attributeName: String, selectAll: Bool = true, onClickAction: ((attributeContent: String?) -> Void)) {
69+
self.schemeName = schemeName.lowercaseString
70+
self.querySelector = querySelector
71+
self.attributeName = attributeName
72+
self.selectAll = selectAll
73+
self.onClickAction = onClickAction
74+
}
75+
}
76+
77+
// MARK: - FolioReaderConfig
4078

4179
/**
4280
Defines the Reader custom configuration
4381
*/
4482
public class FolioReaderConfig: NSObject {
45-
83+
84+
// MARK: ClassBasedOnClickListener
85+
86+
/**
87+
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.
88+
89+
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.
90+
91+
*/
92+
public var classBasedOnClickListeners = [ClassBasedOnClickListener]()
93+
4694
// MARK: Colors
4795

4896
/// Base header custom TintColor

Source/FolioReaderPage.swift

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ public class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGesture
130130
// MARK: - UIWebView Delegate
131131

132132
public func webViewDidFinishLoad(webView: UIWebView) {
133+
134+
// Add the custom class based onClick listener
135+
self.setupClassBasedOnClickListeners()
136+
133137
refreshPageMode()
134138

135139
if readerConfig.enableTTS && !book.hasAudio() {
@@ -233,11 +237,28 @@ public class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGesture
233237
FolioReader.sharedInstance.readerCenter.presentViewController(nav, animated: true, completion: nil)
234238
}
235239
return false
236-
} else if UIApplication.sharedApplication().canOpenURL(url) {
237-
UIApplication.sharedApplication().openURL(url)
238-
return false
239-
}
240-
240+
} else {
241+
// Check if the url is a custom class based onClick listerner
242+
var isClassBasedOnClickListenerScheme = false
243+
for listener in readerConfig.classBasedOnClickListeners {
244+
if url.scheme == listener.schemeName {
245+
let parameterContentString = (request.URL?.absoluteString.stringByReplacingOccurrencesOfString("\(url.scheme)://", withString: "").stringByRemovingPercentEncoding)
246+
listener.onClickAction(parameterContent: parameterContentString)
247+
isClassBasedOnClickListenerScheme = true
248+
}
249+
}
250+
251+
if isClassBasedOnClickListenerScheme == false {
252+
// Try to open the url with the system if it wasn't a custom class based click listener
253+
if UIApplication.sharedApplication().canOpenURL(url) {
254+
UIApplication.sharedApplication().openURL(url)
255+
return false
256+
}
257+
} else {
258+
return false
259+
}
260+
}
261+
241262
return true
242263
}
243264

@@ -393,6 +414,15 @@ public class FolioReaderPage: UICollectionViewCell, UIWebViewDelegate, UIGesture
393414
colorView.frame = CGRectZero
394415
}
395416
}
417+
418+
// MARK: - Class based click listener
419+
420+
private func setupClassBasedOnClickListeners() {
421+
422+
for listener in readerConfig.classBasedOnClickListeners {
423+
self.webView.js("addClassBasedOnClickListener(\"\(listener.schemeName)\", \"\(listener.querySelector)\", \"\(listener.attributeName)\", \"\(listener.selectAll)\")");
424+
}
425+
}
396426
}
397427

398428
// MARK: - WebView Highlight and share implementation

Source/Resources/Bridge.js

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,14 +145,14 @@ var getRectForSelectedText = function(elm) {
145145
// Method that call that a hightlight was clicked
146146
// with URL scheme and rect informations
147147
var callHighlightURL = function(elm) {
148-
var URLBase = "highlight://";
148+
event.stopPropagation();
149+
var URLBase = "highlight://";
149150
var currentHighlightRect = getRectForSelectedText(elm);
150151
thisHighlight = elm;
151152

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

155-
156156
// Reading time
157157
function getReadingTime() {
158158
var text = document.body.innerText;
@@ -579,4 +579,32 @@ function wrappingSentencesWithinPTags(){
579579
}
580580

581581
guessSenetences();
582+
}
583+
584+
// Class based onClick listener
585+
586+
function addClassBasedOnClickListener(schemeName, querySelector, attributeName, selectAll) {
587+
if (selectAll) {
588+
// Get all elements with the given query selector
589+
var elements = document.querySelectorAll(querySelector);
590+
for (elementIndex = 0; elementIndex < elements.length; elementIndex++) {
591+
var element = elements[elementIndex];
592+
addClassBasedOnClickListenerToElement(element, schemeName, attributeName);
593+
}
594+
} else {
595+
// Get the first element with the given query selector
596+
var element = document.querySelector(querySelector);
597+
addClassBasedOnClickListenerToElement(element, schemeName, attributeName);
598+
}
599+
}
600+
601+
function addClassBasedOnClickListenerToElement(element, schemeName, attributeName) {
602+
// Get the content from the given attribute name
603+
var attributeContent = element.getAttribute(attributeName);
604+
// Add the on click logic
605+
element.setAttribute("onclick", "onClassBasedListenerClick(\"" + schemeName + "\", \"" + encodeURIComponent(attributeContent) + "\");");
606+
}
607+
608+
var onClassBasedListenerClick = function(schemeName, parameterContent) {
609+
window.location = schemeName + "://" + parameterContent;
582610
}

0 commit comments

Comments
 (0)