@internetarchive/bookreader 5.0.0-9-multiple-files → 5.0.0-90
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 +21 -19
- package/.github/workflows/node.js.yml +81 -7
- package/.github/workflows/npm-publish.yml +6 -20
- package/.testcaferc.js +10 -0
- package/BookReader/BookReader.css +505 -1442
- 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/images/unviewable_page.png +0 -0
- 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/BookReaderJSSimple.js +1 -0
- package/BookReaderDemo/IADemoBr.js +144 -0
- package/BookReaderDemo/demo-advanced.html +2 -2
- 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 +526 -525
- 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 +595 -33
- package/README.md +14 -1
- package/babel.config.js +20 -0
- package/codecov.yml +6 -0
- package/index.html +5 -2
- package/jsconfig.json +19 -0
- package/netlify.toml +9 -0
- package/package.json +70 -62
- 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 +10 -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 +4 -9
- 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 +29 -25
- package/src/BookNavigator/search/search-provider.js +80 -28
- package/src/BookNavigator/search/search-results.js +29 -26
- package/src/BookNavigator/sharing.js +27 -0
- package/src/BookNavigator/viewable-files.js +95 -0
- package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +13 -12
- package/src/BookNavigator/visual-adjustments/visual-adjustments.js +7 -7
- package/src/BookReader/BookModel.js +76 -41
- package/src/BookReader/DragScrollable.js +233 -0
- package/src/BookReader/ImageCache.js +48 -15
- 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 +777 -0
- package/src/BookReader/ModeCoordinateSpace.js +29 -0
- package/src/BookReader/ModeSmoothZoom.js +312 -0
- package/src/BookReader/ModeThumb.js +19 -13
- package/src/BookReader/Navbar/Navbar.js +70 -54
- package/src/BookReader/PageContainer.js +116 -22
- package/src/BookReader/ReduceSet.js +3 -3
- package/src/BookReader/Toolbar/Toolbar.js +14 -41
- package/src/BookReader/events.js +2 -3
- package/src/BookReader/options.js +73 -15
- 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/classes.js +1 -1
- package/src/BookReader/utils.js +128 -13
- package/src/BookReader.js +562 -1078
- package/src/BookReaderPlugin.js +44 -0
- 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/assets/images/unviewable_page.png +0 -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/_BRicon.scss +8 -2
- package/src/css/_BRmain.scss +33 -27
- package/src/css/_BRnav.scss +12 -42
- package/src/css/_BRpages.scss +170 -42
- 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 +24 -7
- package/src/css/_icons.scss +7 -1
- package/src/ia-bookreader/ia-bookreader.js +224 -0
- package/src/plugins/plugin.archive_analytics.js +84 -78
- package/src/plugins/plugin.autoplay.js +99 -104
- package/src/plugins/plugin.chapters.js +237 -191
- package/src/plugins/plugin.iframe.js +1 -1
- package/src/plugins/plugin.iiif.js +141 -0
- package/src/plugins/plugin.resume.js +53 -50
- package/src/plugins/plugin.text_selection.js +503 -175
- package/src/plugins/plugin.vendor-fullscreen.js +7 -7
- package/src/plugins/search/plugin.search.js +183 -121
- package/src/plugins/search/utils.js +43 -0
- package/src/plugins/search/view.js +67 -202
- package/src/plugins/tts/AbstractTTSEngine.js +75 -45
- package/src/plugins/tts/FestivalTTSEngine.js +21 -31
- package/src/plugins/tts/PageChunk.js +16 -23
- package/src/plugins/tts/PageChunkIterator.js +11 -17
- package/src/plugins/tts/WebTTSEngine.js +88 -72
- package/src/plugins/tts/plugin.tts.js +310 -350
- package/src/plugins/tts/utils.js +16 -26
- package/src/plugins/url/UrlPlugin.js +191 -0
- package/src/plugins/{plugin.url.js → url/plugin.url.js} +47 -18
- package/src/util/browserSniffing.js +22 -0
- package/src/util/docCookies.js +21 -2
- package/src/util/strings.js +1 -0
- package/tests/e2e/README.md +37 -0
- package/tests/e2e/autoplay.test.js +9 -6
- package/tests/e2e/base.test.js +8 -16
- package/tests/e2e/helpers/base.js +55 -50
- package/tests/e2e/helpers/debug.js +1 -1
- package/tests/e2e/helpers/mockSearch.js +19 -22
- 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 +42 -29
- package/tests/jest/BookReader/PageContainer.test.js +238 -0
- package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
- package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +3 -3
- 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 +250 -0
- package/tests/jest/BookReader.keyboard.test.js +190 -0
- package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +10 -2
- package/tests/{BookReader.test.js → jest/BookReader.test.js} +43 -53
- package/tests/jest/plugins/plugin.archive_analytics.test.js +20 -0
- package/tests/jest/plugins/plugin.autoplay.test.js +35 -0
- package/tests/jest/plugins/plugin.chapters.test.js +195 -0
- package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +4 -4
- package/tests/{plugins → jest/plugins}/plugin.resume.test.js +22 -35
- package/tests/jest/plugins/plugin.text_selection.test.js +316 -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 +42 -9
- 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 +30 -10
- 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 +57 -18
- 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 +16 -10
- package/.babelrc +0 -12
- package/.dependabot/config.yml +0 -6
- package/.testcaferc.json +0 -5
- package/BookReader/bookreader-component-bundle.js +0 -14330
- 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/BookReaderJSAutoplay.js +0 -56
- package/BookReaderDemo/IIIFBookReader.js +0 -207
- package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
- package/BookReaderDemo/demo-autoplay.html +0 -38
- 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 -108
- package/src/BookNavigator/volumes/volumes.js +0 -162
- 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/PageContainer.test.js +0 -115
- 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 -133
- package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
- package/tests/plugins/plugin.archive_analytics.test.js +0 -23
- package/tests/plugins/plugin.autoplay.test.js +0 -52
- 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
@@ -1,75 +1,29 @@
|
|
1
1
|
class SearchView {
|
2
2
|
/**
|
3
3
|
* @param {object} params
|
4
|
-
*
|
5
|
-
*
|
6
|
-
* @param {object} params.br The BookReader instance
|
4
|
+
* @param {object} params.br The BookReader instance
|
5
|
+
* @param {function} params.cancelSearch callback when a user wants to cancel search
|
7
6
|
*
|
8
7
|
* @event BookReader:SearchResultsCleared - when the search results nav gets cleared
|
9
8
|
* @event BookReader:ToggleSearchMenu - when search results menu should toggle
|
10
9
|
*/
|
11
|
-
constructor(
|
12
|
-
|
13
|
-
console.warn('BookReader::Search - SearchView must be passed a valid CSS selector');
|
14
|
-
return;
|
15
|
-
}
|
16
|
-
|
17
|
-
this.br = params.br;
|
18
|
-
|
19
|
-
// Search results are returned as a text blob with the hits wrapped in
|
20
|
-
// triple mustaches. Hits occasionally include text beyond the search
|
21
|
-
// term, so everything within the staches is captured and wrapped.
|
22
|
-
this.matcher = new RegExp('{{{(.+?)}}}', 'g');
|
10
|
+
constructor({ br, searchCancelledCallback = () => {} }) {
|
11
|
+
this.br = br;
|
23
12
|
this.matches = [];
|
24
|
-
this.cacheDOMElements(
|
13
|
+
this.cacheDOMElements();
|
14
|
+
this.cancelSearch = searchCancelledCallback;
|
15
|
+
}
|
16
|
+
|
17
|
+
init() {
|
25
18
|
this.bindEvents();
|
26
19
|
}
|
27
20
|
|
28
|
-
|
29
|
-
* @param {string} selector A selector for the element that the search tray will be rendered in
|
30
|
-
*/
|
31
|
-
cacheDOMElements(selector) {
|
21
|
+
cacheDOMElements() {
|
32
22
|
this.dom = {};
|
33
|
-
|
34
|
-
// The parent search tray in mobile menu
|
35
|
-
this.dom.searchTray = this.renderSearchTray(selector);
|
36
|
-
// Container for rendered search results
|
37
|
-
this.dom.results = this.dom.searchTray.querySelector('[data-id="results"]');
|
38
|
-
// Element used to display number of results
|
39
|
-
this.dom.resultsCount = this.dom.searchTray.querySelector('[data-id="results_count"]');
|
40
|
-
// Search input within the mobile search tray
|
41
|
-
this.dom.searchField = this.dom.searchTray.querySelector('[name="query"]');
|
42
|
-
// Waiting indicator displayed while waiting for a search request
|
43
|
-
this.dom.searchPending = this.dom.searchTray.querySelector('[data-id="searchPending"]');
|
44
|
-
// The element added to the mobile menu that is animated into view when
|
45
|
-
// the "search" nav item is clicked
|
46
|
-
this.dom.mobileSearch = this.buildMobileDrawer();
|
47
23
|
// Search input within the top toolbar. Will be removed once the mobile menu is replaced.
|
48
24
|
this.dom.toolbarSearch = this.buildToolbarSearch();
|
49
25
|
}
|
50
26
|
|
51
|
-
/**
|
52
|
-
* @param {boolean} bool
|
53
|
-
*/
|
54
|
-
toggleSearchTray(bool = this.dom.searchTray.classList.contains('hidden')) {
|
55
|
-
this.dom.searchTray.classList.toggle('hidden', !bool);
|
56
|
-
}
|
57
|
-
|
58
|
-
/**
|
59
|
-
* @param {boolean} bool
|
60
|
-
*/
|
61
|
-
toggleResultsCount(bool) {
|
62
|
-
this.dom.resultsCount.classList.toggle('visible', bool);
|
63
|
-
}
|
64
|
-
|
65
|
-
/**
|
66
|
-
* @param {SearchInsideResults} results
|
67
|
-
*/
|
68
|
-
updateResultsCount(results) {
|
69
|
-
this.dom.resultsCount.innerText = `(${results} result${results != 1 ? 's' : ''})`;
|
70
|
-
this.toggleResultsCount(true);
|
71
|
-
}
|
72
|
-
|
73
27
|
/**
|
74
28
|
* @param {string} query
|
75
29
|
*/
|
@@ -78,7 +32,6 @@ class SearchView {
|
|
78
32
|
}
|
79
33
|
|
80
34
|
emptyMatches() {
|
81
|
-
this.dom.results.innerHTML = '';
|
82
35
|
this.matches = [];
|
83
36
|
}
|
84
37
|
|
@@ -86,48 +39,20 @@ class SearchView {
|
|
86
39
|
this.br.$('.BRnavpos .BRsearch').remove();
|
87
40
|
}
|
88
41
|
|
89
|
-
clearSearchFieldAndResults() {
|
42
|
+
clearSearchFieldAndResults(dispatchEventWhenComplete = true) {
|
90
43
|
this.br.removeSearchResults();
|
91
|
-
this.toggleResultsCount(false);
|
92
44
|
this.removeResultPins();
|
93
45
|
this.emptyMatches();
|
94
46
|
this.setQuery('');
|
95
47
|
this.teardownSearchNavigation();
|
96
|
-
|
48
|
+
if (dispatchEventWhenComplete) {
|
49
|
+
this.br.trigger('SearchResultsCleared');
|
50
|
+
}
|
97
51
|
}
|
98
52
|
|
99
53
|
toggleSidebar() {
|
100
54
|
this.br.trigger('ToggleSearchMenu');
|
101
55
|
}
|
102
|
-
/**
|
103
|
-
* @param {string} selector The ID attribute to be used for the search tray
|
104
|
-
*/
|
105
|
-
renderSearchTray(selector) {
|
106
|
-
const searchTray = document.createElement('div');
|
107
|
-
searchTray.setAttribute('id', selector.replace(/^#/, ''));
|
108
|
-
searchTray.innerHTML = `
|
109
|
-
<header>
|
110
|
-
<div>
|
111
|
-
<h3>Search inside</h3>
|
112
|
-
<p data-id="results_count"></p>
|
113
|
-
</div>
|
114
|
-
<a href="#" class="close"></a>
|
115
|
-
</header>
|
116
|
-
<form action="" method="get">
|
117
|
-
<fieldset>
|
118
|
-
<input name="all_files" id="all_files" type="checkbox" />
|
119
|
-
<label class="checkbox" for="all_files">Search all files</label>
|
120
|
-
<input type="search" name="query" placeholder="Enter a search term" />
|
121
|
-
</fieldset>
|
122
|
-
</form>
|
123
|
-
<div data-id="searchPending" id="search_pending">
|
124
|
-
<p>Your search results will appear below</p>
|
125
|
-
<div class="loader tc mt20"></div>
|
126
|
-
</div>
|
127
|
-
<ul data-id="results"></ul>
|
128
|
-
`;
|
129
|
-
return searchTray;
|
130
|
-
}
|
131
56
|
|
132
57
|
renderSearchNavigation() {
|
133
58
|
const selector = 'BRsearch-navigation';
|
@@ -215,17 +140,19 @@ class SearchView {
|
|
215
140
|
const start = pool.slice(0, pool.length / 2);
|
216
141
|
const end = pool.slice(pool.length / 2);
|
217
142
|
return closestTo((comparisonFn(start, end, comparator) ? start : end), comparator);
|
218
|
-
}
|
143
|
+
};
|
219
144
|
|
220
145
|
const closestPage = closestTo(matchPages, currentPage);
|
221
146
|
return this.matches.indexOf(this.matches.find((m) => m.par[0].page === closestPage));
|
222
147
|
}
|
223
148
|
|
224
149
|
updateResultsPosition() {
|
150
|
+
if (!this.dom.searchNavigation) return;
|
225
151
|
this.dom.searchNavigation.find('[data-id=resultsCount]').text(this.resultsPosition());
|
226
152
|
}
|
227
153
|
|
228
154
|
updateSearchNavigationButtons() {
|
155
|
+
if (!this.dom.searchNavigation) return;
|
229
156
|
this.dom.searchNavigation.find('.prev').attr('disabled', !this.currentMatchIndex);
|
230
157
|
this.dom.searchNavigation.find('.next').attr('disabled', this.currentMatchIndex + 1 === this.matches.length);
|
231
158
|
}
|
@@ -272,19 +199,6 @@ class SearchView {
|
|
272
199
|
this.updateSearchNavigationButtons();
|
273
200
|
}
|
274
201
|
|
275
|
-
/**
|
276
|
-
* @param {array} matches
|
277
|
-
*/
|
278
|
-
renderMatches(matches) {
|
279
|
-
const items = matches.map((match) => `
|
280
|
-
<li data-page="${match.par[0].page}" data-page-index="${this.br.leafNumToIndex(match.par[0].page)}">
|
281
|
-
<h4>Page ${match.par[0].page}</h4>
|
282
|
-
<p>${match.text.replace(this.matcher, '<mark>$1</mark>')}</p>
|
283
|
-
</li>
|
284
|
-
`);
|
285
|
-
this.dom.results.innerHTML = items.join('');
|
286
|
-
}
|
287
|
-
|
288
202
|
/**
|
289
203
|
* @param {boolean} bool
|
290
204
|
*/
|
@@ -293,23 +207,6 @@ class SearchView {
|
|
293
207
|
this.br.refs.$BRfooter.find('.BRsearch').css({ visibility: pinsVisibleState });
|
294
208
|
}
|
295
209
|
|
296
|
-
buildMobileDrawer() {
|
297
|
-
const mobileSearch = document.createElement('li');
|
298
|
-
mobileSearch.innerHTML = `
|
299
|
-
<span>
|
300
|
-
<span class="DrawerIconWrapper">
|
301
|
-
<img class="DrawerIcon" src="${this.br.imagesBaseURL}icon_search_button.svg" />
|
302
|
-
</span>
|
303
|
-
Search
|
304
|
-
</span>
|
305
|
-
<div data-id="search_slot">
|
306
|
-
</div>
|
307
|
-
`;
|
308
|
-
mobileSearch.querySelector('[data-id="search_slot"]').appendChild(this.dom.searchTray);
|
309
|
-
mobileSearch.classList.add('BRmobileMenu__search');
|
310
|
-
return mobileSearch;
|
311
|
-
}
|
312
|
-
|
313
210
|
buildToolbarSearch() {
|
314
211
|
const toolbarSearch = document.createElement('span');
|
315
212
|
toolbarSearch.classList.add('BRtoolbarSection', 'BRtoolbarSectionSearch');
|
@@ -329,25 +226,20 @@ class SearchView {
|
|
329
226
|
*/
|
330
227
|
renderPins(matches) {
|
331
228
|
matches.forEach((match) => {
|
332
|
-
const
|
333
|
-
const pageIndex = this.br.leafNumToIndex(match.par[0].page);
|
334
|
-
const pageNumber = this.br.getPageNum(pageIndex);
|
229
|
+
const pageIndex = this.br.book.leafNumToIndex(match.par[0].page);
|
335
230
|
const uiStringSearch = "Search result"; // i18n
|
336
|
-
const
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
.replace(this.matcher, '<b>$1</b>')
|
348
|
-
+ '...';
|
231
|
+
const percentThrough = this.br.constructor.util.cssPercentage(pageIndex, this.br.book.getNumLeafs() - 1);
|
232
|
+
|
233
|
+
let html = match.html;
|
234
|
+
if (html.length > 200) {
|
235
|
+
const start = Math.max(0, html.indexOf('<mark>') - 100);
|
236
|
+
if (start != 0) {
|
237
|
+
html = '…' + match.html
|
238
|
+
.substring(start)
|
239
|
+
// Make sure at word boundary though
|
240
|
+
.replace(/^\S+/, '');
|
241
|
+
}
|
349
242
|
}
|
350
|
-
|
351
243
|
// draw marker
|
352
244
|
$('<div>')
|
353
245
|
.addClass('BRsearch')
|
@@ -357,35 +249,27 @@ class SearchView {
|
|
357
249
|
.attr('title', uiStringSearch)
|
358
250
|
.append(`
|
359
251
|
<div class="BRquery">
|
360
|
-
<
|
361
|
-
<
|
252
|
+
<main>${html}</main>
|
253
|
+
<footer>Page ${match.displayPageNumber}</footer>
|
362
254
|
</div>
|
363
255
|
`)
|
364
|
-
.data({ pageIndex })
|
365
256
|
.appendTo(this.br.$('.BRnavline'))
|
366
|
-
.
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
.click(function (event) {
|
383
|
-
// closures are nested and deep, using an arrow function breaks references.
|
384
|
-
// Todo: update to arrow function & clean up closures
|
385
|
-
// to remove `bind` dependency
|
386
|
-
this.br._searchPluginGoToResult(+$(event.target).data('pageIndex'));
|
387
|
-
this.br.updateSearchHilites();
|
388
|
-
}.bind(this));
|
257
|
+
.on("mouseenter", (event) => {
|
258
|
+
// remove from other markers then turn on just for this
|
259
|
+
// XXX should be done when nav slider moves
|
260
|
+
const marker = event.currentTarget;
|
261
|
+
const tooltip = marker.querySelector('.BRquery');
|
262
|
+
const tooltipOffset = tooltip.getBoundingClientRect();
|
263
|
+
const targetOffset = marker.getBoundingClientRect();
|
264
|
+
const boxSizeAdjust = parseInt(getComputedStyle(tooltip).paddingLeft) * 2;
|
265
|
+
if (tooltipOffset.x - boxSizeAdjust < 0) {
|
266
|
+
tooltip.style.setProperty('transform', `translateX(-${targetOffset.left - boxSizeAdjust}px)`);
|
267
|
+
}
|
268
|
+
$('.BRsearch,.BRchapter').removeClass('front');
|
269
|
+
$(event.target).addClass('front');
|
270
|
+
})
|
271
|
+
.on("mouseleave", (event) => $(event.target).removeClass('front'))
|
272
|
+
.on("click", () => { this.br._searchPluginGoToResult(match.matchIndex); });
|
389
273
|
});
|
390
274
|
}
|
391
275
|
|
@@ -393,20 +277,28 @@ class SearchView {
|
|
393
277
|
* @param {boolean} bool
|
394
278
|
*/
|
395
279
|
toggleSearchPending(bool) {
|
396
|
-
this.dom.searchPending.classList.toggle('visible', bool);
|
397
280
|
if (bool) {
|
398
|
-
this.br.showProgressPopup("Search results will appear below...");
|
281
|
+
this.br.showProgressPopup("Search results will appear below...", () => this.progressPopupClosed());
|
399
282
|
}
|
400
283
|
else {
|
401
284
|
this.br.removeProgressPopup();
|
402
285
|
}
|
403
286
|
}
|
404
287
|
|
405
|
-
|
288
|
+
/**
|
289
|
+
* Primary callback when user cancels search popup
|
290
|
+
*/
|
291
|
+
progressPopupClosed() {
|
292
|
+
this.toggleSearchPending();
|
293
|
+
this.cancelSearch();
|
294
|
+
}
|
295
|
+
|
296
|
+
renderErrorModal(textIsProcessing = false) {
|
297
|
+
const errorDetails = `${!textIsProcessing ? 'The text may still be processing. ' : ''}Please try again.`;
|
406
298
|
this.renderModalMessage(`
|
407
299
|
Sorry, there was an error with your search.
|
408
300
|
<br />
|
409
|
-
|
301
|
+
${errorDetails}
|
410
302
|
`);
|
411
303
|
this.delayModalRemovalFor(4000);
|
412
304
|
}
|
@@ -445,14 +337,6 @@ class SearchView {
|
|
445
337
|
setTimeout(this.br.removeProgressPopup.bind(this.br), timeoutMS);
|
446
338
|
}
|
447
339
|
|
448
|
-
openMobileMenu() {
|
449
|
-
this.br.refs.$mmenu.data('mmenu').open();
|
450
|
-
}
|
451
|
-
|
452
|
-
closeMobileMenu() {
|
453
|
-
this.br.refs.$mmenu.data('mmenu').close();
|
454
|
-
}
|
455
|
-
|
456
340
|
/**
|
457
341
|
* @param {Event} e
|
458
342
|
*/
|
@@ -461,7 +345,6 @@ class SearchView {
|
|
461
345
|
const query = e.target.querySelector('[name="query"]').value;
|
462
346
|
if (!query.length) { return false; }
|
463
347
|
this.br.search(query);
|
464
|
-
this.dom.searchField.blur();
|
465
348
|
this.emptyMatches();
|
466
349
|
this.toggleSearchPending(true);
|
467
350
|
return false;
|
@@ -479,9 +362,7 @@ class SearchView {
|
|
479
362
|
this.teardownSearchNavigation();
|
480
363
|
this.renderSearchNavigation();
|
481
364
|
this.bindSearchNavigationEvents();
|
482
|
-
this.renderMatches(results.matches);
|
483
365
|
this.renderPins(results.matches);
|
484
|
-
this.updateResultsCount(results.matches.length);
|
485
366
|
this.toggleSearchPending(false);
|
486
367
|
if (options.goToFirstResult) {
|
487
368
|
$(document).one('BookReader:pageChanged', () => {
|
@@ -492,15 +373,6 @@ class SearchView {
|
|
492
373
|
}
|
493
374
|
}
|
494
375
|
|
495
|
-
/**
|
496
|
-
* @param {Event} e
|
497
|
-
*/
|
498
|
-
handleNavToggledCallback(e) {
|
499
|
-
const is_visible = this.br.navigationIsVisible();
|
500
|
-
this.togglePinsFor(is_visible);
|
501
|
-
this.toggleSearchTray(is_visible ? !!this.dom.results.querySelector('li') : false);
|
502
|
-
}
|
503
|
-
|
504
376
|
handleSearchStarted() {
|
505
377
|
this.emptyMatches();
|
506
378
|
this.br.removeSearchHilites();
|
@@ -510,9 +382,14 @@ class SearchView {
|
|
510
382
|
this.setQuery(this.br.searchTerm);
|
511
383
|
}
|
512
384
|
|
513
|
-
|
385
|
+
/**
|
386
|
+
* Event listener for: `BookReader:SearchCallbackError`
|
387
|
+
* @param {CustomEvent} event
|
388
|
+
*/
|
389
|
+
handleSearchCallbackError(event = {}) {
|
514
390
|
this.toggleSearchPending(false);
|
515
|
-
|
391
|
+
const isIndexed = event?.detail?.props?.results?.indexed;
|
392
|
+
this.renderErrorModal(isIndexed);
|
516
393
|
}
|
517
394
|
|
518
395
|
handleSearchCallbackBookNotIndexed() {
|
@@ -528,26 +405,14 @@ class SearchView {
|
|
528
405
|
bindEvents() {
|
529
406
|
const namespace = 'BookReader:';
|
530
407
|
|
408
|
+
window.addEventListener(`${namespace}SearchCallbackError`, this.handleSearchCallbackError.bind(this));
|
531
409
|
$(document).on(`${namespace}SearchCallback`, this.handleSearchCallback.bind(this))
|
532
|
-
.on(`${namespace}navToggled`, this.handleNavToggledCallback.bind(this))
|
533
410
|
.on(`${namespace}SearchStarted`, this.handleSearchStarted.bind(this))
|
534
|
-
.on(`${namespace}SearchCallbackError`, this.handleSearchCallbackError.bind(this))
|
535
411
|
.on(`${namespace}SearchCallbackBookNotIndexed`, this.handleSearchCallbackBookNotIndexed.bind(this))
|
536
412
|
.on(`${namespace}SearchCallbackEmpty`, this.handleSearchCallbackEmpty.bind(this))
|
537
413
|
.on(`${namespace}pageChanged`, this.updateSearchNavigation.bind(this));
|
538
414
|
|
539
|
-
this.dom.searchTray.addEventListener('submit', this.submitHandler.bind(this));
|
540
415
|
this.dom.toolbarSearch.querySelector('form').addEventListener('submit', this.submitHandler.bind(this));
|
541
|
-
this.dom.searchField.addEventListener('search', () => {
|
542
|
-
if (this.dom.searchField.value) { return; }
|
543
|
-
this.clearSearchFieldAndResults();
|
544
|
-
});
|
545
|
-
|
546
|
-
$(this.dom.results).on('click', 'li', (e) => {
|
547
|
-
this.br._searchPluginGoToResult(+e.currentTarget.dataset.pageIndex);
|
548
|
-
this.br.updateSearchHilites();
|
549
|
-
this.closeMobileMenu();
|
550
|
-
});
|
551
416
|
}
|
552
417
|
}
|
553
418
|
|
@@ -1,12 +1,12 @@
|
|
1
1
|
import PageChunkIterator from './PageChunkIterator.js';
|
2
|
+
import { hasLocalStorage } from './utils.js';
|
2
3
|
/** @typedef {import('./utils.js').ISO6391} ISO6391 */
|
3
4
|
/** @typedef {import('./PageChunk.js')} PageChunk */
|
4
5
|
|
5
6
|
/**
|
6
7
|
* @export
|
7
8
|
* @typedef {Object} TTSEngineOptions
|
8
|
-
* @property {
|
9
|
-
* @property {String} bookPath
|
9
|
+
* @property {import('@/src/util/strings.js').StringWithVars} pageChunkUrl
|
10
10
|
* @property {ISO6391} bookLanguage
|
11
11
|
* @property {Function} onLoadingStart
|
12
12
|
* @property {Function} onLoadingComplete
|
@@ -28,6 +28,7 @@ import PageChunkIterator from './PageChunkIterator.js';
|
|
28
28
|
* @property {() => void} resume
|
29
29
|
* @property {() => void} finish force the sound to 'finish'
|
30
30
|
* @property {number => void} setPlaybackRate
|
31
|
+
* @property {SpeechSynthesisVoice => void} setVoice
|
31
32
|
**/
|
32
33
|
|
33
34
|
/** Handling bookreader's text-to-speech */
|
@@ -39,6 +40,7 @@ export default class AbstractTTSEngine {
|
|
39
40
|
constructor(options) {
|
40
41
|
this.playing = false;
|
41
42
|
this.paused = false;
|
43
|
+
/** @type {TTSEngineOptions} */
|
42
44
|
this.opts = options;
|
43
45
|
/** @type {PageChunkIterator} */
|
44
46
|
this._chunkIterator = null;
|
@@ -50,9 +52,7 @@ export default class AbstractTTSEngine {
|
|
50
52
|
/** @type {SpeechSynthesisVoice} */
|
51
53
|
this.voice = null;
|
52
54
|
// Listen for voice changes (fired by subclasses)
|
53
|
-
this.events.on('voiceschanged',
|
54
|
-
this.voice = AbstractTTSEngine.getBestBookVoice(this.getVoices(), this.opts.bookLanguage);
|
55
|
-
});
|
55
|
+
this.events.on('voiceschanged', this.updateBestVoice);
|
56
56
|
this.events.trigger('voiceschanged');
|
57
57
|
}
|
58
58
|
|
@@ -71,17 +71,21 @@ export default class AbstractTTSEngine {
|
|
71
71
|
/** @abstract */
|
72
72
|
init() { return null; }
|
73
73
|
|
74
|
+
updateBestVoice = () => {
|
75
|
+
this.voice = AbstractTTSEngine.getBestBookVoice(this.getVoices(), this.opts.bookLanguage);
|
76
|
+
}
|
77
|
+
|
74
78
|
/**
|
75
79
|
* @param {number} leafIndex
|
76
80
|
* @param {number} numLeafs total number of leafs in the current book
|
77
81
|
*/
|
78
82
|
start(leafIndex, numLeafs) {
|
79
83
|
this.playing = true;
|
84
|
+
this.paused = false;
|
80
85
|
this.opts.onLoadingStart();
|
81
86
|
|
82
87
|
this._chunkIterator = new PageChunkIterator(numLeafs, leafIndex, {
|
83
|
-
|
84
|
-
bookPath: this.opts.bookPath,
|
88
|
+
pageChunkUrl: this.opts.pageChunkUrl,
|
85
89
|
pageBufferSize: 5,
|
86
90
|
});
|
87
91
|
|
@@ -92,6 +96,7 @@ export default class AbstractTTSEngine {
|
|
92
96
|
stop() {
|
93
97
|
if (this.activeSound) this.activeSound.stop();
|
94
98
|
this.playing = false;
|
99
|
+
this.paused = true;
|
95
100
|
this._chunkIterator = null;
|
96
101
|
this.activeSound = null;
|
97
102
|
this.events.trigger('stop');
|
@@ -124,13 +129,26 @@ export default class AbstractTTSEngine {
|
|
124
129
|
}
|
125
130
|
|
126
131
|
/** @public */
|
127
|
-
jumpBackward() {
|
128
|
-
Promise.all([
|
132
|
+
async jumpBackward() {
|
133
|
+
await Promise.all([
|
129
134
|
this.activeSound.stop(),
|
130
135
|
this._chunkIterator.decrement()
|
131
|
-
.then(() => this._chunkIterator.decrement())
|
132
|
-
])
|
133
|
-
|
136
|
+
.then(() => this._chunkIterator.decrement()),
|
137
|
+
]);
|
138
|
+
this.step();
|
139
|
+
}
|
140
|
+
|
141
|
+
/** @param {string} voiceURI */
|
142
|
+
setVoice(voiceURI) {
|
143
|
+
// if the user actively selects a voice, don't re-choose best voice anymore
|
144
|
+
// MS Edge fires voices changed randomly very often
|
145
|
+
this.events.off('voiceschanged', this.updateBestVoice);
|
146
|
+
this.voice = this.getVoices().find(voice => voice.voiceURI === voiceURI);
|
147
|
+
// if the current book has a language set, store the selected voice with the book language as a suffix
|
148
|
+
if (this.opts.bookLanguage && hasLocalStorage()) {
|
149
|
+
localStorage.setItem(`BRtts-voice-${this.opts.bookLanguage}`, this.voice.voiceURI);
|
150
|
+
}
|
151
|
+
if (this.activeSound) this.activeSound.setVoice(this.voice);
|
134
152
|
}
|
135
153
|
|
136
154
|
/** @param {number} newRate */
|
@@ -140,36 +158,33 @@ export default class AbstractTTSEngine {
|
|
140
158
|
}
|
141
159
|
|
142
160
|
/** @private */
|
143
|
-
step() {
|
144
|
-
this._chunkIterator.next()
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
.then(() => {
|
171
|
-
if (this.playing) return this.step();
|
172
|
-
});
|
161
|
+
async step() {
|
162
|
+
const chunk = await this._chunkIterator.next();
|
163
|
+
if (chunk == PageChunkIterator.AT_END) {
|
164
|
+
this.stop();
|
165
|
+
this.opts.onDone();
|
166
|
+
return;
|
167
|
+
}
|
168
|
+
this.opts.onLoadingStart();
|
169
|
+
const sound = this.createSound(chunk);
|
170
|
+
sound.chunk = chunk;
|
171
|
+
sound.rate = this.playbackRate;
|
172
|
+
sound.voice = this.voice;
|
173
|
+
sound.load(() => this.opts.onLoadingComplete());
|
174
|
+
|
175
|
+
this.opts.onLoadingComplete();
|
176
|
+
|
177
|
+
await this.opts.beforeChunkPlay(chunk);
|
178
|
+
|
179
|
+
if (!this.playing) return;
|
180
|
+
|
181
|
+
const playPromise = await this.playSound(sound)
|
182
|
+
.then(()=> this.opts.afterChunkPlay(sound.chunk));
|
183
|
+
|
184
|
+
if (this.paused) this.pause();
|
185
|
+
await playPromise;
|
186
|
+
|
187
|
+
if (this.playing) return this.step();
|
173
188
|
}
|
174
189
|
|
175
190
|
/**
|
@@ -212,10 +227,12 @@ export default class AbstractTTSEngine {
|
|
212
227
|
// user languages that match the book language
|
213
228
|
const matchingUserLangs = userLanguages.filter(lang => lang.startsWith(bookLanguage));
|
214
229
|
|
215
|
-
//
|
216
|
-
return AbstractTTSEngine.
|
230
|
+
// First try to find the last chosen voice from localStorage for the current book language
|
231
|
+
return AbstractTTSEngine.getMatchingStoredVoice(bookLangVoices, bookLanguage)
|
232
|
+
// Try to find voices that intersect these two sets
|
233
|
+
|| AbstractTTSEngine.getMatchingVoice(matchingUserLangs, bookLangVoices)
|
217
234
|
// no user languages match the books; let's return the best voice for the book language
|
218
|
-
(bookLangVoices.find(v => v.default) || bookLangVoices[0])
|
235
|
+
|| (bookLangVoices.find(v => v.default) || bookLangVoices[0])
|
219
236
|
// No voices match the book language? let's find a voice in the user's language
|
220
237
|
// and ignore book lang
|
221
238
|
|| AbstractTTSEngine.getMatchingVoice(userLanguages, voices)
|
@@ -223,6 +240,19 @@ export default class AbstractTTSEngine {
|
|
223
240
|
|| (voices.find(v => v.default) || voices[0]);
|
224
241
|
}
|
225
242
|
|
243
|
+
/**
|
244
|
+
* @private
|
245
|
+
* Get the voice last selected by the user for the book language from localStorage.
|
246
|
+
* Returns undefined if no voice is stored or found.
|
247
|
+
* @param {SpeechSynthesisVoice[]} voices browser voices to choose from
|
248
|
+
* @param {ISO6391} bookLanguage book language to look for
|
249
|
+
* @return {SpeechSynthesisVoice | undefined}
|
250
|
+
*/
|
251
|
+
static getMatchingStoredVoice(voices, bookLanguage) {
|
252
|
+
const storedVoice = hasLocalStorage() && localStorage.getItem(`BRtts-voice-${bookLanguage}`);
|
253
|
+
return (storedVoice ? voices.find(v => v.voiceURI === storedVoice) : undefined);
|
254
|
+
}
|
255
|
+
|
226
256
|
/**
|
227
257
|
* @private
|
228
258
|
* Get the best voice that matches one of the BCP47 languages (order by preference)
|