@internetarchive/bookreader 5.0.0-5 → 5.0.0-50-a1
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 +77 -6
- package/.github/workflows/npm-publish.yml +6 -20
- package/.testcaferc.js +10 -0
- package/BookReader/BookReader.css +131 -339
- package/BookReader/BookReader.js +1 -1
- package/BookReader/BookReader.js.LICENSE.txt +24 -0
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +1493 -0
- package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +17 -0
- package/BookReader/ia-bookreader-bundle.js.map +1 -0
- package/BookReader/icons/close-circle-dark.svg +1 -0
- package/BookReader/icons/magnify-minus.svg +1 -1
- package/BookReader/icons/magnify-plus.svg +1 -1
- package/BookReader/icons/pause.svg +1 -1
- package/BookReader/icons/playback-speed.svg +1 -1
- package/BookReader/icons/read-aloud.svg +1 -1
- package/BookReader/icons/voice.svg +1 -0
- package/BookReader/images/BRicons.svg +2 -2
- package/BookReader/images/books_graphic.svg +1 -1
- package/BookReader/images/icon_book.svg +1 -1
- package/BookReader/images/icon_gear.svg +1 -1
- package/BookReader/images/icon_info.svg +1 -1
- package/BookReader/images/icon_playback-rate.svg +1 -1
- package/BookReader/images/icon_search_button.svg +1 -1
- package/BookReader/images/icon_share.svg +1 -1
- package/BookReader/images/icon_speaker.svg +1 -1
- package/BookReader/images/icon_speaker_open.svg +1 -1
- package/BookReader/images/marker_chap-off.svg +1 -1
- package/BookReader/images/marker_chap-on.svg +1 -1
- package/BookReader/images/marker_srch-on.svg +1 -1
- package/BookReader/jquery-3.js +2 -0
- package/BookReader/jquery-3.js.LICENSE.txt +24 -0
- package/BookReader/plugins/plugin.archive_analytics.js +1 -1
- package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
- package/BookReader/plugins/plugin.autoplay.js +1 -1
- package/BookReader/plugins/plugin.autoplay.js.map +1 -1
- package/BookReader/plugins/plugin.chapters.js +1 -1
- package/BookReader/plugins/plugin.chapters.js.map +1 -1
- package/BookReader/plugins/plugin.iframe.js +1 -1
- package/BookReader/plugins/plugin.iframe.js.map +1 -1
- package/BookReader/plugins/plugin.mobile_nav.js +1 -1
- package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
- package/BookReader/plugins/plugin.resume.js +1 -1
- package/BookReader/plugins/plugin.resume.js.map +1 -1
- package/BookReader/plugins/plugin.search.js +1 -1
- package/BookReader/plugins/plugin.search.js.map +1 -1
- package/BookReader/plugins/plugin.text_selection.js +1 -1
- package/BookReader/plugins/plugin.text_selection.js.map +1 -1
- package/BookReader/plugins/plugin.tts.js +1 -1
- package/BookReader/plugins/plugin.tts.js.map +1 -1
- package/BookReader/plugins/plugin.url.js +1 -1
- package/BookReader/plugins/plugin.url.js.map +1 -1
- package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
- 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 +14 -1
- package/BookReaderDemo/IADemoBr.js +148 -0
- package/BookReaderDemo/demo-advanced.html +2 -2
- package/BookReaderDemo/demo-autoplay.html +2 -1
- package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
- package/BookReaderDemo/demo-fullscreen-mobile.html +2 -1
- package/BookReaderDemo/demo-fullscreen.html +2 -1
- package/BookReaderDemo/demo-iiif.html +2 -1
- package/BookReaderDemo/demo-internetarchive.html +84 -17
- 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 -1
- package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
- package/BookReaderDemo/immersion-1up.html +2 -1
- package/BookReaderDemo/immersion-mode.html +2 -1
- package/BookReaderDemo/toggle_controls.html +2 -1
- package/BookReaderDemo/view_mode.html +2 -1
- package/BookReaderDemo/viewmode-cycle.html +2 -3
- package/CHANGELOG.md +202 -0
- package/README.md +14 -1
- package/babel.config.js +18 -0
- package/codecov.yml +6 -0
- package/index.html +3 -0
- package/jsconfig.json +19 -0
- package/package.json +66 -56
- package/renovate.json +52 -0
- package/scripts/preversion.js +4 -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/assets/icon_sort_asc.js +5 -0
- package/src/BookNavigator/assets/icon_sort_desc.js +5 -0
- package/src/BookNavigator/assets/icon_sort_neutral.js +5 -0
- package/src/BookNavigator/assets/icon_volumes.js +11 -0
- package/src/BookNavigator/book-navigator.js +583 -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 +21 -8
- package/src/BookNavigator/bookmarks/ia-bookmarks.js +102 -66
- 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/a-search-result.js +18 -13
- package/src/BookNavigator/search/search-provider.js +80 -28
- package/src/BookNavigator/search/search-results.js +10 -18
- package/src/BookNavigator/sharing.js +27 -0
- package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -10
- package/src/BookNavigator/visual-adjustments/visual-adjustments.js +3 -3
- package/src/BookNavigator/volumes/volumes-provider.js +114 -0
- package/src/BookNavigator/volumes/volumes.js +188 -0
- package/src/BookReader/BookModel.js +0 -29
- package/src/BookReader/DebugConsole.js +3 -3
- package/src/BookReader/DragScrollable.js +233 -0
- package/src/BookReader/Mode1Up.js +51 -351
- package/src/BookReader/Mode1UpLit.js +441 -0
- package/src/BookReader/Mode2Up.js +120 -105
- package/src/BookReader/ModeSmoothZoom.js +179 -0
- package/src/BookReader/ModeThumb.js +17 -11
- package/src/BookReader/Navbar/Navbar.js +10 -36
- package/src/BookReader/PageContainer.js +69 -6
- package/src/BookReader/ReduceSet.js +1 -1
- package/src/BookReader/Toolbar/Toolbar.js +10 -37
- package/src/BookReader/options.js +10 -0
- package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
- package/src/BookReader/utils/ScrollClassAdder.js +31 -0
- package/src/BookReader/utils.js +92 -13
- package/src/BookReader.js +431 -620
- 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 +0 -12
- package/src/css/_BRComponent.scss +1 -1
- package/src/css/_BRmain.scss +19 -24
- package/src/css/_BRnav.scss +4 -26
- package/src/css/_BRpages.scss +35 -0
- package/src/css/_BRsearch.scss +25 -216
- package/src/css/_TextSelection.scss +14 -17
- package/src/css/_colorbox.scss +2 -2
- package/src/css/_controls.scss +17 -5
- package/src/css/_icons.scss +6 -0
- package/src/ia-bookreader/ia-bookreader.js +224 -0
- package/src/plugins/plugin.autoplay.js +4 -4
- package/src/plugins/plugin.chapters.js +28 -35
- package/src/plugins/plugin.mobile_nav.js +11 -10
- package/src/plugins/plugin.resume.js +3 -3
- package/src/plugins/plugin.text_selection.js +26 -39
- package/src/plugins/plugin.vendor-fullscreen.js +4 -4
- package/src/plugins/search/plugin.search.js +174 -116
- package/src/plugins/search/view.js +63 -179
- package/src/plugins/tts/AbstractTTSEngine.js +46 -37
- 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 +66 -69
- package/src/plugins/tts/plugin.tts.js +92 -109
- package/src/plugins/tts/utils.js +0 -9
- package/src/plugins/url/UrlPlugin.js +184 -0
- package/src/plugins/{plugin.url.js → url/plugin.url.js} +28 -6
- package/src/util/manifestGenerator.js +0 -0
- package/tests/e2e/README.md +37 -0
- package/tests/e2e/autoplay.test.js +2 -2
- package/tests/e2e/base.test.js +7 -7
- package/tests/e2e/helpers/base.js +9 -3
- package/tests/e2e/helpers/debug.js +1 -1
- package/tests/e2e/helpers/desktopSearch.js +14 -13
- package/tests/e2e/helpers/mobileSearch.js +3 -3
- package/tests/e2e/helpers/params.js +17 -0
- package/tests/e2e/models/Navigation.js +13 -4
- package/tests/e2e/rightToLeft.test.js +4 -5
- package/tests/e2e/viewmode.test.js +38 -33
- package/tests/jest/BookNavigator/book-navigator.test.js +634 -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 +102 -58
- package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
- package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
- package/tests/jest/BookNavigator/volumes/volumes-provider.test.js +184 -0
- package/tests/jest/BookNavigator/volumes/volumes.test.js +97 -0
- package/tests/{BookReader → jest/BookReader}/BookModel.test.js +34 -14
- package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +176 -0
- package/tests/{BookReader → jest/BookReader}/DebugConsole.test.js +1 -1
- package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
- package/tests/jest/BookReader/Mode1UpLit.test.js +92 -0
- package/tests/{BookReader → jest/BookReader}/Mode2Up.test.js +36 -15
- package/tests/jest/BookReader/ModeSmoothZoom.test.js +149 -0
- package/tests/jest/BookReader/ModeThumb.test.js +71 -0
- package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +7 -7
- 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/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
- package/tests/jest/BookReader/utils.test.js +186 -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} +18 -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/{plugins → jest/plugins}/plugin.chapters.test.js +10 -11
- package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.mobile_nav.test.js +5 -5
- package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
- package/tests/{plugins → jest/plugins}/plugin.text_selection.test.js +39 -47
- package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
- package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +63 -47
- package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +35 -6
- package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +9 -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 +1 -1
- package/tests/{plugins → jest/plugins}/tts/utils.test.js +3 -28
- package/tests/jest/plugins/url/UrlPlugin.test.js +190 -0
- package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +33 -14
- package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
- package/tests/{util → jest/util}/docCookies.test.js +1 -1
- package/tests/{util → jest/util}/strings.test.js +1 -1
- package/tests/{utils.js → jest/utils.js} +38 -0
- package/webpack.config.js +11 -5
- package/.babelrc +0 -12
- package/.dependabot/config.yml +0 -6
- package/.testcaferc.json +0 -5
- package/BookReader/bookreader-component-bundle.js +0 -1450
- package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
- package/BookReader/bookreader-component-bundle.js.map +0 -1
- package/BookReader/jquery-1.10.1.js +0 -2
- package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
- package/BookReader/plugins/plugin.menu_toggle.js +0 -2
- package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
- package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
- 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 -438
- package/src/BookNavigator/assets/book-loader.js +0 -27
- package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
- package/src/BookReaderComponent/BookReaderComponent.js +0 -112
- package/src/ItemNavigator/ItemNavigator.js +0 -372
- package/src/ItemNavigator/providers/sharing.js +0 -29
- package/src/Layers/sharing/sharing-provider.js +0 -22
- package/src/dragscrollable-br.js +0 -261
- package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
- package/src/plugins/plugin.bookmarks.js +0 -50
- package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
- package/tests/BookReader/Mode1Up.test.js +0 -164
- package/tests/BookReader/utils.test.js +0 -109
- 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/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
@@ -1,75 +1,33 @@
|
|
1
|
+
import { escapeHTML } from "../../BookReader/utils.js";
|
2
|
+
|
1
3
|
class SearchView {
|
2
4
|
/**
|
3
5
|
* @param {object} params
|
4
|
-
*
|
5
|
-
*
|
6
|
-
* @param {object} params.br The BookReader instance
|
6
|
+
* @param {object} params.br The BookReader instance
|
7
|
+
* @param {function} params.cancelSearch callback when a user wants to cancel search
|
7
8
|
*
|
8
9
|
* @event BookReader:SearchResultsCleared - when the search results nav gets cleared
|
9
10
|
* @event BookReader:ToggleSearchMenu - when search results menu should toggle
|
10
11
|
*/
|
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;
|
12
|
+
constructor({ br, searchCancelledCallback = () => {} }) {
|
13
|
+
this.br = br;
|
18
14
|
|
19
15
|
// Search results are returned as a text blob with the hits wrapped in
|
20
16
|
// triple mustaches. Hits occasionally include text beyond the search
|
21
17
|
// term, so everything within the staches is captured and wrapped.
|
22
|
-
this.matcher = new RegExp('{{{(.+?)}}}', '
|
18
|
+
this.matcher = new RegExp('{{{(.+?)}}}', 'gs');
|
23
19
|
this.matches = [];
|
24
|
-
this.cacheDOMElements(
|
20
|
+
this.cacheDOMElements();
|
25
21
|
this.bindEvents();
|
22
|
+
this.cancelSearch = searchCancelledCallback;
|
26
23
|
}
|
27
24
|
|
28
|
-
|
29
|
-
* @param {string} selector A selector for the element that the search tray will be rendered in
|
30
|
-
*/
|
31
|
-
cacheDOMElements(selector) {
|
25
|
+
cacheDOMElements() {
|
32
26
|
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
27
|
// Search input within the top toolbar. Will be removed once the mobile menu is replaced.
|
48
28
|
this.dom.toolbarSearch = this.buildToolbarSearch();
|
49
29
|
}
|
50
30
|
|
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
31
|
/**
|
74
32
|
* @param {string} query
|
75
33
|
*/
|
@@ -78,7 +36,6 @@ class SearchView {
|
|
78
36
|
}
|
79
37
|
|
80
38
|
emptyMatches() {
|
81
|
-
this.dom.results.innerHTML = '';
|
82
39
|
this.matches = [];
|
83
40
|
}
|
84
41
|
|
@@ -86,48 +43,20 @@ class SearchView {
|
|
86
43
|
this.br.$('.BRnavpos .BRsearch').remove();
|
87
44
|
}
|
88
45
|
|
89
|
-
clearSearchFieldAndResults() {
|
46
|
+
clearSearchFieldAndResults(dispatchEventWhenComplete = true) {
|
90
47
|
this.br.removeSearchResults();
|
91
|
-
this.toggleResultsCount(false);
|
92
48
|
this.removeResultPins();
|
93
49
|
this.emptyMatches();
|
94
50
|
this.setQuery('');
|
95
51
|
this.teardownSearchNavigation();
|
96
|
-
|
52
|
+
if (dispatchEventWhenComplete) {
|
53
|
+
this.br.trigger('SearchResultsCleared');
|
54
|
+
}
|
97
55
|
}
|
98
56
|
|
99
57
|
toggleSidebar() {
|
100
58
|
this.br.trigger('ToggleSearchMenu');
|
101
59
|
}
|
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
60
|
|
132
61
|
renderSearchNavigation() {
|
133
62
|
const selector = 'BRsearch-navigation';
|
@@ -215,17 +144,19 @@ class SearchView {
|
|
215
144
|
const start = pool.slice(0, pool.length / 2);
|
216
145
|
const end = pool.slice(pool.length / 2);
|
217
146
|
return closestTo((comparisonFn(start, end, comparator) ? start : end), comparator);
|
218
|
-
}
|
147
|
+
};
|
219
148
|
|
220
149
|
const closestPage = closestTo(matchPages, currentPage);
|
221
150
|
return this.matches.indexOf(this.matches.find((m) => m.par[0].page === closestPage));
|
222
151
|
}
|
223
152
|
|
224
153
|
updateResultsPosition() {
|
154
|
+
if (!this.dom.searchNavigation) return;
|
225
155
|
this.dom.searchNavigation.find('[data-id=resultsCount]').text(this.resultsPosition());
|
226
156
|
}
|
227
157
|
|
228
158
|
updateSearchNavigationButtons() {
|
159
|
+
if (!this.dom.searchNavigation) return;
|
229
160
|
this.dom.searchNavigation.find('.prev').attr('disabled', !this.currentMatchIndex);
|
230
161
|
this.dom.searchNavigation.find('.next').attr('disabled', this.currentMatchIndex + 1 === this.matches.length);
|
231
162
|
}
|
@@ -272,19 +203,6 @@ class SearchView {
|
|
272
203
|
this.updateSearchNavigationButtons();
|
273
204
|
}
|
274
205
|
|
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
206
|
/**
|
289
207
|
* @param {boolean} bool
|
290
208
|
*/
|
@@ -293,23 +211,6 @@ class SearchView {
|
|
293
211
|
this.br.refs.$BRfooter.find('.BRsearch').css({ visibility: pinsVisibleState });
|
294
212
|
}
|
295
213
|
|
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
214
|
buildToolbarSearch() {
|
314
215
|
const toolbarSearch = document.createElement('span');
|
315
216
|
toolbarSearch.classList.add('BRtoolbarSection', 'BRtoolbarSectionSearch');
|
@@ -330,22 +231,23 @@ class SearchView {
|
|
330
231
|
renderPins(matches) {
|
331
232
|
matches.forEach((match) => {
|
332
233
|
const queryString = match.text;
|
333
|
-
const pageIndex = this.br.leafNumToIndex(match.par[0].page);
|
334
|
-
const pageNumber = this.br.getPageNum(pageIndex);
|
234
|
+
const pageIndex = this.br.book.leafNumToIndex(match.par[0].page);
|
335
235
|
const uiStringSearch = "Search result"; // i18n
|
336
|
-
const uiStringPage = "Page"; // i18n
|
337
236
|
|
338
|
-
const percentThrough = this.br.constructor.util.cssPercentage(pageIndex, this.br.getNumLeafs() - 1);
|
237
|
+
const percentThrough = this.br.constructor.util.cssPercentage(pageIndex, this.br.book.getNumLeafs() - 1);
|
339
238
|
|
340
|
-
const
|
239
|
+
const escapedQueryString = escapeHTML(queryString);
|
240
|
+
const queryStringWithB = escapedQueryString.replace(this.matcher, '<b>$1</b>');
|
341
241
|
|
342
242
|
let queryStringWithBTruncated = '';
|
343
243
|
|
344
244
|
if (queryString.length > 100) {
|
345
|
-
queryStringWithBTruncated = queryString
|
346
|
-
|
245
|
+
queryStringWithBTruncated = queryString.replace(/^(.{100}[^\s]*).*/, "$1");
|
246
|
+
|
247
|
+
// If truncating, we must escape *after* truncation occurs (but before wrapping in <b>)
|
248
|
+
queryStringWithBTruncated = escapeHTML(queryStringWithBTruncated)
|
347
249
|
.replace(this.matcher, '<b>$1</b>')
|
348
|
-
|
250
|
+
+ '...';
|
349
251
|
}
|
350
252
|
|
351
253
|
// draw marker
|
@@ -358,34 +260,26 @@ class SearchView {
|
|
358
260
|
.append(`
|
359
261
|
<div class="BRquery">
|
360
262
|
<div>${queryStringWithBTruncated || queryStringWithB}</div>
|
361
|
-
<div
|
263
|
+
<div>Page ${match.displayPageNumber}</div>
|
362
264
|
</div>
|
363
265
|
`)
|
364
|
-
.data({ pageIndex })
|
365
266
|
.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));
|
267
|
+
.on("mouseenter", (event) => {
|
268
|
+
// remove from other markers then turn on just for this
|
269
|
+
// XXX should be done when nav slider moves
|
270
|
+
const marker = event.currentTarget;
|
271
|
+
const tooltip = marker.querySelector('.BRquery');
|
272
|
+
const tooltipOffset = tooltip.getBoundingClientRect();
|
273
|
+
const targetOffset = marker.getBoundingClientRect();
|
274
|
+
const boxSizeAdjust = parseInt(getComputedStyle(tooltip).paddingLeft) * 2;
|
275
|
+
if (tooltipOffset.x - boxSizeAdjust < 0) {
|
276
|
+
tooltip.style.setProperty('transform', `translateX(-${targetOffset.left - boxSizeAdjust}px)`);
|
277
|
+
}
|
278
|
+
$('.BRsearch,.BRchapter').removeClass('front');
|
279
|
+
$(event.target).addClass('front');
|
280
|
+
})
|
281
|
+
.on("mouseleave", (event) => $(event.target).removeClass('front'))
|
282
|
+
.on("click", () => { this.br._searchPluginGoToResult(match.matchIndex); });
|
389
283
|
});
|
390
284
|
}
|
391
285
|
|
@@ -393,20 +287,28 @@ class SearchView {
|
|
393
287
|
* @param {boolean} bool
|
394
288
|
*/
|
395
289
|
toggleSearchPending(bool) {
|
396
|
-
this.dom.searchPending.classList.toggle('visible', bool);
|
397
290
|
if (bool) {
|
398
|
-
this.br.showProgressPopup("Search results will appear below...");
|
291
|
+
this.br.showProgressPopup("Search results will appear below...", () => this.progressPopupClosed());
|
399
292
|
}
|
400
293
|
else {
|
401
294
|
this.br.removeProgressPopup();
|
402
295
|
}
|
403
296
|
}
|
404
297
|
|
405
|
-
|
298
|
+
/**
|
299
|
+
* Primary callback when user cancels search popup
|
300
|
+
*/
|
301
|
+
progressPopupClosed() {
|
302
|
+
this.toggleSearchPending();
|
303
|
+
this.cancelSearch();
|
304
|
+
}
|
305
|
+
|
306
|
+
renderErrorModal(textIsProcessing = false) {
|
307
|
+
const errorDetails = `${!textIsProcessing ? 'The text may still be processing. ' : ''}Please try again.`;
|
406
308
|
this.renderModalMessage(`
|
407
309
|
Sorry, there was an error with your search.
|
408
310
|
<br />
|
409
|
-
|
311
|
+
${errorDetails}
|
410
312
|
`);
|
411
313
|
this.delayModalRemovalFor(4000);
|
412
314
|
}
|
@@ -445,14 +347,6 @@ class SearchView {
|
|
445
347
|
setTimeout(this.br.removeProgressPopup.bind(this.br), timeoutMS);
|
446
348
|
}
|
447
349
|
|
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
350
|
/**
|
457
351
|
* @param {Event} e
|
458
352
|
*/
|
@@ -461,7 +355,6 @@ class SearchView {
|
|
461
355
|
const query = e.target.querySelector('[name="query"]').value;
|
462
356
|
if (!query.length) { return false; }
|
463
357
|
this.br.search(query);
|
464
|
-
this.dom.searchField.blur();
|
465
358
|
this.emptyMatches();
|
466
359
|
this.toggleSearchPending(true);
|
467
360
|
return false;
|
@@ -479,9 +372,7 @@ class SearchView {
|
|
479
372
|
this.teardownSearchNavigation();
|
480
373
|
this.renderSearchNavigation();
|
481
374
|
this.bindSearchNavigationEvents();
|
482
|
-
this.renderMatches(results.matches);
|
483
375
|
this.renderPins(results.matches);
|
484
|
-
this.updateResultsCount(results.matches.length);
|
485
376
|
this.toggleSearchPending(false);
|
486
377
|
if (options.goToFirstResult) {
|
487
378
|
$(document).one('BookReader:pageChanged', () => {
|
@@ -498,7 +389,6 @@ class SearchView {
|
|
498
389
|
handleNavToggledCallback(e) {
|
499
390
|
const is_visible = this.br.navigationIsVisible();
|
500
391
|
this.togglePinsFor(is_visible);
|
501
|
-
this.toggleSearchTray(is_visible ? !!this.dom.results.querySelector('li') : false);
|
502
392
|
}
|
503
393
|
|
504
394
|
handleSearchStarted() {
|
@@ -510,9 +400,14 @@ class SearchView {
|
|
510
400
|
this.setQuery(this.br.searchTerm);
|
511
401
|
}
|
512
402
|
|
513
|
-
|
403
|
+
/**
|
404
|
+
* Event listener for: `BookReader:SearchCallbackError`
|
405
|
+
* @param {CustomEvent} event
|
406
|
+
*/
|
407
|
+
handleSearchCallbackError(event = {}) {
|
514
408
|
this.toggleSearchPending(false);
|
515
|
-
|
409
|
+
const isIndexed = event?.detail?.props?.results?.indexed;
|
410
|
+
this.renderErrorModal(isIndexed);
|
516
411
|
}
|
517
412
|
|
518
413
|
handleSearchCallbackBookNotIndexed() {
|
@@ -528,26 +423,15 @@ class SearchView {
|
|
528
423
|
bindEvents() {
|
529
424
|
const namespace = 'BookReader:';
|
530
425
|
|
426
|
+
window.addEventListener(`${namespace}SearchCallbackError`, this.handleSearchCallbackError.bind(this));
|
531
427
|
$(document).on(`${namespace}SearchCallback`, this.handleSearchCallback.bind(this))
|
532
428
|
.on(`${namespace}navToggled`, this.handleNavToggledCallback.bind(this))
|
533
429
|
.on(`${namespace}SearchStarted`, this.handleSearchStarted.bind(this))
|
534
|
-
.on(`${namespace}SearchCallbackError`, this.handleSearchCallbackError.bind(this))
|
535
430
|
.on(`${namespace}SearchCallbackBookNotIndexed`, this.handleSearchCallbackBookNotIndexed.bind(this))
|
536
431
|
.on(`${namespace}SearchCallbackEmpty`, this.handleSearchCallbackEmpty.bind(this))
|
537
432
|
.on(`${namespace}pageChanged`, this.updateSearchNavigation.bind(this));
|
538
433
|
|
539
|
-
this.dom.searchTray.addEventListener('submit', this.submitHandler.bind(this));
|
540
434
|
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
435
|
}
|
552
436
|
}
|
553
437
|
|
@@ -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 */
|
@@ -50,9 +51,7 @@ export default class AbstractTTSEngine {
|
|
50
51
|
/** @type {SpeechSynthesisVoice} */
|
51
52
|
this.voice = null;
|
52
53
|
// Listen for voice changes (fired by subclasses)
|
53
|
-
this.events.on('voiceschanged',
|
54
|
-
this.voice = AbstractTTSEngine.getBestBookVoice(this.getVoices(), this.opts.bookLanguage);
|
55
|
-
});
|
54
|
+
this.events.on('voiceschanged', this.updateBestVoice);
|
56
55
|
this.events.trigger('voiceschanged');
|
57
56
|
}
|
58
57
|
|
@@ -71,6 +70,10 @@ export default class AbstractTTSEngine {
|
|
71
70
|
/** @abstract */
|
72
71
|
init() { return null; }
|
73
72
|
|
73
|
+
updateBestVoice = () => {
|
74
|
+
this.voice = AbstractTTSEngine.getBestBookVoice(this.getVoices(), this.opts.bookLanguage);
|
75
|
+
}
|
76
|
+
|
74
77
|
/**
|
75
78
|
* @param {number} leafIndex
|
76
79
|
* @param {number} numLeafs total number of leafs in the current book
|
@@ -124,13 +127,22 @@ export default class AbstractTTSEngine {
|
|
124
127
|
}
|
125
128
|
|
126
129
|
/** @public */
|
127
|
-
jumpBackward() {
|
128
|
-
Promise.all([
|
130
|
+
async jumpBackward() {
|
131
|
+
await Promise.all([
|
129
132
|
this.activeSound.stop(),
|
130
133
|
this._chunkIterator.decrement()
|
131
134
|
.then(() => this._chunkIterator.decrement())
|
132
|
-
])
|
133
|
-
|
135
|
+
]);
|
136
|
+
this.step();
|
137
|
+
}
|
138
|
+
|
139
|
+
/** @param {string} voiceURI */
|
140
|
+
setVoice(voiceURI) {
|
141
|
+
// if the user actively selects a voice, don't re-choose best voice anymore
|
142
|
+
// MS Edge fires voices changed randomly very often
|
143
|
+
this.events.off('voiceschanged', this.updateBestVoice);
|
144
|
+
this.voice = this.getVoices().find(voice => voice.voiceURI === voiceURI);
|
145
|
+
if (this.activeSound) this.activeSound.setVoice(this.voice);
|
134
146
|
}
|
135
147
|
|
136
148
|
/** @param {number} newRate */
|
@@ -140,36 +152,33 @@ export default class AbstractTTSEngine {
|
|
140
152
|
}
|
141
153
|
|
142
154
|
/** @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
|
-
});
|
155
|
+
async step() {
|
156
|
+
const chunk = await this._chunkIterator.next();
|
157
|
+
if (chunk == PageChunkIterator.AT_END) {
|
158
|
+
this.stop();
|
159
|
+
this.opts.onDone();
|
160
|
+
return;
|
161
|
+
}
|
162
|
+
this.opts.onLoadingStart();
|
163
|
+
const sound = this.createSound(chunk);
|
164
|
+
sound.chunk = chunk;
|
165
|
+
sound.rate = this.playbackRate;
|
166
|
+
sound.voice = this.voice;
|
167
|
+
sound.load(() => this.opts.onLoadingComplete());
|
168
|
+
|
169
|
+
this.opts.onLoadingComplete();
|
170
|
+
|
171
|
+
await this.opts.beforeChunkPlay(chunk);
|
172
|
+
|
173
|
+
if (!this.playing) return;
|
174
|
+
|
175
|
+
const playPromise = await this.playSound(sound)
|
176
|
+
.then(()=> this.opts.afterChunkPlay(sound.chunk));
|
177
|
+
|
178
|
+
if (this.paused) this.pause();
|
179
|
+
await playPromise;
|
180
|
+
|
181
|
+
if (this.playing) return this.step();
|
173
182
|
}
|
174
183
|
|
175
184
|
/**
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import AbstractTTSEngine from './AbstractTTSEngine.js';
|
2
|
-
import { sleep } from '
|
2
|
+
import { sleep } from '../../BookReader/utils.js';
|
3
3
|
/* global soundManager */
|
4
4
|
import 'soundmanager2';
|
5
5
|
import 'jquery.browser';
|
@@ -23,7 +23,7 @@ export default class FestivalTTSEngine extends AbstractTTSEngine {
|
|
23
23
|
// $.browsers is sometimes undefined on some Android browsers :/
|
24
24
|
// Likely related to when $.browser was moved to npm
|
25
25
|
/** @type {'mp3' | 'ogg'} format of audio to get */
|
26
|
-
this.audioFormat = $.browser?.mozilla ? 'ogg' : 'mp3';
|
26
|
+
this.audioFormat = $.browser?.mozilla ? 'ogg' : 'mp3'; //eslint-disable-line no-jquery/no-browser
|
27
27
|
}
|
28
28
|
|
29
29
|
/** @override */
|
@@ -91,10 +91,10 @@ export default class FestivalTTSEngine extends AbstractTTSEngine {
|
|
91
91
|
* See https://stackoverflow.com/questions/12206631/html5-audio-cant-play-through-javascript-unless-triggered-manually-once
|
92
92
|
* @return {PromiseLike}
|
93
93
|
*/
|
94
|
-
iOSCaptureUserIntentHack() {
|
94
|
+
async iOSCaptureUserIntentHack() {
|
95
95
|
const sound = soundManager.createSound({ url: SILENCE_1MS[this.audioFormat] });
|
96
|
-
|
97
|
-
|
96
|
+
await new Promise(res => sound.play({onfinish: res}));
|
97
|
+
sound.destruct();
|
98
98
|
}
|
99
99
|
}
|
100
100
|
|
@@ -107,7 +107,7 @@ class FestivalTTSSound {
|
|
107
107
|
this.sound = null;
|
108
108
|
this.rate = 1;
|
109
109
|
/** @type {function} calling this resolves the "play" promise */
|
110
|
-
this._finishResolver = null
|
110
|
+
this._finishResolver = null;
|
111
111
|
}
|
112
112
|
|
113
113
|
get loaded() {
|
@@ -122,21 +122,20 @@ class FestivalTTSSound {
|
|
122
122
|
if (this.rate != 1) this.sound.setPlaybackRate(this.rate);
|
123
123
|
onload();
|
124
124
|
},
|
125
|
-
onresume: () => {
|
126
|
-
sleep(25)
|
127
|
-
|
128
|
-
});
|
125
|
+
onresume: async () => {
|
126
|
+
await sleep(25);
|
127
|
+
if (this.rate != 1) this.sound.setPlaybackRate(this.rate);
|
129
128
|
}
|
130
129
|
});
|
131
130
|
return this.sound.load();
|
132
131
|
}
|
133
132
|
|
134
|
-
play() {
|
135
|
-
|
133
|
+
async play() {
|
134
|
+
await new Promise(res => {
|
136
135
|
this._finishResolver = res;
|
137
136
|
this.sound.play({ onfinish: res });
|
138
|
-
})
|
139
|
-
|
137
|
+
});
|
138
|
+
this.sound.destruct();
|
140
139
|
}
|
141
140
|
|
142
141
|
/** @override */
|
@@ -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
|
/**
|