diff --git a/.gitignore b/.gitignore index badb0ab32..70a1e9514 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,13 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.externalNativeBuild + # Custom _site @@ -37,4 +47,7 @@ out # Maven target release.properties -pom.xml.* \ No newline at end of file +pom.xml.* + +# Readium DRM LCP +liblcp.aar \ No newline at end of file diff --git a/README.md b/README.md index 94c29acd4..b0009cd6b 100644 --- a/README.md +++ b/README.md @@ -38,20 +38,30 @@ FolioReader-Android is an ePub reader written in Java. ### Gradle -Add following dependency to your app module `build.gradle` file: +Add following dependency to your root project `build.gradle` file: ```groovy -repositories { - maven { - url 'http://dl.bintray.com/mobisystech/maven' +allprojects { + repositories { + ... + maven { url "https://dl.bintray.com/mobisystech/maven" } + maven { url "https://jitpack.io" } + ... } } +``` +Add following dependency to your app module `build.gradle` file: + +```groovy dependencies { - implementation 'com.folioreader:folioreader:0.4.4' + ... + implementation "com.folioreader:folioreader:0.5.1" + ... } ``` + ### AndroidManifest Starting with Android 9.0 (API level 28), cleartext support is disabled by default. @@ -125,6 +135,9 @@ folioReader.openBook(R.raw.adventures); Please follow [Issue Template](https://github.com/FolioReader/FolioReader-Android/blob/master/.github/ISSUE_TEMPLATE.md) to report any issue. +## Share your application +If you are using FolioReader in your application, share your application link in [this issue](https://github.com/FolioReader/FolioReader-Android/issues/291) + ### Credits 1. SwipeLayout 2. r2-streamer-java @@ -158,3 +171,4 @@ Please follow [Issue Template](https://github.com/FolioReader/FolioReader-Androi ## License FolioReaderKit is available under the BSD license. See the [LICENSE](https://github.com/FolioReader/FolioReader-Android/blob/master/License.md) file. + diff --git a/build.gradle b/build.gradle index f8655949a..f9459da6b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.KOTLIN_VERSION = '1.2.61' + ext.KOTLIN_VERSION = '1.2.71' repositories { google() @@ -24,22 +24,28 @@ allprojects { repositories { google() jcenter() + maven { url "https://dl.bintray.com/mobisystech/maven" } + maven { url "https://jitpack.io" } + mavenLocal() } } ext { - LIBRARY_VERSION = '0.4.4' - R2_STREAMER_VERSION = '0.1.8' + FOLIOREADER_SDK_VERSION = '0.5.1' + R2_STREAMER_KOTLIN_VERSION = '1.0.3-5' + R2_SHARED_KOTLIN_VERSION = '1.0.3-2' VERSION_NAME = "1.0" VERSION_CODE = 1 - ANDROID_MIN_SDK = 15 + ANDROID_MIN_SDK = 19 ANDROID_COMPILE_SDK_VERSION = 28 ANDROID_TARGET_SDK_VERSION = 28 - ANDROID_LIB_VERSION = '28.0.0-rc01' + ANDROID_LIB_VERSION = '28.0.0' CONSTRAINT_LAYOUT_VERSION = "1.1.3" + + JACKSON_VERSION = '2.8.6' } task clean(type: Delete) { diff --git a/config/quality/checkstyle/checkstyle-config.xml b/config/quality/checkstyle/checkstyle-config.xml index 262a6c3d1..045ddb97c 100755 --- a/config/quality/checkstyle/checkstyle-config.xml +++ b/config/quality/checkstyle/checkstyle-config.xml @@ -110,12 +110,6 @@ - - - - - - - - - - - - - - + + + + android:theme="@style/FolioActivityDayTheme" /> + + + + \ No newline at end of file diff --git a/folioreader/res/color/content_highlight_text_selector_night_mode.xml b/folioreader/res/color/content_highlight_text_selector_night_mode.xml deleted file mode 100644 index da04ba6ff..000000000 --- a/folioreader/res/color/content_highlight_text_selector_night_mode.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/folioreader/res/drawable-xhdpi/colors_marker.png b/folioreader/res/drawable-xhdpi/colors_marker.png deleted file mode 100644 index ecf58d4aa..000000000 Binary files a/folioreader/res/drawable-xhdpi/colors_marker.png and /dev/null differ diff --git a/folioreader/res/drawable-xhdpi/ic_action_discard.png b/folioreader/res/drawable-xhdpi/ic_action_discard.png deleted file mode 100644 index 9eeeed124..000000000 Binary files a/folioreader/res/drawable-xhdpi/ic_action_discard.png and /dev/null differ diff --git a/folioreader/res/drawable-xhdpi/ic_action_share.png b/folioreader/res/drawable-xhdpi/ic_action_share.png deleted file mode 100644 index 40771e480..000000000 Binary files a/folioreader/res/drawable-xhdpi/ic_action_share.png and /dev/null differ diff --git a/folioreader/res/drawable-xhdpi/ic_blue_marker.png b/folioreader/res/drawable-xhdpi/ic_blue_marker.png deleted file mode 100644 index 0a9e0af56..000000000 Binary files a/folioreader/res/drawable-xhdpi/ic_blue_marker.png and /dev/null differ diff --git a/folioreader/res/drawable-xhdpi/ic_green_marker.png b/folioreader/res/drawable-xhdpi/ic_green_marker.png deleted file mode 100644 index 2f47b528d..000000000 Binary files a/folioreader/res/drawable-xhdpi/ic_green_marker.png and /dev/null differ diff --git a/folioreader/res/drawable-xhdpi/ic_pink_marker.png b/folioreader/res/drawable-xhdpi/ic_pink_marker.png deleted file mode 100644 index 483460499..000000000 Binary files a/folioreader/res/drawable-xhdpi/ic_pink_marker.png and /dev/null differ diff --git a/folioreader/res/drawable-xhdpi/ic_underline_marker.png b/folioreader/res/drawable-xhdpi/ic_underline_marker.png deleted file mode 100644 index 601a06fbf..000000000 Binary files a/folioreader/res/drawable-xhdpi/ic_underline_marker.png and /dev/null differ diff --git a/folioreader/res/drawable-xhdpi/ic_yellow_marker.png b/folioreader/res/drawable-xhdpi/ic_yellow_marker.png deleted file mode 100644 index de18c7162..000000000 Binary files a/folioreader/res/drawable-xhdpi/ic_yellow_marker.png and /dev/null differ diff --git a/folioreader/res/drawable-xhdpi/icon_close.png b/folioreader/res/drawable-xhdpi/icon_close.png deleted file mode 100644 index 365f53727..000000000 Binary files a/folioreader/res/drawable-xhdpi/icon_close.png and /dev/null differ diff --git a/folioreader/res/drawable/ic_close_green_24dp.xml b/folioreader/res/drawable/ic_close_green_24dp.xml index e6e81abbe..62dfc837c 100644 --- a/folioreader/res/drawable/ic_close_green_24dp.xml +++ b/folioreader/res/drawable/ic_close_green_24dp.xml @@ -2,8 +2,8 @@ + android:viewportWidth="24" + android:viewportHeight="24"> diff --git a/folioreader/res/drawable/ic_drawer.xml b/folioreader/res/drawable/ic_drawer.xml index 286181292..d51676b75 100644 --- a/folioreader/res/drawable/ic_drawer.xml +++ b/folioreader/res/drawable/ic_drawer.xml @@ -1,8 +1,8 @@ + android:viewportWidth="24.0" + android:viewportHeight="24.0"> diff --git a/folioreader/res/drawable/ic_format_underlined.xml b/folioreader/res/drawable/ic_format_underlined.xml new file mode 100644 index 000000000..946b35543 --- /dev/null +++ b/folioreader/res/drawable/ic_format_underlined.xml @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/folioreader/res/drawable/ic_highlight_delete.xml b/folioreader/res/drawable/ic_highlight_delete.xml new file mode 100644 index 000000000..2b27d142b --- /dev/null +++ b/folioreader/res/drawable/ic_highlight_delete.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/folioreader/res/drawable/ic_offline_gray_layer_list.xml b/folioreader/res/drawable/ic_offline_gray_layer_list.xml new file mode 100644 index 000000000..89bd96d66 --- /dev/null +++ b/folioreader/res/drawable/ic_offline_gray_layer_list.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/folioreader/res/drawable/note_edittext_background.xml b/folioreader/res/drawable/note_edittext_background.xml index f344669ca..ba907dbe3 100644 --- a/folioreader/res/drawable/note_edittext_background.xml +++ b/folioreader/res/drawable/note_edittext_background.xml @@ -4,5 +4,5 @@ android:shape="rectangle" > - + \ No newline at end of file diff --git a/folioreader/res/drawable/shape_highlight_blue.xml b/folioreader/res/drawable/shape_highlight_blue.xml new file mode 100644 index 000000000..4ff69b693 --- /dev/null +++ b/folioreader/res/drawable/shape_highlight_blue.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/folioreader/res/drawable/shape_highlight_green.xml b/folioreader/res/drawable/shape_highlight_green.xml new file mode 100644 index 000000000..26c6fe633 --- /dev/null +++ b/folioreader/res/drawable/shape_highlight_green.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/folioreader/res/drawable/shape_highlight_pink.xml b/folioreader/res/drawable/shape_highlight_pink.xml new file mode 100644 index 000000000..bbd5f6f07 --- /dev/null +++ b/folioreader/res/drawable/shape_highlight_pink.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/folioreader/res/drawable/shape_highlight_yellow.xml b/folioreader/res/drawable/shape_highlight_yellow.xml new file mode 100644 index 000000000..8219d4f8e --- /dev/null +++ b/folioreader/res/drawable/shape_highlight_yellow.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/folioreader/res/layout/activity_content_highlight.xml b/folioreader/res/layout/activity_content_highlight.xml index a77565702..0c291e3dc 100644 --- a/folioreader/res/layout/activity_content_highlight.xml +++ b/folioreader/res/layout/activity_content_highlight.xml @@ -32,7 +32,7 @@ android:layout_centerInParent="true" android:layout_margin="16dp" android:scaleType="centerCrop" - android:src="@drawable/ic_close_green_24dp" /> + app:srcCompat="@drawable/ic_close_green_24dp" /> + app:srcCompat="@drawable/ic_close_green_24dp" /> diff --git a/folioreader/res/layout/text_selection.xml b/folioreader/res/layout/text_selection.xml new file mode 100644 index 000000000..4c97fd251 --- /dev/null +++ b/folioreader/res/layout/text_selection.xml @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/folioreader/res/menu/menu_on_highlight.xml b/folioreader/res/menu/menu_on_highlight.xml deleted file mode 100644 index 3e8d36402..000000000 --- a/folioreader/res/menu/menu_on_highlight.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/folioreader/res/menu/menu_text_selection.xml b/folioreader/res/menu/menu_text_selection.xml deleted file mode 100644 index 34696bfc0..000000000 --- a/folioreader/res/menu/menu_text_selection.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/folioreader/res/values/attrs.xml b/folioreader/res/values/attrs.xml index 21727395e..bba62dbc3 100644 --- a/folioreader/res/values/attrs.xml +++ b/folioreader/res/values/attrs.xml @@ -1,5 +1,11 @@ + + + + + + @@ -18,5 +24,8 @@ + + + \ No newline at end of file diff --git a/folioreader/res/values/colors.xml b/folioreader/res/values/colors.xml index 0caf9d00f..c231923e9 100644 --- a/folioreader/res/values/colors.xml +++ b/folioreader/res/values/colors.xml @@ -12,10 +12,7 @@ #090609 #71C951 #bcbcbc - #FFEB6B - #C0ED72 - #ADD8FF - #FFB0CA + #B6B6B6 #ff0000 #767676 @@ -27,4 +24,9 @@ #AAAAAA + #FFEB6B + #C0ED72 + #ADD8FF + #FFB0CA + \ No newline at end of file diff --git a/folioreader/res/values/day_theme.xml b/folioreader/res/values/day_theme.xml new file mode 100644 index 000000000..ab43aec64 --- /dev/null +++ b/folioreader/res/values/day_theme.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + @color/white + #000000 + #333333 + #333333 + + + + \ No newline at end of file diff --git a/folioreader/res/values/night_theme.xml b/folioreader/res/values/night_theme.xml new file mode 100644 index 000000000..dd75aba6f --- /dev/null +++ b/folioreader/res/values/night_theme.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + #070707 + #767676 + #888888 + #888888 + + + + \ No newline at end of file diff --git a/folioreader/res/values/strings.xml b/folioreader/res/values/strings.xml index b36636d2d..52928c84e 100644 --- a/folioreader/res/values/strings.xml +++ b/folioreader/res/values/strings.xml @@ -70,14 +70,11 @@ javascript:setMediaOverlayStyle(\'%s\') javascript:goToAnchor(\'%s\') javascript:goToHighlight(\'%s\') - javascript:getHighlightString(\'%s\') javascript:setHighlightStyle(\'%s\'); ]]> ]]> %s]]> %s]]> - \\{\\{(-?\\d+\\.?\\d*)\\,(-?\\d+\\.?\\d*)\\}\\,\\s\\{(-?\\d+\\.?\\d*)\\,(-?\\d+\\.?\\d*)\\}\\} - %s]]> %s @@ -105,11 +102,6 @@ text/html BackCompat - Copy - Highlight - Define - Share - Search Configuration Text To Speech diff --git a/folioreader/res/values/styles.xml b/folioreader/res/values/styles.xml index cd2f84e66..e14bcb51a 100644 --- a/folioreader/res/values/styles.xml +++ b/folioreader/res/values/styles.xml @@ -9,104 +9,12 @@ @color/colorAccent - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/folioreader/src/main/assets/js/Bridge.js b/folioreader/src/main/assets/js/Bridge.js index f2e04a576..87b80c48e 100755 --- a/folioreader/src/main/assets/js/Bridge.js +++ b/folioreader/src/main/assets/js/Bridge.js @@ -10,28 +10,6 @@ var thisHighlight; var audioMarkClass; var wordsPerMinute = 180; -document.addEventListener("DOMContentLoaded", function(event) { -// var lnk = document.getElementsByClassName("lnk"); -// for (var i=0; i 0 ) + for( i = 0; i <= els.length; i++) { + els[i].classList.remove(className); } +} - if (horizontal) { - return document.body.clientWidth * Math.floor(elem.offsetTop / window.innerHeight); - } +/** + Audio Mark ID - marks an element with an ID with the given class and scrolls to it + */ +function audioMarkID(className, id) { + if (audioMarkClass) + removeAllClasses(audioMarkClass); - return elem.offsetTop; -} + audioMarkClass = className + var el = document.getElementById(id); -function scrollAnchor(id) { - window.location.hash = id; + scrollToElement(el); + el.classList.add(className) } -function findElementWithID(node) { - if( !node || node.tagName == "BODY") - return null - else if( node.id ) - return node - else - return findElementWithID(node) +function setMediaOverlayStyle(style){ + document.documentElement.classList.remove("mediaOverlayStyle0", "mediaOverlayStyle1", "mediaOverlayStyle2") + document.documentElement.classList.add(style) } -function findElementWithIDInView() { +function setMediaOverlayStyleColors(color, colorHighlight) { + var stylesheet = document.styleSheets[document.styleSheets.length-1]; +// stylesheet.insertRule(".mediaOverlayStyle0 span.epub-media-overlay-playing { background: "+colorHighlight+" !important }") +// stylesheet.insertRule(".mediaOverlayStyle1 span.epub-media-overlay-playing { border-color: "+color+" !important }") +// stylesheet.insertRule(".mediaOverlayStyle2 span.epub-media-overlay-playing { color: "+color+" !important }") +} - if(audioMarkClass) { - // attempt to find an existing "audio mark" - var el = document.querySelector("."+audioMarkClass) +var currentIndex = -1; - // if that existing audio mark exists and is in view, use it - if( el && el.offsetTop > document.body.scrollTop && el.offsetTop < (window.innerHeight + document.body.scrollTop)) - return el - } +function findSentenceWithIDInView(els) { // @NOTE: is `span` too limiting? - var els = document.querySelectorAll("span[id]") - for(indx in els) { var element = els[indx]; @@ -192,11 +124,13 @@ function findElementWithIDInView() { // document.body.scrollLeft = elLeft; if (elLeft == document.body.scrollLeft) { + currentIndex = indx; return element; } // Vertical } else if(element.offsetTop > document.body.scrollTop) { + currentIndex = indx; return element; } } @@ -204,375 +138,594 @@ function findElementWithIDInView() { return null } +function findNextSentenceInArray(els) { + if(currentIndex >= 0) { + currentIndex ++; + return els[currentIndex]; + } + + return null +} + +function resetCurrentSentenceIndex() { + currentIndex = -1; +} + +function rewindCurrentIndex() { + currentIndex = currentIndex-1; +} -/** - Play Audio - called by native UIMenuController when a user selects a bit of text and presses "play" - */ -function playAudio() { +function getSentenceWithIndex(className) { + var sentence; var sel = getSelection(); var node = null; + var elements = document.querySelectorAll("span.sentence"); - // user selected text? start playing from the selected node + // Check for a selected text, if found start reading from it if (sel.toString() != "") { - node = sel.anchorNode ? findElementWithID(sel.anchorNode.parentNode) : null; + console.log(sel.anchorNode.parentNode); + node = sel.anchorNode.parentNode; + + if (node.className == "sentence") { + sentence = node - // find the first ID'd element that is within view (it will + for(var i = 0, len = elements.length; i < len; i++) { + if (elements[i] === sentence) { + currentIndex = i; + break; + } + } + } else { + sentence = findSentenceWithIDInView(elements); + } + } else if (currentIndex < 0) { + sentence = findSentenceWithIDInView(elements); } else { - node = findElementWithIDInView() + sentence = findNextSentenceInArray(elements); } - playAudioFragmentID(node ? node.id : null) -} - + var text = sentence.innerText || sentence.textContent; -/** - Play Audio Fragment ID - tells page controller to begin playing audio from the following ID - */ -function playAudioFragmentID(fragmentID) { - var URLBase = "play-audio://"; - window.location = URLBase + (fragmentID?encodeURIComponent(fragmentID):"") -} + scrollToElement(sentence); -function bodyOrHtml() { - if ('scrollingElement' in document) { - return document.scrollingElement; - } - // Fallback for legacy browsers - if (navigator.userAgent.indexOf('WebKit') != -1) { - return document.body; + if (audioMarkClass){ + removeAllClasses(audioMarkClass); } - return document.documentElement; -} -function scrollToElement(element) { + audioMarkClass = className; + sentence.classList.add(className) + return text; +} - var scrollingElement = bodyOrHtml(); +function wrappingSentencesWithinPTags(){ + currentIndex = -1; + "use strict"; - if (FolioPageFragment.getDirection() == "VERTICAL") { + var rxOpen = new RegExp("<[^\\/].+?>"), + rxClose = new RegExp("<\\/.+?>"), + rxSupStart = new RegExp("^]*>"), + rxSupEnd = new RegExp("<\/sup>"), + sentenceEnd = [], + rxIndex; - var topDistraction = FolioPageFragment.getTopDistraction(); - var pageTop = scrollingElement.scrollTop + topDistraction; - var pageBottom = scrollingElement.scrollTop + document.documentElement.clientHeight - - FolioPageFragment.getBottomDistraction(); + sentenceEnd.push(new RegExp("[^\\d][\\.!\\?]+")); + sentenceEnd.push(new RegExp("(?=([^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*?$)")); + sentenceEnd.push(new RegExp("(?![^\\(]*?\\))")); + sentenceEnd.push(new RegExp("(?![^\\[]*?\\])")); + sentenceEnd.push(new RegExp("(?![^\\{]*?\\})")); + sentenceEnd.push(new RegExp("(?![^\\|]*?\\|)")); + sentenceEnd.push(new RegExp("(?![^\\\\]*?\\\\)")); + //sentenceEnd.push(new RegExp("(?![^\\/.]*\\/)")); // all could be a problem, but this one is problematic - var elementTop = element.offsetTop - 20; - elementTop = elementTop < 0 ? 0 : elementTop; - var elementBottom = element.offsetTop + element.offsetHeight + 20; - var needToScroll = (elementTop < pageTop || elementBottom > pageBottom); + rxIndex = new RegExp(sentenceEnd.reduce(function (previousValue, currentValue) { + return previousValue + currentValue.source; + }, "")); - //console.log("-> topDistraction = " + topDistraction); - //console.log("-> pageTop = " + pageTop); - //console.log("-> elementTop = " + elementTop); - //console.log("-> pageBottom = " + pageBottom); - //console.log("-> elementBottom = " + elementBottom); + function indexSentenceEnd(html) { + var index = html.search(rxIndex); - if (needToScroll) { - var newScrollTop = elementTop - topDistraction; - newScrollTop = newScrollTop < 0 ? 0 : newScrollTop; - //console.log("-> Scrolled to = " + newScrollTop); - scrollingElement.scrollTop = newScrollTop; + if (index !== -1) { + index += html.match(rxIndex)[0].length - 1; } - } else if (FolioPageFragment.getDirection() == "HORIZONTAL") { + return index; + } - var clientWidth = document.documentElement.clientWidth; - var pageIndex = Math.floor(element.offsetLeft / clientWidth); - var newScrollLeft = clientWidth * pageIndex; - //console.log("-> newScrollLeft = " + newScrollLeft); - scrollingElement.scrollLeft = newScrollLeft; - WebViewPager.setCurrentPage(pageIndex); + function pushSpan(array, className, string, classNameOpt) { + if (!string.match('[a-zA-Z0-9]+')) { + array.push(string); + } else { + array.push('' + string + ''); + } } - return element; -} + function addSupToPrevious(html, array) { + var sup = html.search(rxSupStart), + end = 0, + last; -/** - Remove All Classes - removes the given class from all elements in the DOM - */ -function removeAllClasses(className) { - var els = document.body.getElementsByClassName(className) - if( els.length > 0 ) - for( i = 0; i <= els.length; i++) { - els[i].classList.remove(className); + if (sup !== -1) { + end = html.search(rxSupEnd); + if (end !== -1) { + last = array.pop(); + end = end + 6; + array.push(last.slice(0, -7) + html.slice(0, end) + last.slice(-7)); + } + } + + return html.slice(end); } -} -//For testing purpose only -function sleep(seconds) -{ - var e = new Date().getTime() + (seconds * 1000); - while (new Date().getTime() <= e) {} -} + function paragraphIsSentence(html, array) { + var index = indexSentenceEnd(html); -// Mock objects for testing purpose -/*var FolioPageFragment = { + if (index === -1 || index === html.length) { + pushSpan(array, "sentence", html, "paragraphIsSentence"); + html = ""; + } - setHorizontalPageCount : function(pageCount) { - console.warn("-> Mock call to FolioPageFragment.setHorizontalPageCount(" + pageCount + ")"); - }, + return html; + } - storeFirstVisibleSpan : function(usingId, value) { - console.warn("-> Mock call to FolioPageFragment.storeFirstVisibleSpan(" + usingId + ", " + value + ")"); - }, + function paragraphNoMarkup(html, array) { + var open = html.search(rxOpen), + index = 0; - getDirection : function() { - //var direction = "VERTICAL"; - var direction = "HORIZONTAL"; - console.warn("-> Mock call to FolioPageFragment.getDirection(), return " + direction); - return direction; - }, + if (open === -1) { + index = indexSentenceEnd(html); + if (index === -1) { + index = html.length; + } - getTopDistraction : function() { - console.warn("-> Mock call to FolioPageFragment.getTopDistraction(), return " + 0); - return 0; - }, + pushSpan(array, "sentence", html.slice(0, index += 1), "paragraphNoMarkup"); + } - getBottomDistraction : function() { - console.warn("-> Mock call to FolioPageFragment.getBottomDistraction(), return " + 0); - return 0; + return html.slice(index); } -}; -var FolioWebView = { + function sentenceUncontained(html, array) { + var open = html.search(rxOpen), + index = 0, + close; - setCompatMode : function(compatMode) { - console.warn("-> Mock call to FolioWebView.setCompatMode(" + compatMode + ")"); + if (open !== -1) { + index = indexSentenceEnd(html); + if (index === -1) { + index = html.length; + } + + close = html.search(rxClose); + if (index < open || index > close) { + pushSpan(array, "sentence", html.slice(0, index += 1), "sentenceUncontained"); + } else { + index = 0; + } + } + + return html.slice(index); } -}; -var WebViewPager = { + function sentenceContained(html, array) { + var open = html.search(rxOpen), + index = 0, + close, + count; - setCurrentPage : function(pageIndex) { - console.warn("-> Mock call to WebViewPager.setCurrentPage(" + pageIndex + ")"); - }, + if (open !== -1) { + index = indexSentenceEnd(html); + if (index === -1) { + index = html.length; + } - setPageToLast : function() { - console.warn("-> Mock call to WebViewPager.setPageToLast()"); - }, + close = html.search(rxClose); + if (index > open && index < close) { + count = html.match(rxClose)[0].length; + pushSpan(array, "sentence", html.slice(0, close + count), "sentenceContained"); + index = close + count; + } else { + index = 0; + } + } - setPageToFirst : function() { - console.warn("-> Mock call to WebViewPager.setPageToFirst()"); + return html.slice(index); } -}; -var LoadingView = { + function anythingElse(html, array) { + pushSpan(array, "sentence", html, "anythingElse"); - show : function() { - console.warn("-> Mock call to LoadingView.show()"); - }, + return ""; + } - hide : function() { - console.warn("-> Mock call to LoadingView.hide()"); - }, + function guessSenetences() { + var paragraphs = document.getElementsByTagName("p"); - visible : function() { - console.warn("-> Mock call to LoadingView.visible()"); - }, + Array.prototype.forEach.call(paragraphs, function (paragraph) { + var html = paragraph.innerHTML, + length = html.length, + array = [], + safety = 100; - invisible : function() { - console.warn("-> Mock call to LoadingView.invisible()"); + while (length && safety) { + html = addSupToPrevious(html, array); + if (html.length === length) { + if (html.length === length) { + html = paragraphIsSentence(html, array); + if (html.length === length) { + html = paragraphNoMarkup(html, array); + if (html.length === length) { + html = sentenceUncontained(html, array); + if (html.length === length) { + html = sentenceContained(html, array); + if (html.length === length) { + html = anythingElse(html, array); + } + } + } + } + } + } + + length = html.length; + safety -= 1; + } + + try { + paragraph.innerHTML = array.join(""); + } catch(err) { + console.error(err); + console.error("-> " + err.message); + } + }); } -};*/ -var searchResults = []; -var lastSearchQuery = null; -var testCounter = 0; -var searchResultsInvisible = true; + guessSenetences(); +} -// Testing purpose calls -function test() { +$(function(){ + window.ssReader = Class({ + $singleton: true, - ++testCounter; - console.log("-> testCounter = " + testCounter); + init: function() { + rangy.init(); - var searchQuery = "look"; + this.highlighter = rangy.createHighlighter(); - if (testCounter == 1) { + this.highlighter.addClassApplier(rangy.createClassApplier("highlight_yellow", { + ignoreWhiteSpace: true, + tagNames: ["span", "a"] + })); - getCompatMode(); - wrappingSentencesWithinPTags(); + this.highlighter.addClassApplier(rangy.createClassApplier("highlight_green", { + ignoreWhiteSpace: true, + tagNames: ["span", "a"] + })); - if (FolioPageFragment.getDirection() == "HORIZONTAL") - initHorizontalDirection(); + this.highlighter.addClassApplier(rangy.createClassApplier("highlight_blue", { + ignoreWhiteSpace: true, + tagNames: ["span", "a"] + })); - highlightSearchResult(searchQuery, 1); + this.highlighter.addClassApplier(rangy.createClassApplier("highlight_pink", { + ignoreWhiteSpace: true, + tagNames: ["span", "a"] + })); - } else if (testCounter == 2) { + this.highlighter.addClassApplier(rangy.createClassApplier("highlight_underline", { + ignoreWhiteSpace: true, + tagNames: ["span", "a"] + })); - makeSearchResultsInvisible(); + }, - } else if (testCounter == 3) { + setFontAndada: function(){ + this.setFont("andada"); + }, - highlightSearchResult(searchQuery, 2); + setFontLato: function(){ + this.setFont("lato"); + }, - } else if (testCounter == 4) { + setFontPtSerif: function(){ + this.setFont("pt-serif"); + }, - } -} + setFontPtSans: function(){ + this.setFont("pt-sans"); + }, -function highlightSearchResult(searchQuery, occurrenceInChapter) { + base64encode: function(str){ + return btoa(unescape(encodeURIComponent(str))); + }, - if (searchQuery == lastSearchQuery) { - makeSearchResultsInvisible(); - } else { - resetSearchResults(); - searchResults = applySearchResultClass(searchQuery); - console.debug("-> Search Query Found = " + searchResults.length); - } + base64decode: function(str){ + return decodeURIComponent(escape(atob(str))); + }, - applySearchResultVisibleClass(occurrenceInChapter); - LoadingView.hide(); -} + clearSelection: function(){ + if (window.getSelection) { + if (window.getSelection().empty) { // Chrome + window.getSelection().empty(); + } else if (window.getSelection().removeAllRanges) { // Firefox + window.getSelection().removeAllRanges(); + } + } else if (document.selection) { // IE? + document.selection.empty(); + } + }, -function applySearchResultClass(searchQuery) { + // Public methods - var searchQueryRegExp = new RegExp(escapeRegExp(searchQuery), "i"); + setFont: function(fontName){ + $("#ss-wrapper-font").removeClass().addClass("ss-wrapper-"+fontName); + }, - var searchResults = []; - var searchChildNodesArray = []; - var elementArray = []; - var textNodeArray = []; + setSize: function(size){ + $("#ss-wrapper-size").removeClass().addClass("ss-wrapper-"+size); + }, - var bodyElement = document.getElementsByTagName('body')[0]; - var elementsInBody = bodyElement.getElementsByTagName('*'); + setTheme: function(theme){ + $("body, #ss-wrapper-theme").removeClass().addClass("ss-wrapper-"+theme); + }, - for (var i = 0 ; i < elementsInBody.length ; i++) { + setComment: function(comment, inputId){ + $("#"+inputId).val(ssReader.base64decode(comment)); + $("#"+inputId).trigger("input", ["true"]); + }, - var childNodes = elementsInBody[i].childNodes; + highlightSelection: function(color){ + try { - for (var j = 0; j < childNodes.length; j++) { + this.highlighter.highlightSelection(color, null); + var range = window.getSelection().toString(); + var params = {content: range,rangy: this.getHighlights(),color: color}; + this.clearSelection(); + Highlight.onReceiveHighlights(JSON.stringify(params)); + } catch(err){ + console.log("highlightSelection : " + err); + } + }, - if (childNodes[j].nodeType == Node.TEXT_NODE && - childNodes[j].nodeValue.trim().length) { - //console.log("-> " + childNodes[j].nodeValue); + unHighlightSelection: function(){ + try { + this.highlighter.unhighlightSelection(); + Highlight.onReceiveHighlights(this.getHighlights()); + } catch(err){} + }, - if (childNodes[j].nodeValue.match(searchQueryRegExp)) { - //console.log("-> Found -> " + childNodes[j].nodeValue); + getHighlights: function(){ + try { + return this.highlighter.serialize(); + } catch(err){} + }, - searchChildNodesArray.push( - getSearchChildNodes(childNodes[j].nodeValue, searchQuery)); + setHighlights: function(serializedHighlight){ + try { + this.highlighter.removeAllHighlights(); + this.highlighter.deserialize(serializedHighlight); + } catch(err){} + }, - elementArray.push(elementsInBody[i]); - textNodeArray.push(childNodes[j]); - } - } - } + removeAll: function(){ + try { + this.highlighter.removeAllHighlights(); + } catch(err){} + }, + + copy: function(){ + SSBridge.onCopy(window.getSelection().toString()); + this.clearSelection(); + }, + + share: function(){ + SSBridge.onShare(window.getSelection().toString()); + this.clearSelection(); + }, + + search: function(){ + SSBridge.onSearch(window.getSelection().toString()); + this.clearSelection(); } + }); - for (var i = 0 ; i < searchChildNodesArray.length ; i++) { + if(typeof ssReader !== "undefined"){ + ssReader.init(); + } - var searchChildNodes = searchChildNodesArray[i]; + $(".verse").click(function(){ + SSBridge.onVerseClick(ssReader.base64encode($(this).attr("verse"))); + }); - for (var j = 0 ; j < searchChildNodes.length ; j++) { + $("code").each(function(i){ + var textarea = $("