@internetarchive/bookreader 5.0.0-8-multiple-files → 5.0.0-80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +17 -15
- package/.github/workflows/node.js.yml +78 -6
- package/.github/workflows/npm-publish.yml +6 -20
- package/.testcaferc.js +10 -0
- package/BookReader/BookReader.css +442 -1393
- package/BookReader/BookReader.js +2 -21564
- package/BookReader/BookReader.js.LICENSE.txt +20 -20
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +1782 -0
- package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +7 -0
- package/BookReader/ia-bookreader-bundle.js.map +1 -0
- package/BookReader/icons/1up.svg +1 -12
- package/BookReader/icons/2up.svg +1 -15
- package/BookReader/icons/advance.svg +3 -26
- package/BookReader/icons/chevron-right.svg +1 -1
- package/BookReader/icons/close-circle-dark.svg +1 -0
- package/BookReader/icons/close-circle.svg +1 -1
- package/BookReader/icons/fullscreen.svg +1 -17
- package/BookReader/icons/fullscreen_exit.svg +1 -17
- package/BookReader/icons/hamburger.svg +1 -15
- package/BookReader/icons/left-arrow.svg +1 -12
- package/BookReader/icons/magnify-minus.svg +1 -16
- package/BookReader/icons/magnify-plus.svg +1 -17
- package/BookReader/icons/magnify.svg +1 -15
- package/BookReader/icons/pause.svg +1 -23
- package/BookReader/icons/play.svg +1 -22
- package/BookReader/icons/playback-speed.svg +1 -34
- package/BookReader/icons/read-aloud.svg +1 -22
- package/BookReader/icons/review.svg +3 -22
- package/BookReader/icons/thumbnails.svg +1 -17
- package/BookReader/icons/voice.svg +1 -0
- package/BookReader/icons/volume-full.svg +1 -22
- package/BookReader/images/BRicons.svg +5 -94
- package/BookReader/images/books_graphic.svg +1 -177
- package/BookReader/images/icon_book.svg +1 -12
- package/BookReader/images/icon_bookmark.svg +1 -12
- package/BookReader/images/icon_gear.svg +1 -14
- package/BookReader/images/icon_hamburger.svg +1 -20
- package/BookReader/images/icon_home.svg +1 -21
- package/BookReader/images/icon_info.svg +1 -11
- package/BookReader/images/icon_one_page.svg +1 -8
- package/BookReader/images/icon_pause.svg +1 -1
- package/BookReader/images/icon_play.svg +1 -1
- package/BookReader/images/icon_playback-rate.svg +1 -15
- package/BookReader/images/icon_search_button.svg +1 -8
- package/BookReader/images/icon_share.svg +1 -9
- package/BookReader/images/icon_skip-ahead.svg +1 -6
- package/BookReader/images/icon_skip-back.svg +2 -13
- package/BookReader/images/icon_speaker.svg +1 -18
- package/BookReader/images/icon_speaker_open.svg +1 -10
- package/BookReader/images/icon_thumbnails.svg +1 -12
- package/BookReader/images/icon_toc.svg +1 -5
- package/BookReader/images/icon_two_pages.svg +1 -9
- package/BookReader/images/marker_chap-off.svg +1 -11
- package/BookReader/images/marker_chap-on.svg +1 -11
- package/BookReader/images/marker_srch-on.svg +1 -11
- package/BookReader/jquery-3.js +2 -0
- package/BookReader/jquery-3.js.LICENSE.txt +24 -0
- package/BookReader/plugins/plugin.archive_analytics.js +1 -172
- package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
- package/BookReader/plugins/plugin.autoplay.js +1 -165
- package/BookReader/plugins/plugin.autoplay.js.map +1 -1
- package/BookReader/plugins/plugin.chapters.js +22 -301
- package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
- package/BookReader/plugins/plugin.chapters.js.map +1 -1
- package/BookReader/plugins/plugin.iframe.js +1 -74
- package/BookReader/plugins/plugin.iframe.js.map +1 -1
- package/BookReader/plugins/plugin.iiif.js +2 -0
- package/BookReader/plugins/plugin.iiif.js.map +1 -0
- package/BookReader/plugins/plugin.resume.js +1 -368
- package/BookReader/plugins/plugin.resume.js.map +1 -1
- package/BookReader/plugins/plugin.search.js +2 -1420
- package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
- package/BookReader/plugins/plugin.search.js.map +1 -1
- package/BookReader/plugins/plugin.text_selection.js +2 -1080
- package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
- package/BookReader/plugins/plugin.text_selection.js.map +1 -1
- package/BookReader/plugins/plugin.tts.js +2 -9193
- package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
- package/BookReader/plugins/plugin.tts.js.map +1 -1
- package/BookReader/plugins/plugin.url.js +1 -269
- package/BookReader/plugins/plugin.url.js.map +1 -1
- package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -379
- package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
- package/BookReader/webcomponents-bundle.js +3 -0
- package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
- package/BookReader/webcomponents-bundle.js.map +1 -0
- package/BookReaderDemo/BookReaderDemo.css +18 -19
- package/BookReaderDemo/BookReaderJSAdvanced.js +0 -3
- package/BookReaderDemo/BookReaderJSAutoplay.js +4 -1
- package/BookReaderDemo/BookReaderJSSimple.js +1 -0
- package/BookReaderDemo/IADemoBr.js +147 -0
- package/BookReaderDemo/demo-advanced.html +2 -2
- package/BookReaderDemo/demo-autoplay.html +2 -3
- package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
- package/BookReaderDemo/demo-fullscreen-mobile.html +3 -5
- package/BookReaderDemo/demo-fullscreen.html +2 -4
- package/BookReaderDemo/demo-iiif.html +99 -12
- package/BookReaderDemo/demo-internetarchive.html +214 -18
- package/BookReaderDemo/demo-multiple.html +2 -1
- package/BookReaderDemo/demo-preview-pages.html +2 -1
- package/BookReaderDemo/demo-simple.html +2 -1
- package/BookReaderDemo/demo-vendor-fullscreen.html +2 -4
- package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
- package/BookReaderDemo/immersion-1up.html +2 -2
- package/BookReaderDemo/immersion-mode.html +2 -4
- package/BookReaderDemo/toggle_controls.html +3 -2
- package/BookReaderDemo/view_mode.html +2 -1
- package/BookReaderDemo/viewmode-cycle.html +2 -3
- package/CHANGELOG.md +545 -33
- package/README.md +14 -1
- package/babel.config.js +20 -0
- package/codecov.yml +6 -0
- package/index.html +4 -1
- package/jsconfig.json +19 -0
- package/netlify.toml +9 -0
- package/package.json +70 -60
- package/renovate.json +52 -0
- package/scripts/preversion.js +0 -1
- package/src/BookNavigator/assets/bookmark-colors.js +1 -1
- package/src/BookNavigator/assets/button-base.js +9 -2
- package/src/BookNavigator/assets/ia-logo.js +17 -0
- package/src/BookNavigator/assets/icon_checkmark.js +1 -1
- package/src/BookNavigator/assets/icon_close.js +1 -1
- package/src/BookNavigator/book-navigator.js +590 -0
- package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
- package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
- package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
- package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
- package/src/BookNavigator/bookmarks/bookmarks-provider.js +27 -17
- package/src/BookNavigator/bookmarks/ia-bookmarks.js +116 -67
- package/src/BookNavigator/delete-modal-actions.js +1 -1
- package/src/BookNavigator/downloads/downloads-provider.js +36 -21
- package/src/BookNavigator/downloads/downloads.js +41 -25
- package/src/BookNavigator/search/search-provider.js +80 -28
- package/src/BookNavigator/search/search-results.js +28 -25
- package/src/BookNavigator/sharing.js +27 -0
- package/src/BookNavigator/viewable-files.js +95 -0
- package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -10
- package/src/BookNavigator/visual-adjustments/visual-adjustments.js +3 -3
- package/src/BookReader/BookModel.js +64 -34
- package/src/BookReader/DragScrollable.js +233 -0
- package/src/BookReader/Mode1Up.js +56 -351
- package/src/BookReader/Mode1UpLit.js +388 -0
- package/src/BookReader/Mode2Up.js +73 -1318
- package/src/BookReader/Mode2UpLit.js +776 -0
- package/src/BookReader/ModeCoordinateSpace.js +29 -0
- package/src/BookReader/ModeSmoothZoom.js +312 -0
- package/src/BookReader/ModeThumb.js +18 -12
- package/src/BookReader/Navbar/Navbar.js +14 -40
- package/src/BookReader/PageContainer.js +81 -6
- package/src/BookReader/ReduceSet.js +1 -1
- package/src/BookReader/Toolbar/Toolbar.js +10 -37
- package/src/BookReader/events.js +2 -3
- package/src/BookReader/options.js +27 -2
- package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
- package/src/BookReader/utils/ScrollClassAdder.js +31 -0
- package/src/BookReader/utils/SelectionObserver.js +45 -0
- package/src/BookReader/utils.js +118 -13
- package/src/BookReader.js +446 -1062
- package/src/assets/icons/close-circle-dark.svg +1 -0
- package/src/assets/icons/magnify-minus.svg +3 -7
- package/src/assets/icons/magnify-plus.svg +3 -7
- package/src/assets/icons/voice.svg +1 -0
- package/src/css/BookReader.scss +1 -17
- package/src/css/_BRBookmarks.scss +1 -1
- package/src/css/_BRComponent.scss +1 -1
- package/src/css/_BRmain.scss +33 -27
- package/src/css/_BRnav.scss +12 -39
- package/src/css/_BRpages.scss +149 -40
- package/src/css/_BRsearch.scss +68 -230
- package/src/css/_BRtoolbar.scss +5 -5
- package/src/css/_TextSelection.scss +87 -27
- package/src/css/_colorbox.scss +2 -2
- package/src/css/_controls.scss +20 -7
- package/src/css/_icons.scss +7 -1
- package/src/ia-bookreader/ia-bookreader.js +224 -0
- package/src/plugins/plugin.archive_analytics.js +3 -3
- package/src/plugins/plugin.autoplay.js +5 -11
- package/src/plugins/plugin.chapters.js +237 -191
- package/src/plugins/plugin.iiif.js +151 -0
- package/src/plugins/plugin.resume.js +3 -3
- package/src/plugins/plugin.text_selection.js +464 -134
- package/src/plugins/plugin.vendor-fullscreen.js +4 -4
- package/src/plugins/search/plugin.search.js +175 -120
- package/src/plugins/search/utils.js +43 -0
- package/src/plugins/search/view.js +64 -202
- package/src/plugins/tts/AbstractTTSEngine.js +71 -40
- package/src/plugins/tts/FestivalTTSEngine.js +13 -14
- package/src/plugins/tts/PageChunk.js +15 -21
- package/src/plugins/tts/PageChunkIterator.js +8 -12
- package/src/plugins/tts/WebTTSEngine.js +87 -71
- package/src/plugins/tts/plugin.tts.js +96 -127
- package/src/plugins/tts/utils.js +15 -25
- package/src/plugins/url/UrlPlugin.js +191 -0
- package/src/plugins/{plugin.url.js → url/plugin.url.js} +45 -16
- package/src/util/browserSniffing.js +22 -0
- package/src/util/docCookies.js +21 -2
- package/tests/e2e/README.md +37 -0
- package/tests/e2e/autoplay.test.js +2 -2
- package/tests/e2e/base.test.js +8 -16
- package/tests/e2e/helpers/base.js +53 -48
- package/tests/e2e/helpers/debug.js +1 -1
- package/tests/e2e/helpers/params.js +17 -0
- package/tests/e2e/helpers/rightToLeft.js +8 -14
- package/tests/e2e/helpers/search.js +73 -0
- package/tests/e2e/models/Navigation.js +20 -37
- package/tests/e2e/rightToLeft.test.js +4 -5
- package/tests/e2e/viewmode.test.js +40 -33
- package/tests/jest/BookNavigator/book-navigator.test.js +661 -0
- package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
- package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
- package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
- package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
- package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
- package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
- package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
- package/tests/{karma/BookNavigator → jest/BookNavigator/search}/search-results.test.js +109 -60
- package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
- package/tests/jest/BookNavigator/viewable-files/viewable-files-provider.test.js +80 -0
- package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
- package/tests/{BookReader → jest/BookReader}/BookModel.test.js +74 -14
- package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +193 -0
- package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
- package/tests/jest/BookReader/Mode1UpLit.test.js +73 -0
- package/tests/jest/BookReader/Mode2Up.test.js +98 -0
- package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
- package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
- package/tests/jest/BookReader/ModeSmoothZoom.test.js +218 -0
- package/tests/jest/BookReader/ModeThumb.test.js +71 -0
- package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +10 -10
- package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +88 -6
- package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
- package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
- package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
- package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
- package/tests/jest/BookReader/utils/SelectionObserver.test.js +57 -0
- package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
- package/tests/jest/BookReader/utils.test.js +229 -0
- package/tests/jest/BookReader.keyboard.test.js +190 -0
- package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
- package/tests/{BookReader.test.js → jest/BookReader.test.js} +26 -37
- package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +4 -4
- package/tests/jest/plugins/plugin.chapters.test.js +195 -0
- package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
- package/tests/jest/plugins/plugin.text_selection.test.js +317 -0
- package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
- package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +26 -47
- package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +39 -6
- package/tests/jest/plugins/search/utils.js +25 -0
- package/tests/jest/plugins/search/utils.test.js +29 -0
- package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +29 -9
- package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
- package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
- package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
- package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +47 -1
- package/tests/{plugins → jest/plugins}/tts/utils.test.js +1 -60
- package/tests/jest/plugins/url/UrlPlugin.test.js +198 -0
- package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +53 -14
- package/tests/jest/setup.js +3 -0
- package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
- package/tests/jest/util/docCookies.test.js +24 -0
- package/tests/{util → jest/util}/strings.test.js +1 -1
- package/tests/{utils.js → jest/utils.js} +38 -0
- package/webpack.config.js +12 -6
- package/.babelrc +0 -12
- package/.dependabot/config.yml +0 -6
- package/.testcaferc.json +0 -5
- package/BookReader/bookreader-component-bundle.js +0 -14312
- package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
- package/BookReader/bookreader-component-bundle.js.map +0 -1
- package/BookReader/icons/sort-ascending.svg +0 -1
- package/BookReader/icons/sort-descending.svg +0 -1
- package/BookReader/jquery-1.10.1.js +0 -108
- package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
- package/BookReader/plugins/plugin.menu_toggle.js +0 -369
- package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
- package/BookReader/plugins/plugin.mobile_nav.js +0 -335
- package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
- package/BookReaderDemo/IIIFBookReader.js +0 -207
- package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
- package/BookReaderDemo/demo-iiif.js +0 -26
- package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
- package/karma.conf.js +0 -23
- package/src/BookNavigator/BookModel.js +0 -14
- package/src/BookNavigator/BookNavigator.js +0 -452
- package/src/BookNavigator/assets/book-loader.js +0 -27
- package/src/BookNavigator/assets/icon_sort_ascending.js +0 -5
- package/src/BookNavigator/assets/icon_sort_descending.js +0 -5
- package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
- package/src/BookNavigator/search/a-search-result.js +0 -55
- package/src/BookNavigator/volumes/volumes-provider.js +0 -76
- package/src/BookNavigator/volumes/volumes.js +0 -161
- package/src/BookReader/DebugConsole.js +0 -54
- package/src/BookReaderComponent/BookReaderComponent.js +0 -112
- package/src/ItemNavigator/ItemNavigator.js +0 -372
- package/src/ItemNavigator/providers/sharing.js +0 -29
- package/src/assets/icons/sort-ascending.svg +0 -1
- package/src/assets/icons/sort-descending.svg +0 -1
- package/src/css/_MobileNav.scss +0 -194
- package/src/dragscrollable-br.js +0 -261
- package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
- package/src/plugins/plugin.mobile_nav.js +0 -287
- package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
- package/tests/BookReader/DebugConsole.test.js +0 -25
- package/tests/BookReader/Mode1Up.test.js +0 -164
- package/tests/BookReader/Mode2Up.test.js +0 -247
- package/tests/BookReader/utils.test.js +0 -109
- package/tests/e2e/helpers/desktopSearch.js +0 -72
- package/tests/e2e/helpers/mobileSearch.js +0 -85
- package/tests/e2e/ia-production/ia-prod-base.js +0 -17
- package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
- package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
- package/tests/karma/BookNavigator/volumes.test.js +0 -101
- package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
- package/tests/plugins/plugin.chapters.test.js +0 -130
- package/tests/plugins/plugin.mobile_nav.test.js +0 -66
- package/tests/plugins/plugin.text_selection.test.js +0 -203
- package/tests/util/docCookies.test.js +0 -15
|
@@ -21,27 +21,18 @@ export default class PageChunk {
|
|
|
21
21
|
* @param {number} leafIndex
|
|
22
22
|
* @return {Promise<PageChunk[]>}
|
|
23
23
|
*/
|
|
24
|
-
static fetch(server, bookPath, leafIndex) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
cache: true,
|
|
35
|
-
data: {
|
|
36
|
-
path: `${bookPath}_djvu.xml`,
|
|
37
|
-
page: leafIndex
|
|
38
|
-
},
|
|
39
|
-
error: rej,
|
|
40
|
-
})
|
|
41
|
-
.then(chunks => {
|
|
42
|
-
res(PageChunk._fromTextWrapperResponse(leafIndex, chunks));
|
|
43
|
-
});
|
|
24
|
+
static async fetch(server, bookPath, leafIndex) {
|
|
25
|
+
const chunks = await $.ajax({
|
|
26
|
+
type: 'GET',
|
|
27
|
+
url: `https://${server}/BookReader/BookReaderGetTextWrapper.php`,
|
|
28
|
+
dataType:'jsonp',
|
|
29
|
+
cache: true,
|
|
30
|
+
data: {
|
|
31
|
+
path: `${bookPath}_djvu.xml`,
|
|
32
|
+
page: leafIndex
|
|
33
|
+
}
|
|
44
34
|
});
|
|
35
|
+
return PageChunk._fromTextWrapperResponse(leafIndex, chunks);
|
|
45
36
|
}
|
|
46
37
|
|
|
47
38
|
/**
|
|
@@ -97,7 +88,10 @@ export default class PageChunk {
|
|
|
97
88
|
* @return {string}
|
|
98
89
|
*/
|
|
99
90
|
static _removeDanglingHyphens(text) {
|
|
100
|
-
|
|
91
|
+
// Some books mis-OCR a dangling hyphen as a ¬ (mathematical not sign) . Since in math
|
|
92
|
+
// the not sign should not appear followed by a space, we think we can safely assume
|
|
93
|
+
// this should be replaced.
|
|
94
|
+
return text.replace(/[-¬]\s+/g, '');
|
|
101
95
|
}
|
|
102
96
|
}
|
|
103
97
|
|
|
@@ -53,22 +53,18 @@ export default class PageChunkIterator {
|
|
|
53
53
|
* in the correct order.
|
|
54
54
|
* @return {PromiseLike<"__PageChunkIterator.AT_END__" | PageChunk>}
|
|
55
55
|
*/
|
|
56
|
-
_nextUncontrolled() {
|
|
56
|
+
async _nextUncontrolled() {
|
|
57
57
|
if (this._cursor.page == this.pageCount) {
|
|
58
58
|
return Promise.resolve(PageChunkIterator.AT_END);
|
|
59
59
|
}
|
|
60
|
-
|
|
61
60
|
this._recenterBuffer(this._cursor.page);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
return chunks[this._cursor.chunk++];
|
|
71
|
-
});
|
|
61
|
+
const chunks = await this._fetchPageChunks(this._cursor.page);
|
|
62
|
+
if (this._cursor.chunk == chunks.length) {
|
|
63
|
+
this._cursor.page++;
|
|
64
|
+
this._cursor.chunk = 0;
|
|
65
|
+
return this._nextUncontrolled();
|
|
66
|
+
}
|
|
67
|
+
return chunks[this._cursor.chunk++];
|
|
72
68
|
}
|
|
73
69
|
|
|
74
70
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* global br */
|
|
2
2
|
import { isChrome, isFirefox } from '../../util/browserSniffing.js';
|
|
3
|
-
import {
|
|
3
|
+
import { isAndroid } from './utils.js';
|
|
4
|
+
import { promisifyEvent, sleep } from '../../BookReader/utils.js';
|
|
4
5
|
import AbstractTTSEngine from './AbstractTTSEngine.js';
|
|
5
6
|
/** @typedef {import("./AbstractTTSEngine.js").PageChunk} PageChunk */
|
|
6
7
|
/** @typedef {import("./AbstractTTSEngine.js").AbstractTTSSound} AbstractTTSSound */
|
|
@@ -70,7 +71,22 @@ export default class WebTTSEngine extends AbstractTTSEngine {
|
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
/** @override */
|
|
73
|
-
getVoices() {
|
|
74
|
+
getVoices() {
|
|
75
|
+
const voices = speechSynthesis.getVoices();
|
|
76
|
+
if (voices.filter(v => v.default).length != 1) {
|
|
77
|
+
// iOS bug where the default system voice is sometimes
|
|
78
|
+
// missing from the list
|
|
79
|
+
voices.unshift({
|
|
80
|
+
voiceURI: 'bookreader.SystemDefault',
|
|
81
|
+
name: 'System Default',
|
|
82
|
+
// Not necessarily true, but very likely
|
|
83
|
+
lang: navigator.language,
|
|
84
|
+
default: true,
|
|
85
|
+
localService: true,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return voices;
|
|
89
|
+
}
|
|
74
90
|
|
|
75
91
|
/** @override */
|
|
76
92
|
createSound(chunk) {
|
|
@@ -121,7 +137,11 @@ export class WebTTSSound {
|
|
|
121
137
|
this.started = false;
|
|
122
138
|
|
|
123
139
|
this.utterance = new SpeechSynthesisUtterance(this.text.slice(this._charIndex));
|
|
124
|
-
|
|
140
|
+
// iOS bug where the default system voice is sometimes
|
|
141
|
+
// missing from the list
|
|
142
|
+
if (this.voice?.voiceURI !== 'bookreader.SystemDefault') {
|
|
143
|
+
this.utterance.voice = this.voice;
|
|
144
|
+
}
|
|
125
145
|
// Need to also set lang (for some reason); won't set voice on Chrome@Android otherwise
|
|
126
146
|
if (this.voice) this.utterance.lang = this.voice.lang;
|
|
127
147
|
this.utterance.rate = this.rate;
|
|
@@ -167,7 +187,7 @@ export class WebTTSSound {
|
|
|
167
187
|
* left off.
|
|
168
188
|
* @return {Promise<void>}
|
|
169
189
|
*/
|
|
170
|
-
reload() {
|
|
190
|
+
async reload() {
|
|
171
191
|
// We'll restore the pause state, so copy it here
|
|
172
192
|
const wasPaused = this.paused;
|
|
173
193
|
// Use recent event to determine where we'll restart from
|
|
@@ -179,14 +199,12 @@ export class WebTTSSound {
|
|
|
179
199
|
}
|
|
180
200
|
|
|
181
201
|
// We can't modify the utterance object, so we have to make a new one
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if (!wasPaused) this.play();
|
|
189
|
-
});
|
|
202
|
+
await this.stop();
|
|
203
|
+
this.load();
|
|
204
|
+
// Instead of playing and immediately pausing, we don't start playing. Note
|
|
205
|
+
// this is a requirement because pause doesn't work consistently across
|
|
206
|
+
// browsers.
|
|
207
|
+
if (!wasPaused) this.play();
|
|
190
208
|
}
|
|
191
209
|
|
|
192
210
|
play() {
|
|
@@ -222,15 +240,16 @@ export class WebTTSSound {
|
|
|
222
240
|
return endPromise;
|
|
223
241
|
}
|
|
224
242
|
|
|
225
|
-
finish() {
|
|
226
|
-
this.stop()
|
|
243
|
+
async finish() {
|
|
244
|
+
await this.stop();
|
|
245
|
+
this.utterance.dispatchEvent(new Event('finish'));
|
|
227
246
|
}
|
|
228
247
|
|
|
229
248
|
/**
|
|
230
249
|
* @override
|
|
231
250
|
* Will fire a pause event unless already paused
|
|
232
251
|
**/
|
|
233
|
-
pause() {
|
|
252
|
+
async pause() {
|
|
234
253
|
if (this.paused) return;
|
|
235
254
|
|
|
236
255
|
const pausePromise = promisifyEvent(this.utterance, 'pause');
|
|
@@ -246,19 +265,18 @@ export class WebTTSSound {
|
|
|
246
265
|
if (pauseMightNotFire) {
|
|
247
266
|
// wait for it just in case
|
|
248
267
|
const timeoutPromise = sleep(100).then(() => 'timeout');
|
|
249
|
-
Promise.race([pausePromise, timeoutPromise])
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
});
|
|
268
|
+
const result = await Promise.race([pausePromise, timeoutPromise]);
|
|
269
|
+
// We got our pause event; nothing to do!
|
|
270
|
+
if (result != 'timeout') return;
|
|
271
|
+
|
|
272
|
+
this.utterance.dispatchEvent(new CustomEvent('pause', this._lastEvents.start));
|
|
273
|
+
|
|
274
|
+
// if pause might not work, then we'll stop entirely and restart later
|
|
275
|
+
if (pauseMightNotWork) this.stop();
|
|
258
276
|
}
|
|
259
277
|
}
|
|
260
278
|
|
|
261
|
-
resume() {
|
|
279
|
+
async resume() {
|
|
262
280
|
if (!this.started) {
|
|
263
281
|
this.play();
|
|
264
282
|
return;
|
|
@@ -278,16 +296,15 @@ export class WebTTSSound {
|
|
|
278
296
|
speechSynthesis.resume();
|
|
279
297
|
|
|
280
298
|
if (resumeMightNotFire) {
|
|
281
|
-
Promise.race([resumePromise, sleep(100).then(() => 'timeout')])
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
});
|
|
299
|
+
const result = await Promise.race([resumePromise, sleep(100).then(() => 'timeout')]);
|
|
300
|
+
|
|
301
|
+
if (result != 'timeout') return;
|
|
302
|
+
|
|
303
|
+
this.utterance.dispatchEvent(new CustomEvent('resume', {}));
|
|
304
|
+
if (resumeMightNotWork) {
|
|
305
|
+
await this.reload();
|
|
306
|
+
this.play();
|
|
307
|
+
}
|
|
291
308
|
}
|
|
292
309
|
}
|
|
293
310
|
|
|
@@ -296,6 +313,11 @@ export class WebTTSSound {
|
|
|
296
313
|
this.reload();
|
|
297
314
|
}
|
|
298
315
|
|
|
316
|
+
/** @param {SpeechSynthesisVoice} voice */
|
|
317
|
+
setVoice(voice) {
|
|
318
|
+
this.voice = voice;
|
|
319
|
+
this.reload();
|
|
320
|
+
}
|
|
299
321
|
/**
|
|
300
322
|
* @private
|
|
301
323
|
* Chrome has a bug where it only plays 15 seconds of TTS and then
|
|
@@ -303,45 +325,39 @@ export class WebTTSSound {
|
|
|
303
325
|
* We avoid this (as described here: https://bugs.chromium.org/p/chromium/issues/detail?id=679437#c15 )
|
|
304
326
|
* by pausing after 14 seconds and ~instantly resuming.
|
|
305
327
|
*/
|
|
306
|
-
_chromePausingBugFix() {
|
|
328
|
+
async _chromePausingBugFix() {
|
|
307
329
|
const timeoutPromise = sleep(14000).then(() => 'timeout');
|
|
308
330
|
const pausePromise = promisifyEvent(this.utterance, 'pause').then(() => 'paused');
|
|
309
331
|
const endPromise = promisifyEvent(this.utterance, 'end').then(() => 'ended');
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
speechSynthesis.resume();
|
|
340
|
-
this._chromePausingBugFix();
|
|
341
|
-
});
|
|
342
|
-
break;
|
|
343
|
-
}
|
|
344
|
-
});
|
|
332
|
+
const result = await Promise.race([timeoutPromise, pausePromise, endPromise]);
|
|
333
|
+
if (location.toString().indexOf('_debugReadAloud=true') != -1) {
|
|
334
|
+
console.log(`CHROME-PAUSE-HACK: ${result}`);
|
|
335
|
+
}
|
|
336
|
+
switch (result) {
|
|
337
|
+
case 'ended':
|
|
338
|
+
// audio was stopped/finished; nothing to do
|
|
339
|
+
break;
|
|
340
|
+
case 'paused':
|
|
341
|
+
// audio was paused; wait for resume
|
|
342
|
+
// Chrome won't let you resume the audio if 14s have passed 🤷
|
|
343
|
+
// We could do the same as before (but resume+pause instead of pause+resume),
|
|
344
|
+
// but that means we'd _constantly_ be running in the background. So in that
|
|
345
|
+
// case, let's just restart the chunk
|
|
346
|
+
await Promise.race([
|
|
347
|
+
promisifyEvent(this.utterance, 'resume'),
|
|
348
|
+
sleep(14000).then(() => 'timeout'),
|
|
349
|
+
]);
|
|
350
|
+
result == 'timeout' ? this.reload() : this._chromePausingBugFix();
|
|
351
|
+
break;
|
|
352
|
+
case 'timeout':
|
|
353
|
+
// We hit Chrome's secret cut off time. Pause/resume
|
|
354
|
+
// to be able to keep TTS-ing
|
|
355
|
+
speechSynthesis.pause();
|
|
356
|
+
await sleep(25);
|
|
357
|
+
speechSynthesis.resume();
|
|
358
|
+
this._chromePausingBugFix();
|
|
359
|
+
break;
|
|
360
|
+
}
|
|
345
361
|
}
|
|
346
362
|
}
|
|
347
363
|
|
|
@@ -6,8 +6,9 @@ import FestivalTTSEngine from './FestivalTTSEngine.js';
|
|
|
6
6
|
import WebTTSEngine from './WebTTSEngine.js';
|
|
7
7
|
import { toISO6391, approximateWordCount } from './utils.js';
|
|
8
8
|
import { en as tooltips } from './tooltip_dict.js';
|
|
9
|
-
|
|
10
|
-
/** @typedef {import(
|
|
9
|
+
import { renderBoxesInPageContainerLayer } from '../../BookReader/PageContainer.js';
|
|
10
|
+
/** @typedef {import('./PageChunk.js').default} PageChunk */
|
|
11
|
+
/** @typedef {import("./AbstractTTSEngine.js").default} AbstractTTSEngine */
|
|
11
12
|
|
|
12
13
|
// Default options for TTS
|
|
13
14
|
jQuery.extend(BookReader.defaultOptions, {
|
|
@@ -22,7 +23,9 @@ BookReader.prototype.setup = (function (super_) {
|
|
|
22
23
|
super_.call(this, options);
|
|
23
24
|
|
|
24
25
|
if (this.options.enableTtsPlugin) {
|
|
25
|
-
|
|
26
|
+
/** @type { {[pageIndex: number]: Array<{ l: number, r: number, t: number, b: number }>} } */
|
|
27
|
+
this._ttsBoxesByIndex = {};
|
|
28
|
+
|
|
26
29
|
let TTSEngine = WebTTSEngine.isSupported() ? WebTTSEngine :
|
|
27
30
|
FestivalTTSEngine.isSupported() ? FestivalTTSEngine :
|
|
28
31
|
null;
|
|
@@ -54,17 +57,6 @@ BookReader.prototype.init = (function(super_) {
|
|
|
54
57
|
if (this.options.enableTtsPlugin) {
|
|
55
58
|
// Bind to events
|
|
56
59
|
|
|
57
|
-
// TODO move this to BookReader.js or something
|
|
58
|
-
this.bind(BookReader.eventNames.fragmentChange, () => {
|
|
59
|
-
if (this.mode == this.constMode2up) {
|
|
60
|
-
// clear highlights if they're no longer valid for this page
|
|
61
|
-
const visibleIndices = [this.twoPage.currentIndexL, this.twoPage.currentIndexR];
|
|
62
|
-
const visibleSelector = visibleIndices.map(i => `.BRReadAloudHilite.Leaf-${i}`).join(', ');
|
|
63
|
-
$(this.ttsHilites).filter(visibleSelector).show();
|
|
64
|
-
$(this.ttsHilites).not(visibleSelector).hide();
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
|
|
68
60
|
this.bind(BookReader.eventNames.PostInit, () => {
|
|
69
61
|
this.$('.BRicon.read').click(() => {
|
|
70
62
|
this.ttsToggle();
|
|
@@ -88,6 +80,17 @@ BookReader.prototype.init = (function(super_) {
|
|
|
88
80
|
};
|
|
89
81
|
})(BookReader.prototype.init);
|
|
90
82
|
|
|
83
|
+
/** @override */
|
|
84
|
+
BookReader.prototype._createPageContainer = (function (super_) {
|
|
85
|
+
return function (index) {
|
|
86
|
+
const pageContainer = super_.call(this, index);
|
|
87
|
+
if (this.options.enableTtsPlugin && pageContainer.page && index in this._ttsBoxesByIndex) {
|
|
88
|
+
const pageIndex = pageContainer.page.index;
|
|
89
|
+
renderBoxesInPageContainerLayer('ttsHiliteLayer', this._ttsBoxesByIndex[pageIndex], pageContainer.page, pageContainer.$container[0]);
|
|
90
|
+
}
|
|
91
|
+
return pageContainer;
|
|
92
|
+
};
|
|
93
|
+
})(BookReader.prototype._createPageContainer);
|
|
91
94
|
|
|
92
95
|
// Extend buildMobileDrawerElement
|
|
93
96
|
BookReader.prototype.buildMobileDrawerElement = (function (super_) {
|
|
@@ -146,19 +149,53 @@ BookReader.prototype.initNavbar = (function (super_) {
|
|
|
146
149
|
<div class="icon icon-advance"></div>
|
|
147
150
|
</button>
|
|
148
151
|
</li>
|
|
152
|
+
<li>
|
|
153
|
+
<select class="playback-voices" name="playback-voice" style="display: none" title="Change read aloud voices">
|
|
154
|
+
</select>
|
|
155
|
+
</li>
|
|
149
156
|
</ul>
|
|
150
157
|
`);
|
|
158
|
+
|
|
151
159
|
$el.find('.BRcontrols').prepend(this.refs.$BRReadAloudToolbar);
|
|
160
|
+
|
|
161
|
+
const renderVoiceOption = (voices) => {
|
|
162
|
+
return voices.map(voice =>
|
|
163
|
+
`<option value="${voice.voiceURI}">${voice.lang} - ${voice.name}</option>`).join('');
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const voiceSortOrder = (a,b) => `${a.lang} - ${a.name}`.localeCompare(`${b.lang} - ${b.name}`);
|
|
167
|
+
|
|
168
|
+
const renderVoicesMenu = (voicesMenu) => {
|
|
169
|
+
voicesMenu.empty();
|
|
170
|
+
const bookLanguage = this.ttsEngine.opts.bookLanguage;
|
|
171
|
+
const bookLanguages = this.ttsEngine.getVoices().filter(v => v.lang.startsWith(bookLanguage)).sort(voiceSortOrder);
|
|
172
|
+
const otherLanguages = this.ttsEngine.getVoices().filter(v => !v.lang.startsWith(bookLanguage)).sort(voiceSortOrder);
|
|
173
|
+
|
|
174
|
+
if (this.ttsEngine.getVoices().length > 1) {
|
|
175
|
+
voicesMenu.append($(`<optgroup label="Book Language (${bookLanguage})"> ${renderVoiceOption(bookLanguages)} </optgroup>`));
|
|
176
|
+
voicesMenu.append($(`<optgroup label="Other Languages"> ${renderVoiceOption(otherLanguages)} </optgroup>`));
|
|
177
|
+
|
|
178
|
+
voicesMenu.val(this.ttsEngine.voice.voiceURI);
|
|
179
|
+
voicesMenu.show();
|
|
180
|
+
} else {
|
|
181
|
+
voicesMenu.hide();
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const voicesMenu = this.refs.$BRReadAloudToolbar.find('[name=playback-voice]');
|
|
186
|
+
renderVoicesMenu(voicesMenu);
|
|
187
|
+
voicesMenu.on("change", ev => this.ttsEngine.setVoice(voicesMenu.val()));
|
|
152
188
|
this.ttsEngine.events.on('pause resume start', () => this.ttsUpdateState());
|
|
153
|
-
this.
|
|
154
|
-
this.refs.$BRReadAloudToolbar.find('[name=
|
|
155
|
-
this.refs.$BRReadAloudToolbar.find('[name=
|
|
189
|
+
this.ttsEngine.events.on('voiceschanged', () => renderVoicesMenu(voicesMenu));
|
|
190
|
+
this.refs.$BRReadAloudToolbar.find('[name=play]').on("click", this.ttsPlayPause.bind(this));
|
|
191
|
+
this.refs.$BRReadAloudToolbar.find('[name=advance]').on("click", this.ttsJumpForward.bind(this));
|
|
192
|
+
this.refs.$BRReadAloudToolbar.find('[name=review]').on("click", this.ttsJumpBackward.bind(this));
|
|
156
193
|
const $rateSelector = this.refs.$BRReadAloudToolbar.find('select[name="playback-speed"]');
|
|
157
|
-
$rateSelector.change
|
|
194
|
+
$rateSelector.on("change", ev => this.ttsEngine.setPlaybackRate(parseFloat($rateSelector.val())));
|
|
158
195
|
$(`<li>
|
|
159
196
|
<button class="BRicon read js-tooltip" title="${tooltips.readAloud}">
|
|
160
197
|
<div class="icon icon-read-aloud"></div>
|
|
161
|
-
<span class="
|
|
198
|
+
<span class="BRtooltip">${tooltips.readAloud}</span>
|
|
162
199
|
</button>
|
|
163
200
|
</li>`).insertBefore($el.find('.BRcontrols .BRicon.zoom_out').closest('li'));
|
|
164
201
|
}
|
|
@@ -187,7 +224,7 @@ BookReader.prototype.ttsStart = function (startTTSEngine = true) {
|
|
|
187
224
|
this.$('.BRicon.read').addClass('unread active');
|
|
188
225
|
this.ttsSendAnalyticsEvent('Start');
|
|
189
226
|
if (startTTSEngine)
|
|
190
|
-
this.ttsEngine.start(this.currentIndex(), this.getNumLeafs());
|
|
227
|
+
this.ttsEngine.start(this.currentIndex(), this.book.getNumLeafs());
|
|
191
228
|
};
|
|
192
229
|
|
|
193
230
|
BookReader.prototype.ttsJumpForward = function () {
|
|
@@ -214,7 +251,7 @@ BookReader.prototype.ttsPlayPause = function() {
|
|
|
214
251
|
this.ttsToggle();
|
|
215
252
|
} else {
|
|
216
253
|
this.ttsEngine.togglePlayPause();
|
|
217
|
-
this.ttsUpdateState(
|
|
254
|
+
this.ttsUpdateState();
|
|
218
255
|
}
|
|
219
256
|
};
|
|
220
257
|
|
|
@@ -233,12 +270,10 @@ BookReader.prototype.ttsStop = function () {
|
|
|
233
270
|
* @param {PageChunk} chunk
|
|
234
271
|
* @return {PromiseLike<void>} returns once the flip is done
|
|
235
272
|
*/
|
|
236
|
-
BookReader.prototype.ttsBeforeChunkPlay = function(chunk) {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
this.ttsScrollToChunk(chunk);
|
|
241
|
-
});
|
|
273
|
+
BookReader.prototype.ttsBeforeChunkPlay = async function(chunk) {
|
|
274
|
+
await this.ttsMaybeFlipToIndex(chunk.leafIndex);
|
|
275
|
+
this.ttsHighlightChunk(chunk);
|
|
276
|
+
this.ttsScrollToChunk(chunk);
|
|
242
277
|
};
|
|
243
278
|
|
|
244
279
|
/**
|
|
@@ -251,129 +286,63 @@ BookReader.prototype.ttsSendChunkFinishedAnalyticsEvent = function(chunk) {
|
|
|
251
286
|
/**
|
|
252
287
|
* Flip the page if the provided leaf index is not visible
|
|
253
288
|
* @param {Number} leafIndex
|
|
254
|
-
* @return {PromiseLike<void>} resolves once the flip animation has completed
|
|
255
289
|
*/
|
|
256
|
-
BookReader.prototype.ttsMaybeFlipToIndex = function (leafIndex) {
|
|
257
|
-
|
|
258
|
-
let resolve = null;
|
|
259
|
-
const promise = new Promise(res => resolve = res);
|
|
260
|
-
|
|
261
|
-
if (!in2PageMode) {
|
|
290
|
+
BookReader.prototype.ttsMaybeFlipToIndex = async function (leafIndex) {
|
|
291
|
+
if (this.constMode2up != this.mode) {
|
|
262
292
|
this.jumpToIndex(leafIndex);
|
|
263
|
-
resolve();
|
|
264
293
|
} else {
|
|
265
|
-
|
|
266
|
-
if (leafVisible) {
|
|
267
|
-
resolve();
|
|
268
|
-
} else {
|
|
269
|
-
this.animationFinishedCallback = resolve;
|
|
270
|
-
const mustGoNext = leafIndex > Math.max(this.twoPage.currentIndexR, this.twoPage.currentIndexL);
|
|
271
|
-
if (mustGoNext) this.next();
|
|
272
|
-
else this.prev();
|
|
273
|
-
promise.then(this.ttsMaybeFlipToIndex.bind(this, leafIndex));
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
return promise;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* @param {PageChunk} chunk
|
|
282
|
-
*/
|
|
283
|
-
BookReader.prototype.ttsHighlightChunk = function(chunk) {
|
|
284
|
-
this.ttsRemoveHilites();
|
|
285
|
-
|
|
286
|
-
if (this.constMode2up == this.mode) {
|
|
287
|
-
this.ttsHilite2UP(chunk);
|
|
288
|
-
} else {
|
|
289
|
-
this.ttsHilite1UP(chunk);
|
|
294
|
+
await this._modes.mode2Up.mode2UpLit.jumpToIndex(leafIndex);
|
|
290
295
|
}
|
|
291
296
|
};
|
|
292
297
|
|
|
293
298
|
/**
|
|
294
299
|
* @param {PageChunk} chunk
|
|
295
300
|
*/
|
|
296
|
-
BookReader.prototype.
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
let leafTop = 0;
|
|
300
|
-
let h;
|
|
301
|
-
let i;
|
|
302
|
-
for (i = 0; i < chunk.leafIndex; i++) {
|
|
303
|
-
h = parseInt(this._getPageHeight(i) / this.reduce);
|
|
304
|
-
leafTop += h + this.padding;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
const chunkTop = chunk.lineRects[0][3]; //coords are in l,b,r,t order
|
|
308
|
-
const chunkBot = chunk.lineRects[chunk.lineRects.length - 1][1];
|
|
309
|
-
|
|
310
|
-
const topOfFirstChunk = leafTop + chunkTop / this.reduce;
|
|
311
|
-
const botOfLastChunk = leafTop + chunkBot / this.reduce;
|
|
312
|
-
|
|
313
|
-
if (window?.soundManager?.debugMode) console.log('leafTop = ' + leafTop + ' topOfFirstChunk = ' + topOfFirstChunk + ' botOfLastChunk = ' + botOfLastChunk);
|
|
301
|
+
BookReader.prototype.ttsHighlightChunk = function(chunk) {
|
|
302
|
+
// The poorly-named variable leafIndex
|
|
303
|
+
const pageIndex = chunk.leafIndex;
|
|
314
304
|
|
|
315
|
-
|
|
316
|
-
const containerBot = containerTop + this.refs.$brContainer.height();
|
|
317
|
-
if (window?.soundManager?.debugMode) console.log('containerTop = ' + containerTop + ' containerBot = ' + containerBot);
|
|
305
|
+
this.ttsRemoveHilites();
|
|
318
306
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
};
|
|
307
|
+
// group by index; currently only possible to have chunks on one page :/
|
|
308
|
+
this._ttsBoxesByIndex = {
|
|
309
|
+
[pageIndex]: chunk.lineRects.map(([l, b, r, t]) => ({l, r, b, t}))
|
|
310
|
+
};
|
|
323
311
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
const l = chunk.lineRects[i][0];
|
|
331
|
-
const b = chunk.lineRects[i][1];
|
|
332
|
-
const r = chunk.lineRects[i][2];
|
|
333
|
-
const t = chunk.lineRects[i][3];
|
|
334
|
-
|
|
335
|
-
const div = document.createElement('div');
|
|
336
|
-
this.ttsHilites.push(div);
|
|
337
|
-
$(div).prop('className', 'BookReaderSearchHilite').appendTo(
|
|
338
|
-
this.$('.pagediv' + chunk.leafIndex)
|
|
339
|
-
);
|
|
340
|
-
|
|
341
|
-
$(div).css({
|
|
342
|
-
width: (r - l) / this.reduce + 'px',
|
|
343
|
-
height: (b - t) / this.reduce + 'px',
|
|
344
|
-
left: l / this.reduce + 'px',
|
|
345
|
-
top: t / this.reduce + 'px'
|
|
346
|
-
});
|
|
312
|
+
// update any already created pages
|
|
313
|
+
for (const [pageIndexString, boxes] of Object.entries(this._ttsBoxesByIndex)) {
|
|
314
|
+
const pageIndex = parseFloat(pageIndexString);
|
|
315
|
+
const page = this.book.getPage(pageIndex);
|
|
316
|
+
const pageContainers = this.getActivePageContainerElementsForIndex(pageIndex);
|
|
317
|
+
pageContainers.forEach(container => renderBoxesInPageContainerLayer('ttsHiliteLayer', boxes, page, container));
|
|
347
318
|
}
|
|
348
|
-
|
|
349
319
|
};
|
|
350
320
|
|
|
351
321
|
/**
|
|
352
322
|
* @param {PageChunk} chunk
|
|
353
323
|
*/
|
|
354
|
-
BookReader.prototype.
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
}
|
|
324
|
+
BookReader.prototype.ttsScrollToChunk = function(chunk) {
|
|
325
|
+
// It behaves weird if used in thumb mode
|
|
326
|
+
if (this.constModeThumb == this.mode) return;
|
|
327
|
+
|
|
328
|
+
$(`.pagediv${chunk.leafIndex} .ttsHiliteLayer rect`).last()?.[0]?.scrollIntoView({
|
|
329
|
+
// Only vertically center the highlight if we're in 1up or in full screen. In
|
|
330
|
+
// 2up, if we're not fullscreen, the whole body gets scrolled around to try to
|
|
331
|
+
// center the highlight 🙄 See:
|
|
332
|
+
// https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move/11041376
|
|
333
|
+
// Note: nearest doesn't quite work great, because the ReadAloud toolbar is now
|
|
334
|
+
// full-width, and covers up the last line of the highlight.
|
|
335
|
+
block: this.constMode1up == this.mode || this.isFullscreenActive ? 'center' : 'nearest',
|
|
336
|
+
inline: 'center',
|
|
337
|
+
behavior: 'smooth',
|
|
338
|
+
});
|
|
370
339
|
};
|
|
371
340
|
|
|
372
341
|
// ttsRemoveHilites()
|
|
373
342
|
//______________________________________________________________________________
|
|
374
343
|
BookReader.prototype.ttsRemoveHilites = function () {
|
|
375
|
-
$(this.
|
|
376
|
-
this.
|
|
344
|
+
$(this.getActivePageContainerElements()).find('.ttsHiliteLayer').remove();
|
|
345
|
+
this._ttsBoxesByIndex = {};
|
|
377
346
|
};
|
|
378
347
|
|
|
379
348
|
/**
|