@internetarchive/bookreader 5.0.0-88-alpha.11 → 5.0.0-89

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.
Files changed (243) hide show
  1. package/BookReader/BookReader.css +17 -3
  2. package/BookReader/BookReader.js +1 -1
  3. package/BookReader/BookReader.js.map +1 -1
  4. package/BookReader/ia-bookreader-bundle.js +87 -108
  5. package/BookReader/ia-bookreader-bundle.js.map +1 -1
  6. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  7. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  8. package/BookReader/plugins/plugin.autoplay.js +1 -1
  9. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  10. package/BookReader/plugins/plugin.iiif.js +1 -1
  11. package/BookReader/plugins/plugin.iiif.js.map +1 -1
  12. package/BookReader/plugins/plugin.resume.js +1 -1
  13. package/BookReader/plugins/plugin.resume.js.map +1 -1
  14. package/BookReader/plugins/plugin.search.js +1 -1
  15. package/BookReader/plugins/plugin.search.js.map +1 -1
  16. package/BookReader/plugins/plugin.text_selection.js +1 -1
  17. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  18. package/BookReader/plugins/plugin.tts.js +1 -1
  19. package/BookReader/plugins/plugin.tts.js.map +1 -1
  20. package/BookReader/plugins/plugin.url.js +1 -1
  21. package/BookReader/plugins/plugin.url.js.map +1 -1
  22. package/CHANGELOG.md +14 -0
  23. package/babel.config.js +12 -30
  24. package/codecov.yml +1 -1
  25. package/jsconfig.json +1 -3
  26. package/package.json +14 -16
  27. package/src/BookNavigator/search/search-results.js +1 -1
  28. package/src/BookReader/ImageCache.js +48 -15
  29. package/src/BookReader/Mode1UpLit.js +56 -86
  30. package/src/BookReader/Mode2UpLit.js +5 -5
  31. package/src/BookReader/Navbar/Navbar.js +53 -11
  32. package/src/BookReader/PageContainer.js +41 -22
  33. package/src/BookReader/options.js +27 -3
  34. package/src/BookReader/utils.js +10 -0
  35. package/src/BookReader.js +120 -21
  36. package/src/BookReaderPlugin.js +44 -0
  37. package/src/css/_BRnav.scss +0 -3
  38. package/src/css/_BRpages.scss +21 -2
  39. package/src/css/_controls.scss +4 -0
  40. package/src/plugins/plugin.archive_analytics.js +84 -78
  41. package/src/plugins/plugin.autoplay.js +98 -102
  42. package/src/plugins/plugin.chapters.js +17 -22
  43. package/src/plugins/plugin.iiif.js +16 -30
  44. package/src/plugins/plugin.resume.js +54 -51
  45. package/src/plugins/plugin.text_selection.js +68 -76
  46. package/src/plugins/tts/AbstractTTSEngine.js +2 -4
  47. package/src/plugins/tts/PageChunk.js +5 -9
  48. package/src/plugins/tts/PageChunkIterator.js +3 -5
  49. package/src/plugins/tts/plugin.tts.js +309 -329
  50. package/src/plugins/url/plugin.url.js +1 -1
  51. package/src/util/strings.js +1 -0
  52. package/tests/e2e/autoplay.test.js +8 -5
  53. package/tests/e2e/helpers/base.js +2 -2
  54. package/tests/e2e/helpers/mockSearch.js +6 -9
  55. package/tests/jest/BookReader/Navbar/Navbar.test.js +16 -3
  56. package/tests/jest/BookReader/PageContainer.test.js +96 -55
  57. package/tests/jest/BookReader/utils.test.js +21 -0
  58. package/tests/jest/BookReader.test.js +13 -12
  59. package/tests/jest/plugins/plugin.archive_analytics.test.js +8 -11
  60. package/tests/jest/plugins/plugin.autoplay.test.js +9 -22
  61. package/tests/jest/plugins/plugin.resume.test.js +19 -32
  62. package/tests/jest/plugins/plugin.text_selection.test.js +23 -24
  63. package/dist/esm/BookNavigator/assets/bookmark-colors.js +0 -4
  64. package/dist/esm/BookNavigator/assets/button-base.js +0 -4
  65. package/dist/esm/BookNavigator/assets/ia-logo.js +0 -4
  66. package/dist/esm/BookNavigator/assets/icon_checkmark.js +0 -8
  67. package/dist/esm/BookNavigator/assets/icon_close.js +0 -4
  68. package/dist/esm/BookNavigator/book-navigator.js +0 -612
  69. package/dist/esm/BookNavigator/bookmarks/bookmark-button.js +0 -35
  70. package/dist/esm/BookNavigator/bookmarks/bookmark-edit.js +0 -78
  71. package/dist/esm/BookNavigator/bookmarks/bookmarks-list.js +0 -160
  72. package/dist/esm/BookNavigator/bookmarks/bookmarks-loginCTA.js +0 -24
  73. package/dist/esm/BookNavigator/bookmarks/bookmarks-provider.js +0 -55
  74. package/dist/esm/BookNavigator/bookmarks/ia-bookmarks.js +0 -521
  75. package/dist/esm/BookNavigator/delete-modal-actions.js +0 -29
  76. package/dist/esm/BookNavigator/downloads/downloads-provider.js +0 -84
  77. package/dist/esm/BookNavigator/downloads/downloads.js +0 -69
  78. package/dist/esm/BookNavigator/search/search-provider.js +0 -238
  79. package/dist/esm/BookNavigator/search/search-results.js +0 -161
  80. package/dist/esm/BookNavigator/sharing.js +0 -26
  81. package/dist/esm/BookNavigator/viewable-files.js +0 -94
  82. package/dist/esm/BookNavigator/visual-adjustments/visual-adjustments-provider.js +0 -83
  83. package/dist/esm/BookNavigator/visual-adjustments/visual-adjustments.js +0 -131
  84. package/dist/esm/BookReader/BookModel.js +0 -575
  85. package/dist/esm/BookReader/DragScrollable.js +0 -224
  86. package/dist/esm/BookReader/ImageCache.js +0 -122
  87. package/dist/esm/BookReader/Mode1Up.js +0 -114
  88. package/dist/esm/BookReader/Mode1UpLit.js +0 -579
  89. package/dist/esm/BookReader/Mode2Up.js +0 -106
  90. package/dist/esm/BookReader/Mode2UpLit.js +0 -1020
  91. package/dist/esm/BookReader/ModeCoordinateSpace.js +0 -28
  92. package/dist/esm/BookReader/ModeSmoothZoom.js +0 -318
  93. package/dist/esm/BookReader/ModeThumb.js +0 -366
  94. package/dist/esm/BookReader/Navbar/Navbar.js +0 -253
  95. package/dist/esm/BookReader/PageContainer.js +0 -165
  96. package/dist/esm/BookReader/ReduceSet.js +0 -27
  97. package/dist/esm/BookReader/Toolbar/Toolbar.js +0 -242
  98. package/dist/esm/BookReader/events.js +0 -20
  99. package/dist/esm/BookReader/options.js +0 -331
  100. package/dist/esm/BookReader/utils/HTMLDimensionsCacher.js +0 -48
  101. package/dist/esm/BookReader/utils/ScrollClassAdder.js +0 -31
  102. package/dist/esm/BookReader/utils/SelectionObserver.js +0 -42
  103. package/dist/esm/BookReader/utils/classes.js +0 -37
  104. package/dist/esm/BookReader/utils.js +0 -315
  105. package/dist/esm/BookReader.js +0 -1828
  106. package/dist/esm/assets/icons/1up.svg +0 -12
  107. package/dist/esm/assets/icons/2up.svg +0 -15
  108. package/dist/esm/assets/icons/advance.svg +0 -26
  109. package/dist/esm/assets/icons/chevron-right.svg +0 -1
  110. package/dist/esm/assets/icons/close-circle-dark.svg +0 -1
  111. package/dist/esm/assets/icons/close-circle.svg +0 -1
  112. package/dist/esm/assets/icons/fullscreen.svg +0 -17
  113. package/dist/esm/assets/icons/fullscreen_exit.svg +0 -17
  114. package/dist/esm/assets/icons/hamburger.svg +0 -15
  115. package/dist/esm/assets/icons/left-arrow.svg +0 -12
  116. package/dist/esm/assets/icons/magnify-minus.svg +0 -12
  117. package/dist/esm/assets/icons/magnify-plus.svg +0 -13
  118. package/dist/esm/assets/icons/magnify.svg +0 -15
  119. package/dist/esm/assets/icons/pause.svg +0 -23
  120. package/dist/esm/assets/icons/play.svg +0 -22
  121. package/dist/esm/assets/icons/playback-speed.svg +0 -34
  122. package/dist/esm/assets/icons/read-aloud.svg +0 -22
  123. package/dist/esm/assets/icons/review.svg +0 -22
  124. package/dist/esm/assets/icons/thumbnails.svg +0 -17
  125. package/dist/esm/assets/icons/voice.svg +0 -1
  126. package/dist/esm/assets/icons/volume-full.svg +0 -22
  127. package/dist/esm/assets/images/BRicons.png +0 -0
  128. package/dist/esm/assets/images/BRicons.svg +0 -94
  129. package/dist/esm/assets/images/BRicons_ia.png +0 -0
  130. package/dist/esm/assets/images/back_pages.png +0 -0
  131. package/dist/esm/assets/images/book_bottom_icon.png +0 -0
  132. package/dist/esm/assets/images/book_down_icon.png +0 -0
  133. package/dist/esm/assets/images/book_left_icon.png +0 -0
  134. package/dist/esm/assets/images/book_leftmost_icon.png +0 -0
  135. package/dist/esm/assets/images/book_right_icon.png +0 -0
  136. package/dist/esm/assets/images/book_rightmost_icon.png +0 -0
  137. package/dist/esm/assets/images/book_top_icon.png +0 -0
  138. package/dist/esm/assets/images/book_up_icon.png +0 -0
  139. package/dist/esm/assets/images/books_graphic.svg +0 -177
  140. package/dist/esm/assets/images/booksplit.png +0 -0
  141. package/dist/esm/assets/images/control_pause_icon.png +0 -0
  142. package/dist/esm/assets/images/control_play_icon.png +0 -0
  143. package/dist/esm/assets/images/embed_icon.png +0 -0
  144. package/dist/esm/assets/images/icon-home-ia.png +0 -0
  145. package/dist/esm/assets/images/icon_OL-logo-xs.png +0 -0
  146. package/dist/esm/assets/images/icon_alert-xs.png +0 -0
  147. package/dist/esm/assets/images/icon_book.svg +0 -12
  148. package/dist/esm/assets/images/icon_bookmark.svg +0 -12
  149. package/dist/esm/assets/images/icon_close-pop.png +0 -0
  150. package/dist/esm/assets/images/icon_download.png +0 -0
  151. package/dist/esm/assets/images/icon_gear.svg +0 -14
  152. package/dist/esm/assets/images/icon_hamburger.svg +0 -20
  153. package/dist/esm/assets/images/icon_home.png +0 -0
  154. package/dist/esm/assets/images/icon_home.svg +0 -21
  155. package/dist/esm/assets/images/icon_home_ia.png +0 -0
  156. package/dist/esm/assets/images/icon_indicator.png +0 -0
  157. package/dist/esm/assets/images/icon_info.svg +0 -11
  158. package/dist/esm/assets/images/icon_one_page.svg +0 -8
  159. package/dist/esm/assets/images/icon_pause.svg +0 -1
  160. package/dist/esm/assets/images/icon_play.svg +0 -1
  161. package/dist/esm/assets/images/icon_playback-rate.svg +0 -15
  162. package/dist/esm/assets/images/icon_return.png +0 -0
  163. package/dist/esm/assets/images/icon_search_button.svg +0 -8
  164. package/dist/esm/assets/images/icon_share.svg +0 -9
  165. package/dist/esm/assets/images/icon_skip-ahead.svg +0 -6
  166. package/dist/esm/assets/images/icon_skip-back.svg +0 -13
  167. package/dist/esm/assets/images/icon_speaker.svg +0 -18
  168. package/dist/esm/assets/images/icon_speaker_open.svg +0 -10
  169. package/dist/esm/assets/images/icon_thumbnails.svg +0 -12
  170. package/dist/esm/assets/images/icon_toc.svg +0 -5
  171. package/dist/esm/assets/images/icon_two_pages.svg +0 -9
  172. package/dist/esm/assets/images/icon_zoomer.png +0 -0
  173. package/dist/esm/assets/images/loading.gif +0 -0
  174. package/dist/esm/assets/images/logo_icon.png +0 -0
  175. package/dist/esm/assets/images/marker_chap-off.png +0 -0
  176. package/dist/esm/assets/images/marker_chap-off.svg +0 -11
  177. package/dist/esm/assets/images/marker_chap-off_ia.png +0 -0
  178. package/dist/esm/assets/images/marker_chap-on.png +0 -0
  179. package/dist/esm/assets/images/marker_chap-on.svg +0 -11
  180. package/dist/esm/assets/images/marker_srch-on.svg +0 -11
  181. package/dist/esm/assets/images/marker_srchchap-off.png +0 -0
  182. package/dist/esm/assets/images/marker_srchchap-on.png +0 -0
  183. package/dist/esm/assets/images/nav_control-dn.png +0 -0
  184. package/dist/esm/assets/images/nav_control-dn_ia.png +0 -0
  185. package/dist/esm/assets/images/nav_control-up.png +0 -0
  186. package/dist/esm/assets/images/nav_control-up_ia.png +0 -0
  187. package/dist/esm/assets/images/nav_control.png +0 -0
  188. package/dist/esm/assets/images/one_page_mode_icon.png +0 -0
  189. package/dist/esm/assets/images/paper-badge.png +0 -0
  190. package/dist/esm/assets/images/print_icon.png +0 -0
  191. package/dist/esm/assets/images/progressbar.gif +0 -0
  192. package/dist/esm/assets/images/right_edges.png +0 -0
  193. package/dist/esm/assets/images/slider.png +0 -0
  194. package/dist/esm/assets/images/slider_ia.png +0 -0
  195. package/dist/esm/assets/images/thumbnail_mode_icon.png +0 -0
  196. package/dist/esm/assets/images/transparent.png +0 -0
  197. package/dist/esm/assets/images/two_page_mode_icon.png +0 -0
  198. package/dist/esm/assets/images/unviewable_page.png +0 -0
  199. package/dist/esm/assets/images/zoom_in_icon.png +0 -0
  200. package/dist/esm/assets/images/zoom_out_icon.png +0 -0
  201. package/dist/esm/css/BookReader.scss +0 -85
  202. package/dist/esm/css/_BRBookmarks.scss +0 -29
  203. package/dist/esm/css/_BRComponent.scss +0 -13
  204. package/dist/esm/css/_BRfloat.scss +0 -197
  205. package/dist/esm/css/_BRicon.scss +0 -54
  206. package/dist/esm/css/_BRmain.scss +0 -262
  207. package/dist/esm/css/_BRnav.scss +0 -354
  208. package/dist/esm/css/_BRpages.scss +0 -213
  209. package/dist/esm/css/_BRsearch.scss +0 -268
  210. package/dist/esm/css/_BRtoolbar.scss +0 -84
  211. package/dist/esm/css/_BRvendor.scss +0 -5
  212. package/dist/esm/css/_TextSelection.scss +0 -108
  213. package/dist/esm/css/_colorbox.scss +0 -52
  214. package/dist/esm/css/_controls.scss +0 -257
  215. package/dist/esm/css/_icons.scss +0 -121
  216. package/dist/esm/ia-bookreader/ia-bookreader.js +0 -141
  217. package/dist/esm/jquery-wrapper.js +0 -3
  218. package/dist/esm/plugins/plugin.archive_analytics.js +0 -72
  219. package/dist/esm/plugins/plugin.autoplay.js +0 -119
  220. package/dist/esm/plugins/plugin.chapters.js +0 -288
  221. package/dist/esm/plugins/plugin.iframe.js +0 -44
  222. package/dist/esm/plugins/plugin.iiif.js +0 -146
  223. package/dist/esm/plugins/plugin.resume.js +0 -66
  224. package/dist/esm/plugins/plugin.text_selection.js +0 -621
  225. package/dist/esm/plugins/plugin.vendor-fullscreen.js +0 -227
  226. package/dist/esm/plugins/search/plugin.search.js +0 -499
  227. package/dist/esm/plugins/search/utils.js +0 -42
  228. package/dist/esm/plugins/search/view.js +0 -360
  229. package/dist/esm/plugins/tts/AbstractTTSEngine.js +0 -282
  230. package/dist/esm/plugins/tts/FestivalTTSEngine.js +0 -192
  231. package/dist/esm/plugins/tts/PageChunk.js +0 -105
  232. package/dist/esm/plugins/tts/PageChunkIterator.js +0 -155
  233. package/dist/esm/plugins/tts/WebTTSEngine.js +0 -364
  234. package/dist/esm/plugins/tts/plugin.tts.js +0 -315
  235. package/dist/esm/plugins/tts/tooltip_dict.js +0 -14
  236. package/dist/esm/plugins/tts/utils.js +0 -79
  237. package/dist/esm/plugins/url/UrlPlugin.js +0 -197
  238. package/dist/esm/plugins/url/plugin.url.js +0 -212
  239. package/dist/esm/util/browserSniffing.js +0 -56
  240. package/dist/esm/util/debouncer.js +0 -25
  241. package/dist/esm/util/docCookies.js +0 -75
  242. package/dist/esm/util/strings.js +0 -34
  243. package/index.js +0 -2
@@ -1,360 +0,0 @@
1
- class SearchView {
2
- /**
3
- * @param {object} params
4
- * @param {object} params.br The BookReader instance
5
- * @param {function} params.cancelSearch callback when a user wants to cancel search
6
- *
7
- * @event BookReader:SearchResultsCleared - when the search results nav gets cleared
8
- * @event BookReader:ToggleSearchMenu - when search results menu should toggle
9
- */
10
- constructor(_ref) {
11
- var {
12
- br,
13
- searchCancelledCallback = () => {}
14
- } = _ref;
15
- this.br = br;
16
- this.matches = [];
17
- this.cacheDOMElements();
18
- this.cancelSearch = searchCancelledCallback;
19
- }
20
- init() {
21
- this.bindEvents();
22
- }
23
- cacheDOMElements() {
24
- this.dom = {};
25
- // Search input within the top toolbar. Will be removed once the mobile menu is replaced.
26
- this.dom.toolbarSearch = this.buildToolbarSearch();
27
- }
28
-
29
- /**
30
- * @param {string} query
31
- */
32
- setQuery(query) {
33
- this.br.$('[name="query"]').val(query);
34
- }
35
- emptyMatches() {
36
- this.matches = [];
37
- }
38
- removeResultPins() {
39
- this.br.$('.BRnavpos .BRsearch').remove();
40
- }
41
- clearSearchFieldAndResults() {
42
- var dispatchEventWhenComplete = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
43
- this.br.removeSearchResults();
44
- this.removeResultPins();
45
- this.emptyMatches();
46
- this.setQuery('');
47
- this.teardownSearchNavigation();
48
- if (dispatchEventWhenComplete) {
49
- this.br.trigger('SearchResultsCleared');
50
- }
51
- }
52
- toggleSidebar() {
53
- this.br.trigger('ToggleSearchMenu');
54
- }
55
- renderSearchNavigation() {
56
- var selector = 'BRsearch-navigation';
57
- $('.BRnav').before("\n <div class=\"".concat(selector, "\">\n <button class=\"toggle-sidebar\">\n <h4>\n <span class=\"icon icon-search\"></span> Results\n </h4>\n </button>\n <div class=\"pagination\">\n <button class=\"prev\" title=\"Previous result\"><span class=\"icon icon-chevron hflip\"></span></button>\n <span data-id=\"resultsCount\">").concat(this.resultsPosition(), "</span>\n <button class=\"next\" title=\"Next result\"><span class=\"icon icon-chevron\"></button>\n </div>\n <button class=\"clear\" title=\"Clear search results\">\n <span class=\"icon icon-close\"></span>\n </button>\n </div>\n "));
58
- this.dom.searchNavigation = $(".".concat(selector));
59
- }
60
- resultsPosition() {
61
- var positionMessage = "".concat(this.matches.length, " result").concat(this.matches.length === 1 ? '' : 's');
62
- if (~this.currentMatchIndex) {
63
- positionMessage = "".concat(this.currentMatchIndex + 1, " / ").concat(this.matches.length);
64
- }
65
- return positionMessage;
66
- }
67
- bindSearchNavigationEvents() {
68
- if (!this.dom.searchNavigation) {
69
- return;
70
- }
71
- var namespace = 'searchNavigation';
72
- this.dom.searchNavigation.on("click.".concat(namespace), '.clear', this.clearSearchFieldAndResults.bind(this)).on("click.".concat(namespace), '.prev', this.showPrevResult.bind(this)).on("click.".concat(namespace), '.next', this.showNextResult.bind(this)).on("click.".concat(namespace), '.toggle-sidebar', this.toggleSidebar.bind(this)).on("click.".concat(namespace), false);
73
- }
74
- showPrevResult() {
75
- if (this.currentMatchIndex === 0) {
76
- return;
77
- }
78
- if (this.br.mode === this.br.constModeThumb) {
79
- this.br.switchMode(this.br.constMode1up);
80
- }
81
- if (!~this.currentMatchIndex) {
82
- this.currentMatchIndex = this.getClosestMatchIndex((start, end, comparator) => end[0] > comparator) + 1;
83
- }
84
- this.br.$('.BRnavline .BRsearch').eq(--this.currentMatchIndex).click();
85
- this.updateResultsPosition();
86
- this.updateSearchNavigationButtons();
87
- }
88
- showNextResult() {
89
- if (this.currentMatchIndex + 1 === this.matches.length) {
90
- return;
91
- }
92
- if (this.br.mode === this.br.constModeThumb) {
93
- this.br.switchMode(this.br.constMode1up);
94
- }
95
- if (!~this.currentMatchIndex) {
96
- this.currentMatchIndex = this.getClosestMatchIndex((start, end, comparator) => start[start.length - 1] > comparator) - 1;
97
- }
98
- this.br.$('.BRnavline .BRsearch').eq(++this.currentMatchIndex).click();
99
- this.updateResultsPosition();
100
- this.updateSearchNavigationButtons();
101
- }
102
-
103
- /**
104
- * Obtains closest match based on the logical comparison function passed in.
105
- * When the comparison function returns true, the starting (left) half of the
106
- * matches array is used in the binary split, else the ending (right) half is
107
- * used. A recursive call is made to perform the same split and comparison
108
- * on the winning half of the matches. This is traditionally known as binary
109
- * search (https://en.wikipedia.org/wiki/Binary_search_algorithm), and in
110
- * most cases (medium to large search result arrays) should outperform
111
- * traversing the array from start to finish. In the case of small arrays,
112
- * the speed difference is negligible.
113
- *
114
- * @param {function} comparisonFn
115
- * @return {number} matchIndex
116
- */
117
- getClosestMatchIndex(comparisonFn) {
118
- var matchPages = this.matches.map(m => m.par[0].page);
119
- var currentPage = this.br.currentIndex() + 1;
120
- var closestTo = (pool, comparator) => {
121
- if (pool.length === 1) {
122
- return pool[0];
123
- }
124
- var start = pool.slice(0, pool.length / 2);
125
- var end = pool.slice(pool.length / 2);
126
- return closestTo(comparisonFn(start, end, comparator) ? start : end, comparator);
127
- };
128
- var closestPage = closestTo(matchPages, currentPage);
129
- return this.matches.indexOf(this.matches.find(m => m.par[0].page === closestPage));
130
- }
131
- updateResultsPosition() {
132
- if (!this.dom.searchNavigation) return;
133
- this.dom.searchNavigation.find('[data-id=resultsCount]').text(this.resultsPosition());
134
- }
135
- updateSearchNavigationButtons() {
136
- if (!this.dom.searchNavigation) return;
137
- this.dom.searchNavigation.find('.prev').attr('disabled', !this.currentMatchIndex);
138
- this.dom.searchNavigation.find('.next').attr('disabled', this.currentMatchIndex + 1 === this.matches.length);
139
- }
140
- teardownSearchNavigation() {
141
- if (!this.dom.searchNavigation) {
142
- this.dom.searchNavigation = $('.BRsearch-navigation');
143
- }
144
- if (!this.dom.searchNavigation.length) {
145
- return;
146
- }
147
- this.dom.searchNavigation.off('.searchNavigation').remove();
148
- this.dom.searchNavigation = null;
149
- this.br.resize();
150
- }
151
- setCurrentMatchIndex() {
152
- var matchingSearchResult;
153
- if (this.br.mode === this.br.constModeThumb) {
154
- this.currentMatchIndex = -1;
155
- return;
156
- }
157
- if (this.br.mode === this.br.constMode2up) {
158
- matchingSearchResult = this.find2upMatchingSearchResult();
159
- } else {
160
- matchingSearchResult = this.find1upMatchingSearchResult();
161
- }
162
- this.currentMatchIndex = this.matches.indexOf(matchingSearchResult);
163
- }
164
- find1upMatchingSearchResult() {
165
- return this.matches.find(m => this.br.currentIndex() === m.par[0].page - 1);
166
- }
167
- find2upMatchingSearchResult() {
168
- return this.matches.find(m => this.br._isIndexDisplayed(m.par[0].page - 1));
169
- }
170
- updateSearchNavigation() {
171
- if (!this.matches.length) {
172
- return;
173
- }
174
- this.setCurrentMatchIndex();
175
- this.updateResultsPosition();
176
- this.updateSearchNavigationButtons();
177
- }
178
-
179
- /**
180
- * @param {boolean} bool
181
- */
182
- togglePinsFor(bool) {
183
- var pinsVisibleState = bool ? 'visible' : 'hidden';
184
- this.br.refs.$BRfooter.find('.BRsearch').css({
185
- visibility: pinsVisibleState
186
- });
187
- }
188
- buildToolbarSearch() {
189
- var toolbarSearch = document.createElement('span');
190
- toolbarSearch.classList.add('BRtoolbarSection', 'BRtoolbarSectionSearch');
191
- toolbarSearch.innerHTML = "\n <form class=\"BRbooksearch desktop\">\n <input type=\"search\" name=\"query\" class=\"BRsearchInput\" value=\"\" placeholder=\"Search inside\"/>\n <button type=\"submit\" class=\"BRsearchSubmit\">\n <img src=\"".concat(this.br.imagesBaseURL, "icon_search_button.svg\" />\n </button>\n </form>\n ");
192
- return toolbarSearch;
193
- }
194
-
195
- /**
196
- * @param {array} matches
197
- */
198
- renderPins(matches) {
199
- matches.forEach(match => {
200
- var pageIndex = this.br.book.leafNumToIndex(match.par[0].page);
201
- var uiStringSearch = "Search result"; // i18n
202
- var percentThrough = this.br.constructor.util.cssPercentage(pageIndex, this.br.book.getNumLeafs() - 1);
203
- var html = match.html;
204
- if (html.length > 200) {
205
- var start = Math.max(0, html.indexOf('<mark>') - 100);
206
- if (start != 0) {
207
- html = '…' + match.html.substring(start)
208
- // Make sure at word boundary though
209
- .replace(/^\S+/, '');
210
- }
211
- }
212
- // draw marker
213
- $('<div>').addClass('BRsearch').css({
214
- left: percentThrough
215
- }).attr('title', uiStringSearch).append("\n <div class=\"BRquery\">\n <main>".concat(html, "</main>\n <footer>Page ").concat(match.displayPageNumber, "</footer>\n </div>\n ")).appendTo(this.br.$('.BRnavline')).on("mouseenter", event => {
216
- // remove from other markers then turn on just for this
217
- // XXX should be done when nav slider moves
218
- var marker = event.currentTarget;
219
- var tooltip = marker.querySelector('.BRquery');
220
- var tooltipOffset = tooltip.getBoundingClientRect();
221
- var targetOffset = marker.getBoundingClientRect();
222
- var boxSizeAdjust = parseInt(getComputedStyle(tooltip).paddingLeft) * 2;
223
- if (tooltipOffset.x - boxSizeAdjust < 0) {
224
- tooltip.style.setProperty('transform', "translateX(-".concat(targetOffset.left - boxSizeAdjust, "px)"));
225
- }
226
- $('.BRsearch,.BRchapter').removeClass('front');
227
- $(event.target).addClass('front');
228
- }).on("mouseleave", event => $(event.target).removeClass('front')).on("click", () => {
229
- this.br._searchPluginGoToResult(match.matchIndex);
230
- });
231
- });
232
- }
233
-
234
- /**
235
- * @param {boolean} bool
236
- */
237
- toggleSearchPending(bool) {
238
- if (bool) {
239
- this.br.showProgressPopup("Search results will appear below...", () => this.progressPopupClosed());
240
- } else {
241
- this.br.removeProgressPopup();
242
- }
243
- }
244
-
245
- /**
246
- * Primary callback when user cancels search popup
247
- */
248
- progressPopupClosed() {
249
- this.toggleSearchPending();
250
- this.cancelSearch();
251
- }
252
- renderErrorModal() {
253
- var textIsProcessing = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
254
- var errorDetails = "".concat(!textIsProcessing ? 'The text may still be processing. ' : '', "Please try again.");
255
- this.renderModalMessage("\n Sorry, there was an error with your search.\n <br />\n ".concat(errorDetails, "\n "));
256
- this.delayModalRemovalFor(4000);
257
- }
258
- renderBookNotIndexedModal() {
259
- this.renderModalMessage("\n <p>\n This book hasn't been indexed for searching yet.\n We've just started indexing it, so search should be available soon.\n <br />\n Please try again later. Thanks!\n </p>\n ");
260
- this.delayModalRemovalFor(5000);
261
- }
262
- renderResultsEmptyModal() {
263
- this.renderModalMessage('No matches were found.');
264
- this.delayModalRemovalFor(2000);
265
- }
266
-
267
- /**
268
- * @param {string} messageHTML The innerHTML string used to popupate the modal contents
269
- */
270
- renderModalMessage(messageHTML) {
271
- var modal = document.createElement('div');
272
- modal.classList.add('BRprogresspopup', 'search_modal');
273
- modal.innerHTML = messageHTML;
274
- document.querySelector(this.br.el).append(modal);
275
- }
276
-
277
- /**
278
- * @param {number} timeoutMS
279
- */
280
- delayModalRemovalFor(timeoutMS) {
281
- setTimeout(this.br.removeProgressPopup.bind(this.br), timeoutMS);
282
- }
283
-
284
- /**
285
- * @param {Event} e
286
- */
287
- submitHandler(e) {
288
- e.preventDefault();
289
- var query = e.target.querySelector('[name="query"]').value;
290
- if (!query.length) {
291
- return false;
292
- }
293
- this.br.search(query);
294
- this.emptyMatches();
295
- this.toggleSearchPending(true);
296
- return false;
297
- }
298
-
299
- /**
300
- * @param {Event} e
301
- * @param {object} properties
302
- * @param {object} properties.results
303
- * @param {object} properties.options
304
- */
305
- handleSearchCallback(e, _ref2) {
306
- var {
307
- results,
308
- options
309
- } = _ref2;
310
- this.matches = results.matches;
311
- this.setCurrentMatchIndex();
312
- this.teardownSearchNavigation();
313
- this.renderSearchNavigation();
314
- this.bindSearchNavigationEvents();
315
- this.renderPins(results.matches);
316
- this.toggleSearchPending(false);
317
- if (options.goToFirstResult) {
318
- $(document).one('BookReader:pageChanged', () => {
319
- this.br.resize();
320
- });
321
- } else {
322
- this.br.resize();
323
- }
324
- }
325
- handleSearchStarted() {
326
- this.emptyMatches();
327
- this.br.removeSearchHilites();
328
- this.removeResultPins();
329
- this.toggleSearchPending(true);
330
- this.teardownSearchNavigation();
331
- this.setQuery(this.br.searchTerm);
332
- }
333
-
334
- /**
335
- * Event listener for: `BookReader:SearchCallbackError`
336
- * @param {CustomEvent} event
337
- */
338
- handleSearchCallbackError() {
339
- var _event$detail;
340
- var event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
341
- this.toggleSearchPending(false);
342
- var isIndexed = event === null || event === void 0 || (_event$detail = event.detail) === null || _event$detail === void 0 || (_event$detail = _event$detail.props) === null || _event$detail === void 0 || (_event$detail = _event$detail.results) === null || _event$detail === void 0 ? void 0 : _event$detail.indexed;
343
- this.renderErrorModal(isIndexed);
344
- }
345
- handleSearchCallbackBookNotIndexed() {
346
- this.toggleSearchPending(false);
347
- this.renderBookNotIndexedModal();
348
- }
349
- handleSearchCallbackEmpty() {
350
- this.toggleSearchPending(false);
351
- this.renderResultsEmptyModal();
352
- }
353
- bindEvents() {
354
- var namespace = 'BookReader:';
355
- window.addEventListener("".concat(namespace, "SearchCallbackError"), this.handleSearchCallbackError.bind(this));
356
- $(document).on("".concat(namespace, "SearchCallback"), this.handleSearchCallback.bind(this)).on("".concat(namespace, "SearchStarted"), this.handleSearchStarted.bind(this)).on("".concat(namespace, "SearchCallbackBookNotIndexed"), this.handleSearchCallbackBookNotIndexed.bind(this)).on("".concat(namespace, "SearchCallbackEmpty"), this.handleSearchCallbackEmpty.bind(this)).on("".concat(namespace, "pageChanged"), this.updateSearchNavigation.bind(this));
357
- this.dom.toolbarSearch.querySelector('form').addEventListener('submit', this.submitHandler.bind(this));
358
- }
359
- }
360
- export default SearchView;
@@ -1,282 +0,0 @@
1
- function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
2
- function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
3
- function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
4
- function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
5
- function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
- import PageChunkIterator from './PageChunkIterator.js';
7
- import { hasLocalStorage } from './utils.js';
8
- /** @typedef {import('./utils.js').ISO6391} ISO6391 */
9
- /** @typedef {import('./PageChunk.js')} PageChunk */
10
-
11
- /**
12
- * @export
13
- * @typedef {Object} TTSEngineOptions
14
- * @property {String} server
15
- * @property {String} bookPath
16
- * @property {ISO6391} bookLanguage
17
- * @property {Function} onLoadingStart
18
- * @property {Function} onLoadingComplete
19
- * @property {Function} onDone called when the entire book is done
20
- * @property {function(PageChunk): PromiseLike} beforeChunkPlay will delay the playing of the chunk
21
- * @property {function(PageChunk): void} afterChunkPlay fires once a chunk has fully finished
22
- */
23
-
24
- /**
25
- * @typedef {Object} AbstractTTSSound
26
- * @property {PageChunk} chunk
27
- * @property {boolean} loaded
28
- * @property {number} rate
29
- * @property {SpeechSynthesisVoice} voice
30
- * @property {(callback: Function) => void} load
31
- * @property {() => PromiseLike} play
32
- * @property {() => Promise} stop
33
- * @property {() => void} pause
34
- * @property {() => void} resume
35
- * @property {() => void} finish force the sound to 'finish'
36
- * @property {number => void} setPlaybackRate
37
- * @property {SpeechSynthesisVoice => void} setVoice
38
- **/
39
-
40
- /** Handling bookreader's text-to-speech */
41
- export default class AbstractTTSEngine {
42
- /**
43
- * @protected
44
- * @param {TTSEngineOptions} options
45
- */
46
- constructor(options) {
47
- _defineProperty(this, "updateBestVoice", () => {
48
- this.voice = AbstractTTSEngine.getBestBookVoice(this.getVoices(), this.opts.bookLanguage);
49
- });
50
- this.playing = false;
51
- this.paused = false;
52
- this.opts = options;
53
- /** @type {PageChunkIterator} */
54
- this._chunkIterator = null;
55
- /** @type {AbstractTTSSound} */
56
- this.activeSound = null;
57
- this.playbackRate = 1;
58
- /** Events we can bind to */
59
- this.events = $({});
60
- /** @type {SpeechSynthesisVoice} */
61
- this.voice = null;
62
- // Listen for voice changes (fired by subclasses)
63
- this.events.on('voiceschanged', this.updateBestVoice);
64
- this.events.trigger('voiceschanged');
65
- }
66
-
67
- /**
68
- * @abstract
69
- * @return {boolean}
70
- */
71
- static isSupported() {
72
- throw new Error("Unimplemented abstract class");
73
- }
74
-
75
- /**
76
- * @abstract
77
- * @return {SpeechSynthesisVoice[]}
78
- */
79
- getVoices() {
80
- throw new Error("Unimplemented abstract class");
81
- }
82
-
83
- /** @abstract */
84
- init() {
85
- return null;
86
- }
87
- /**
88
- * @param {number} leafIndex
89
- * @param {number} numLeafs total number of leafs in the current book
90
- */
91
- start(leafIndex, numLeafs) {
92
- this.playing = true;
93
- this.paused = false;
94
- this.opts.onLoadingStart();
95
- this._chunkIterator = new PageChunkIterator(numLeafs, leafIndex, {
96
- server: this.opts.server,
97
- bookPath: this.opts.bookPath,
98
- pageBufferSize: 5
99
- });
100
- this.step();
101
- this.events.trigger('start');
102
- }
103
- stop() {
104
- if (this.activeSound) this.activeSound.stop();
105
- this.playing = false;
106
- this.paused = true;
107
- this._chunkIterator = null;
108
- this.activeSound = null;
109
- this.events.trigger('stop');
110
- }
111
-
112
- /** @public */
113
- pause() {
114
- var fireEvent = !this.paused && this.activeSound;
115
- this.paused = true;
116
- if (this.activeSound) this.activeSound.pause();
117
- if (fireEvent) this.events.trigger('pause');
118
- }
119
-
120
- /** @public */
121
- resume() {
122
- var fireEvent = this.paused && this.activeSound;
123
- this.paused = false;
124
- if (this.activeSound) this.activeSound.resume();
125
- if (fireEvent) this.events.trigger('resume');
126
- }
127
- togglePlayPause() {
128
- if (this.paused) this.resume();else this.pause();
129
- }
130
-
131
- /** @public */
132
- jumpForward() {
133
- if (this.activeSound) this.activeSound.finish();
134
- }
135
-
136
- /** @public */
137
- jumpBackward() {
138
- var _this = this;
139
- return _asyncToGenerator(function* () {
140
- yield Promise.all([_this.activeSound.stop(), _this._chunkIterator.decrement().then(() => _this._chunkIterator.decrement())]);
141
- _this.step();
142
- })();
143
- }
144
-
145
- /** @param {string} voiceURI */
146
- setVoice(voiceURI) {
147
- // if the user actively selects a voice, don't re-choose best voice anymore
148
- // MS Edge fires voices changed randomly very often
149
- this.events.off('voiceschanged', this.updateBestVoice);
150
- this.voice = this.getVoices().find(voice => voice.voiceURI === voiceURI);
151
- // if the current book has a language set, store the selected voice with the book language as a suffix
152
- if (this.opts.bookLanguage && hasLocalStorage()) {
153
- localStorage.setItem("BRtts-voice-".concat(this.opts.bookLanguage), this.voice.voiceURI);
154
- }
155
- if (this.activeSound) this.activeSound.setVoice(this.voice);
156
- }
157
-
158
- /** @param {number} newRate */
159
- setPlaybackRate(newRate) {
160
- this.playbackRate = newRate;
161
- if (this.activeSound) this.activeSound.setPlaybackRate(newRate);
162
- }
163
-
164
- /** @private */
165
- step() {
166
- var _this2 = this;
167
- return _asyncToGenerator(function* () {
168
- var chunk = yield _this2._chunkIterator.next();
169
- if (chunk == PageChunkIterator.AT_END) {
170
- _this2.stop();
171
- _this2.opts.onDone();
172
- return;
173
- }
174
- _this2.opts.onLoadingStart();
175
- var sound = _this2.createSound(chunk);
176
- sound.chunk = chunk;
177
- sound.rate = _this2.playbackRate;
178
- sound.voice = _this2.voice;
179
- sound.load(() => _this2.opts.onLoadingComplete());
180
- _this2.opts.onLoadingComplete();
181
- yield _this2.opts.beforeChunkPlay(chunk);
182
- if (!_this2.playing) return;
183
- var playPromise = yield _this2.playSound(sound).then(() => _this2.opts.afterChunkPlay(sound.chunk));
184
- if (_this2.paused) _this2.pause();
185
- yield playPromise;
186
- if (_this2.playing) return _this2.step();
187
- })();
188
- }
189
-
190
- /**
191
- * @abstract
192
- * @param {PageChunk} chunk
193
- * @return {AbstractTTSSound}
194
- */
195
- createSound(chunk) {
196
- throw new Error("Unimplemented abstract class");
197
- }
198
-
199
- /**
200
- * @param {AbstractTTSSound} sound
201
- * @return {PromiseLike} promise called once playing finished
202
- */
203
- playSound(sound) {
204
- this.activeSound = sound;
205
- if (!this.activeSound.loaded) this.opts.onLoadingStart();
206
- return this.activeSound.play();
207
- }
208
-
209
- /** Convenience wrapper for {@see AbstractTTSEngine.getBestVoice} */
210
- getBestVoice() {
211
- return AbstractTTSEngine.getBestBookVoice(this.getVoices(), this.opts.bookLanguage);
212
- }
213
-
214
- /**
215
- * @private
216
- * Find the best voice to use given the available voices, the book language, and the user's
217
- * languages.
218
- * @param {SpeechSynthesisVoice[]} voices
219
- * @param {ISO6391} bookLanguage
220
- * @param {string[]} userLanguages languages in BCP47 format (e.g. en-US). Ordered by preference.
221
- * @return {SpeechSynthesisVoice | undefined}
222
- */
223
- static getBestBookVoice(voices, bookLanguage) {
224
- var userLanguages = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : navigator.languages;
225
- var bookLangVoices = voices.filter(v => v.lang.startsWith(bookLanguage));
226
- // navigator.languages browser support isn't great yet, so get just 1 language otherwise
227
- // Sample navigator.languages: ["en-CA", "fr-CA", "fr", "en-US", "en", "de-DE", "de"]
228
- userLanguages = userLanguages || (navigator.language ? [navigator.language] : []);
229
-
230
- // user languages that match the book language
231
- var matchingUserLangs = userLanguages.filter(lang => lang.startsWith(bookLanguage));
232
-
233
- // First try to find the last chosen voice from localStorage for the current book language
234
- return AbstractTTSEngine.getMatchingStoredVoice(bookLangVoices, bookLanguage)
235
- // Try to find voices that intersect these two sets
236
- || AbstractTTSEngine.getMatchingVoice(matchingUserLangs, bookLangVoices)
237
- // no user languages match the books; let's return the best voice for the book language
238
- || bookLangVoices.find(v => v.default) || bookLangVoices[0]
239
- // No voices match the book language? let's find a voice in the user's language
240
- // and ignore book lang
241
- || AbstractTTSEngine.getMatchingVoice(userLanguages, voices)
242
- // C'mon! Ok, just read with whatever we got!
243
- || voices.find(v => v.default) || voices[0];
244
- }
245
-
246
- /**
247
- * @private
248
- * Get the voice last selected by the user for the book language from localStorage.
249
- * Returns undefined if no voice is stored or found.
250
- * @param {SpeechSynthesisVoice[]} voices browser voices to choose from
251
- * @param {ISO6391} bookLanguage book language to look for
252
- * @return {SpeechSynthesisVoice | undefined}
253
- */
254
- static getMatchingStoredVoice(voices, bookLanguage) {
255
- var storedVoice = hasLocalStorage() && localStorage.getItem("BRtts-voice-".concat(bookLanguage));
256
- return storedVoice ? voices.find(v => v.voiceURI === storedVoice) : undefined;
257
- }
258
-
259
- /**
260
- * @private
261
- * Get the best voice that matches one of the BCP47 languages (order by preference)
262
- * @param {string[]} languages in BCP 47 format (e.g. 'en-US', or 'en'); ordered by preference
263
- * @param {SpeechSynthesisVoice[]} voices voices to choose from
264
- * @return {SpeechSynthesisVoice | undefined}
265
- */
266
- static getMatchingVoice(languages, voices) {
267
- var _loop = function _loop(lang) {
268
- // Chrome Android was returning voice languages like `en_US` instead of `en-US`
269
- var matchingVoices = voices.filter(v => v.lang.replace('_', '-').startsWith(lang));
270
- if (matchingVoices.length) {
271
- return {
272
- v: matchingVoices.find(v => v.default) || matchingVoices[0]
273
- };
274
- }
275
- },
276
- _ret;
277
- for (var lang of languages) {
278
- _ret = _loop(lang);
279
- if (_ret) return _ret.v;
280
- }
281
- }
282
- }