@internetarchive/bookreader 5.0.0-38 → 5.0.0-39

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 (222) hide show
  1. package/BookReader/BookReader.css +8 -0
  2. package/BookReader/BookReader.js +1 -1
  3. package/BookReader/BookReader.js.map +1 -1
  4. package/BookReader/ia-bookreader-bundle.js +99 -75
  5. package/BookReader/ia-bookreader-bundle.js.map +1 -1
  6. package/BookReader/icons/magnify-minus.svg +1 -1
  7. package/BookReader/icons/magnify-plus.svg +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.chapters.js +1 -1
  11. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  12. package/BookReader/plugins/plugin.mobile_nav.js +1 -1
  13. package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
  14. package/BookReader/plugins/plugin.resume.js +1 -1
  15. package/BookReader/plugins/plugin.resume.js.map +1 -1
  16. package/BookReader/plugins/plugin.search.js +1 -1
  17. package/BookReader/plugins/plugin.search.js.map +1 -1
  18. package/BookReader/plugins/plugin.text_selection.js +1 -1
  19. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  20. package/BookReader/plugins/plugin.tts.js +1 -1
  21. package/BookReader/plugins/plugin.tts.js.map +1 -1
  22. package/BookReader/plugins/plugin.url.js +1 -1
  23. package/BookReader/plugins/plugin.url.js.map +1 -1
  24. package/CHANGELOG.md +5 -0
  25. package/README.md +13 -0
  26. package/package.json +14 -14
  27. package/renovate.json +1 -1
  28. package/src/BookReader/Mode1UpLit.js +7 -1
  29. package/src/BookReader/Mode2Up.js +11 -0
  30. package/src/BookReader/ModeSmoothZoom.js +2 -0
  31. package/src/BookReader/PageContainer.js +10 -4
  32. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  33. package/src/assets/icons/magnify-minus.svg +3 -7
  34. package/src/assets/icons/magnify-plus.svg +3 -7
  35. package/src/css/_TextSelection.scss +13 -0
  36. package/tests/jest/BookReader/PageContainer.test.js +5 -4
  37. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  38. package/.husky/_/husky.sh +0 -30
  39. package/stat/BookNavigator/BookModel.js +0 -14
  40. package/stat/BookNavigator/BookNavigator.js +0 -524
  41. package/stat/BookNavigator/assets/bookmark-colors.js +0 -15
  42. package/stat/BookNavigator/assets/button-base.js +0 -61
  43. package/stat/BookNavigator/assets/ia-logo.js +0 -17
  44. package/stat/BookNavigator/assets/icon_checkmark.js +0 -6
  45. package/stat/BookNavigator/assets/icon_close.js +0 -3
  46. package/stat/BookNavigator/assets/icon_sort_asc.js +0 -5
  47. package/stat/BookNavigator/assets/icon_sort_desc.js +0 -5
  48. package/stat/BookNavigator/assets/icon_sort_neutral.js +0 -5
  49. package/stat/BookNavigator/assets/icon_volumes.js +0 -11
  50. package/stat/BookNavigator/bookmarks/bookmark-button.js +0 -64
  51. package/stat/BookNavigator/bookmarks/bookmark-edit.js +0 -215
  52. package/stat/BookNavigator/bookmarks/bookmarks-list.js +0 -285
  53. package/stat/BookNavigator/bookmarks/bookmarks-loginCTA.js +0 -28
  54. package/stat/BookNavigator/bookmarks/bookmarks-provider.js +0 -56
  55. package/stat/BookNavigator/bookmarks/ia-bookmarks.js +0 -523
  56. package/stat/BookNavigator/br-fullscreen-mgr.js +0 -82
  57. package/stat/BookNavigator/delete-modal-actions.js +0 -49
  58. package/stat/BookNavigator/downloads/downloads-provider.js +0 -72
  59. package/stat/BookNavigator/downloads/downloads.js +0 -139
  60. package/stat/BookNavigator/provider-config.js +0 -0
  61. package/stat/BookNavigator/search/a-search-result.js +0 -55
  62. package/stat/BookNavigator/search/search-provider.js +0 -180
  63. package/stat/BookNavigator/search/search-results.js +0 -360
  64. package/stat/BookNavigator/sharing.js +0 -31
  65. package/stat/BookNavigator/visual-adjustments/visual-adjustments-provider.js +0 -94
  66. package/stat/BookNavigator/visual-adjustments/visual-adjustments.js +0 -280
  67. package/stat/BookNavigator/volumes/volumes-provider.js +0 -83
  68. package/stat/BookNavigator/volumes/volumes.js +0 -178
  69. package/stat/BookReader/BookModel.js +0 -518
  70. package/stat/BookReader/DebugConsole.js +0 -54
  71. package/stat/BookReader/DragScrollable.js +0 -233
  72. package/stat/BookReader/ImageCache.js +0 -116
  73. package/stat/BookReader/Mode1Up.js +0 -102
  74. package/stat/BookReader/Mode1UpLit.js +0 -434
  75. package/stat/BookReader/Mode2Up.js +0 -1372
  76. package/stat/BookReader/ModeSmoothZoom.js +0 -177
  77. package/stat/BookReader/ModeThumb.js +0 -344
  78. package/stat/BookReader/Navbar/Navbar.js +0 -310
  79. package/stat/BookReader/PageContainer.js +0 -120
  80. package/stat/BookReader/ReduceSet.js +0 -26
  81. package/stat/BookReader/Toolbar/Toolbar.js +0 -384
  82. package/stat/BookReader/events.js +0 -20
  83. package/stat/BookReader/options.js +0 -324
  84. package/stat/BookReader/utils/HTMLDimensionsCacher.js +0 -44
  85. package/stat/BookReader/utils/classes.js +0 -36
  86. package/stat/BookReader/utils.js +0 -240
  87. package/stat/BookReader.js +0 -2550
  88. package/stat/BookReaderComponent/BookReaderComponent.js +0 -117
  89. package/stat/assets/icons/1up.svg +0 -12
  90. package/stat/assets/icons/2up.svg +0 -15
  91. package/stat/assets/icons/advance.svg +0 -26
  92. package/stat/assets/icons/chevron-right.svg +0 -1
  93. package/stat/assets/icons/close-circle-dark.svg +0 -1
  94. package/stat/assets/icons/close-circle.svg +0 -1
  95. package/stat/assets/icons/fullscreen.svg +0 -17
  96. package/stat/assets/icons/fullscreen_exit.svg +0 -17
  97. package/stat/assets/icons/hamburger.svg +0 -15
  98. package/stat/assets/icons/left-arrow.svg +0 -12
  99. package/stat/assets/icons/magnify-minus.svg +0 -16
  100. package/stat/assets/icons/magnify-plus.svg +0 -17
  101. package/stat/assets/icons/magnify.svg +0 -15
  102. package/stat/assets/icons/pause.svg +0 -23
  103. package/stat/assets/icons/play.svg +0 -22
  104. package/stat/assets/icons/playback-speed.svg +0 -34
  105. package/stat/assets/icons/read-aloud.svg +0 -22
  106. package/stat/assets/icons/review.svg +0 -22
  107. package/stat/assets/icons/thumbnails.svg +0 -17
  108. package/stat/assets/icons/voice.svg +0 -1
  109. package/stat/assets/icons/volume-full.svg +0 -22
  110. package/stat/assets/images/BRicons.png +0 -0
  111. package/stat/assets/images/BRicons.svg +0 -94
  112. package/stat/assets/images/BRicons_ia.png +0 -0
  113. package/stat/assets/images/back_pages.png +0 -0
  114. package/stat/assets/images/book_bottom_icon.png +0 -0
  115. package/stat/assets/images/book_down_icon.png +0 -0
  116. package/stat/assets/images/book_left_icon.png +0 -0
  117. package/stat/assets/images/book_leftmost_icon.png +0 -0
  118. package/stat/assets/images/book_right_icon.png +0 -0
  119. package/stat/assets/images/book_rightmost_icon.png +0 -0
  120. package/stat/assets/images/book_top_icon.png +0 -0
  121. package/stat/assets/images/book_up_icon.png +0 -0
  122. package/stat/assets/images/books_graphic.svg +0 -177
  123. package/stat/assets/images/booksplit.png +0 -0
  124. package/stat/assets/images/control_pause_icon.png +0 -0
  125. package/stat/assets/images/control_play_icon.png +0 -0
  126. package/stat/assets/images/embed_icon.png +0 -0
  127. package/stat/assets/images/icon-home-ia.png +0 -0
  128. package/stat/assets/images/icon_OL-logo-xs.png +0 -0
  129. package/stat/assets/images/icon_alert-xs.png +0 -0
  130. package/stat/assets/images/icon_book.svg +0 -12
  131. package/stat/assets/images/icon_bookmark.svg +0 -12
  132. package/stat/assets/images/icon_close-pop.png +0 -0
  133. package/stat/assets/images/icon_download.png +0 -0
  134. package/stat/assets/images/icon_gear.svg +0 -14
  135. package/stat/assets/images/icon_hamburger.svg +0 -20
  136. package/stat/assets/images/icon_home.png +0 -0
  137. package/stat/assets/images/icon_home.svg +0 -21
  138. package/stat/assets/images/icon_home_ia.png +0 -0
  139. package/stat/assets/images/icon_indicator.png +0 -0
  140. package/stat/assets/images/icon_info.svg +0 -11
  141. package/stat/assets/images/icon_one_page.svg +0 -8
  142. package/stat/assets/images/icon_pause.svg +0 -1
  143. package/stat/assets/images/icon_play.svg +0 -1
  144. package/stat/assets/images/icon_playback-rate.svg +0 -15
  145. package/stat/assets/images/icon_return.png +0 -0
  146. package/stat/assets/images/icon_search_button.svg +0 -8
  147. package/stat/assets/images/icon_share.svg +0 -9
  148. package/stat/assets/images/icon_skip-ahead.svg +0 -6
  149. package/stat/assets/images/icon_skip-back.svg +0 -13
  150. package/stat/assets/images/icon_speaker.svg +0 -18
  151. package/stat/assets/images/icon_speaker_open.svg +0 -10
  152. package/stat/assets/images/icon_thumbnails.svg +0 -12
  153. package/stat/assets/images/icon_toc.svg +0 -5
  154. package/stat/assets/images/icon_two_pages.svg +0 -9
  155. package/stat/assets/images/icon_zoomer.png +0 -0
  156. package/stat/assets/images/loading.gif +0 -0
  157. package/stat/assets/images/logo_icon.png +0 -0
  158. package/stat/assets/images/marker_chap-off.png +0 -0
  159. package/stat/assets/images/marker_chap-off.svg +0 -11
  160. package/stat/assets/images/marker_chap-off_ia.png +0 -0
  161. package/stat/assets/images/marker_chap-on.png +0 -0
  162. package/stat/assets/images/marker_chap-on.svg +0 -11
  163. package/stat/assets/images/marker_srch-on.svg +0 -11
  164. package/stat/assets/images/marker_srchchap-off.png +0 -0
  165. package/stat/assets/images/marker_srchchap-on.png +0 -0
  166. package/stat/assets/images/nav_control-dn.png +0 -0
  167. package/stat/assets/images/nav_control-dn_ia.png +0 -0
  168. package/stat/assets/images/nav_control-up.png +0 -0
  169. package/stat/assets/images/nav_control-up_ia.png +0 -0
  170. package/stat/assets/images/nav_control.png +0 -0
  171. package/stat/assets/images/one_page_mode_icon.png +0 -0
  172. package/stat/assets/images/paper-badge.png +0 -0
  173. package/stat/assets/images/print_icon.png +0 -0
  174. package/stat/assets/images/progressbar.gif +0 -0
  175. package/stat/assets/images/right_edges.png +0 -0
  176. package/stat/assets/images/slider.png +0 -0
  177. package/stat/assets/images/slider_ia.png +0 -0
  178. package/stat/assets/images/thumbnail_mode_icon.png +0 -0
  179. package/stat/assets/images/transparent.png +0 -0
  180. package/stat/assets/images/two_page_mode_icon.png +0 -0
  181. package/stat/assets/images/zoom_in_icon.png +0 -0
  182. package/stat/assets/images/zoom_out_icon.png +0 -0
  183. package/stat/css/BookReader.scss +0 -89
  184. package/stat/css/_BRBookmarks.scss +0 -29
  185. package/stat/css/_BRComponent.scss +0 -13
  186. package/stat/css/_BRfloat.scss +0 -197
  187. package/stat/css/_BRicon.scss +0 -48
  188. package/stat/css/_BRmain.scss +0 -251
  189. package/stat/css/_BRnav.scss +0 -359
  190. package/stat/css/_BRpages.scss +0 -139
  191. package/stat/css/_BRsearch.scss +0 -226
  192. package/stat/css/_BRtoolbar.scss +0 -84
  193. package/stat/css/_BRvendor.scss +0 -5
  194. package/stat/css/_MobileNav.scss +0 -194
  195. package/stat/css/_TextSelection.scss +0 -32
  196. package/stat/css/_colorbox.scss +0 -52
  197. package/stat/css/_controls.scss +0 -253
  198. package/stat/css/_icons.scss +0 -121
  199. package/stat/jquery-wrapper.js +0 -4
  200. package/stat/plugins/plugin.archive_analytics.js +0 -86
  201. package/stat/plugins/plugin.autoplay.js +0 -129
  202. package/stat/plugins/plugin.chapters.js +0 -248
  203. package/stat/plugins/plugin.iframe.js +0 -48
  204. package/stat/plugins/plugin.mobile_nav.js +0 -288
  205. package/stat/plugins/plugin.resume.js +0 -68
  206. package/stat/plugins/plugin.text_selection.js +0 -291
  207. package/stat/plugins/plugin.url.js +0 -198
  208. package/stat/plugins/plugin.vendor-fullscreen.js +0 -247
  209. package/stat/plugins/search/plugin.search.js +0 -439
  210. package/stat/plugins/search/view.js +0 -439
  211. package/stat/plugins/tts/AbstractTTSEngine.js +0 -249
  212. package/stat/plugins/tts/FestivalTTSEngine.js +0 -169
  213. package/stat/plugins/tts/PageChunk.js +0 -107
  214. package/stat/plugins/tts/PageChunkIterator.js +0 -163
  215. package/stat/plugins/tts/WebTTSEngine.js +0 -357
  216. package/stat/plugins/tts/plugin.tts.js +0 -357
  217. package/stat/plugins/tts/tooltip_dict.js +0 -15
  218. package/stat/plugins/tts/utils.js +0 -91
  219. package/stat/util/browserSniffing.js +0 -30
  220. package/stat/util/debouncer.js +0 -26
  221. package/stat/util/docCookies.js +0 -67
  222. package/stat/util/strings.js +0 -34
@@ -1,247 +0,0 @@
1
- /* global BookReader */
2
-
3
- /**
4
- * Toggles browser's native fullscreen mode if available device is not mobile
5
- */
6
- if (!isMobile()) {
7
- const EVENT_NAMESPACE = '.bookreader_vendor-fullscreen';
8
-
9
- jQuery.extend(BookReader.defaultOptions, {
10
- /** @type {boolean} */
11
- enableVendorFullscreenPlugin: true
12
- });
13
-
14
- /** @override */
15
- BookReader.prototype.setup = (function(super_) {
16
- return function(options) {
17
- super_.call(this, options);
18
-
19
- this.isVendorFullscreenActive = false;
20
- };
21
- })(BookReader.prototype.setup);
22
-
23
- /** @override */
24
- BookReader.prototype.getInitialMode = (function(super_) {
25
- return function(params) {
26
- let nextMode = super_.call(this, params);
27
- if (this.isVendorFullscreenActive) {
28
- nextMode = this.constMode1up;
29
- }
30
- return nextMode;
31
- };
32
- })(BookReader.prototype.getInitialMode);
33
-
34
- /** @override */
35
- BookReader.prototype.init = (function(super_) {
36
- return function() {
37
- super_.call(this);
38
-
39
- if (!fullscreenAllowed()) {
40
- return;
41
- }
42
- // In fullscreen mode the colorbox and overlay need to be inside the fullscreen element to display properly.
43
- bindFullscreenChangeListener(this, (e) => {
44
- e.data.resize();
45
- e.data.updateBrClasses();
46
- const cboxOverlay = $('#cboxOverlay');
47
- const cbox = $('#colorbox');
48
- if (isFullscreenActive()) {
49
- // In full screen mode, the colorbox and overlay need
50
- // to be children of the fullscreen element to display properly.
51
- const $fullscreen = $(getFullscreenElement());
52
- $fullscreen.append(cboxOverlay).append(cbox);
53
- } else {
54
- // In non-fullscreen mode, the colorbox and overlay need
55
- // to be children of the main document body.
56
- $(document.body).append(cboxOverlay).append(cbox);
57
- }
58
- });
59
- };
60
- })(BookReader.prototype.init);
61
-
62
- /**
63
- * Start fullscreen mode
64
- */
65
- BookReader.prototype.enterFullWindow = function() {
66
- this.refs.$brContainer.css('opacity', 0);
67
-
68
- const windowWidth = $(window).width();
69
- if (windowWidth <= this.onePageMinBreakpoint) {
70
- this.switchMode(this.constMode1up);
71
- }
72
-
73
- this.isVendorFullscreenActive = true;
74
- this.updateBrClasses();
75
-
76
- this.resize();
77
- this.jumpToIndex(this.currentIndex());
78
-
79
- this.refs.$brContainer.animate({ opacity: 1 }, 400, 'linear');
80
-
81
- $(document).on(`keyup.${EVENT_NAMESPACE}`, e => {
82
- if (e.keyCode === 27) this.exitFullScreen();
83
- });
84
- };
85
-
86
- /**
87
- * Exit from fullscreen mode
88
- */
89
- BookReader.prototype.exitFullWindow = function() {
90
- this.refs.$brContainer.css('opacity', 0);
91
-
92
- $(document).off('keyup' + EVENT_NAMESPACE);
93
-
94
- this.isFullscreenActive = false;
95
- this.updateBrClasses();
96
-
97
- this.resize();
98
- this.refs.$brContainer.animate({ opacity: 1 }, 400, 'linear');
99
- };
100
-
101
- /**
102
- * Returns true if fullscreen mode is enabled
103
- *
104
- * @returns {boolean}
105
- */
106
- BookReader.prototype.isFullscreen = function() {
107
- return isFullscreenActive() || this.isVendorFullscreenActive;
108
- };
109
-
110
- /**
111
- * Toggle screen
112
- */
113
- BookReader.prototype.toggleFullscreen = function() {
114
- if (this.isFullscreen()) {
115
- if (fullscreenAllowed()) {
116
- exitFullscreen();
117
- } else {
118
- this.exitFullWindow();
119
- }
120
- } else {
121
- if (fullscreenAllowed()) {
122
- requestFullscreen(this.refs.$br[0]);
123
- } else {
124
- this.enterFullWindow();
125
- }
126
- }
127
- };
128
-
129
- /** @deprecated */
130
- BookReader.util.isMobile = isMobile;
131
-
132
- /** @deprecated */
133
- BookReader.util.getFullscreenElement = getFullscreenElement;
134
-
135
- /** @deprecated */
136
- BookReader.util.bindFullscreenChangeListener = bindFullscreenChangeListener;
137
-
138
- /** @deprecated */
139
- BookReader.util.fullscreenAllowed = fullscreenAllowed;
140
-
141
- /** @deprecated */
142
- BookReader.util.requestFullscreen = requestFullscreen;
143
-
144
- /** @deprecated */
145
- BookReader.util.exitFullscreen = exitFullscreen;
146
-
147
- /** @deprecated */
148
- BookReader.util.isFullscreenActive = isFullscreenActive;
149
- }
150
-
151
-
152
- /**
153
- * Returns the DOM element being used for fullscreen.
154
- *
155
- * @returns {HTMLElement}
156
- * @see https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/fullscreenElement
157
- */
158
- export function getFullscreenElement() {
159
- return document.fullscreenElement ||
160
- document.webkitFullscreenElement ||
161
- document.mozFullScreenElement ||
162
- document.msFullscreenElement;
163
- }
164
-
165
- /**
166
- * Returns true if the document is in fullscreen mode.
167
- *
168
- * @returns {boolean}
169
- */
170
- export function isFullscreenActive() {
171
- const fullscreenElement = getFullscreenElement();
172
- return fullscreenElement !== null && fullscreenElement !== undefined;
173
- }
174
-
175
- /**
176
- * Exits fullscreen mode.
177
- *
178
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/exitFullscreen
179
- */
180
- export function exitFullscreen() {
181
- if (document.exitFullscreen) {
182
- document.exitFullscreen();
183
- } else if (document.webkitExitFullscreen) {
184
- document.webkitExitFullscreen();
185
- } else if (document.mozCancelFullScreen) {
186
- document.mozCancelFullScreen();
187
- } else if (document.msExitFullscreen) {
188
- document.msExitFullscreen();
189
- }
190
- }
191
-
192
- /**
193
- * Requests fullscreen mode for the given element
194
- *
195
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullscreen
196
- */
197
- export function requestFullscreen(element) {
198
- if (element.requestFullscreen) {
199
- element.requestFullscreen();
200
- } else if (element.webkitRequestFullscreen) {
201
- element.webkitRequestFullscreen();
202
- } else if (element.mozRequestFullScreen) {
203
- element.mozRequestFullScreen();
204
- } else if (element.msRequestFullscreen) {
205
- element.msRequestFullscreen();
206
- }
207
- }
208
-
209
- /**
210
- * Returns true if fullscreen mode is allowed on this device and document.
211
- *
212
- * @returns {boolean}
213
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/fullscreenEnabled
214
- */
215
- export function fullscreenAllowed() {
216
- return (document.fullscreenEnabled ||
217
- document.webkitFullscreenEnabled ||
218
- document.mozFullScreenEnabled ||
219
- document.msFullScreenEnabled);
220
- }
221
-
222
- /**
223
- * jQuery-style binding to a fullscreenchange event.
224
- *
225
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/fullscreenchange_event
226
- */
227
- export function bindFullscreenChangeListener(
228
- data, fullscreenchangeListener
229
- ) {
230
- const event = 'fullscreenchange ';
231
- const vendor_prefixes = [
232
- 'webkit',
233
- 'moz',
234
- 'ms'
235
- ];
236
- const all_events = (event + vendor_prefixes.join(event) + event).trim();
237
- $(document).on(all_events, data, fullscreenchangeListener);
238
- }
239
-
240
- /**
241
- * Returns true if current device is mobile
242
- *
243
- * @returns {boolean}
244
- */
245
- export function isMobile() {
246
- return (typeof window.orientation !== 'undefined') || (navigator.userAgent.indexOf('IEMobile') !== -1);
247
- }
@@ -1,439 +0,0 @@
1
- /* global BookReader */
2
- /**
3
- * Plugin for Archive.org book search
4
- * NOTE: This script must be loaded AFTER `plugin.mobile_nav.js`
5
- * as it mutates mobile nav drawer
6
- *
7
- * Events fired at various points throughout search processing are published
8
- * on the document DOM element. These can be subscribed to using jQuery's event
9
- * binding method `$.fn.on`. All of the events are prefixed with a BookReader
10
- * namespace. The events are:
11
- *
12
- * @event BookReader:SearchStarted - When a search form is submitted, immediately
13
- * before an AJAX call is made to request search results
14
- * @event BookReader:SearchCallback - When the search AJAX call is returned and at
15
- * least one result is returned. The event callback receives an object
16
- * with the `results`, plugin `options`, and the BookReader `instance`
17
- * @event BookReader:SearchCallbackError - When the AJAX request returns an error.
18
- * Receives the `results` and `instance`
19
- * @event BookReader:SearchCallbackNotIndexed - When a message is received that
20
- * the book has not had OCR text indexed yet. Receives `instance`
21
- * @event BookReader:SearchCallbackEmpty - When no results found. Receives
22
- * `instance`
23
- * @event BookReader:SearchCanceled - When no results found. Receives
24
- * `instance`
25
- */
26
- import { renderBoxesInPageContainerLayer } from '../../BookReader/PageContainer.js';
27
- import SearchView from './view.js';
28
- /** @typedef {import('../../BookReader/PageContainer').PageContainer} PageContainer */
29
- /** @typedef {import('../../BookReader/BookModel').PageIndex} PageIndex */
30
-
31
- jQuery.extend(BookReader.defaultOptions, {
32
- server: 'ia600609.us.archive.org',
33
- bookId: '',
34
- subPrefix: '',
35
- bookPath: '',
36
- enableSearch: true,
37
- searchInsideUrl: '/fulltext/inside.php',
38
- initialSearchTerm: null,
39
- });
40
-
41
- /** @override */
42
- BookReader.prototype.setup = (function (super_) {
43
- return function (options) {
44
- super_.call(this, options);
45
-
46
- this.searchTerm = '';
47
- this.searchResults = null;
48
- this.searchInsideUrl = options.searchInsideUrl;
49
- this.enableSearch = options.enableSearch;
50
-
51
- // Base server used by some api calls
52
- this.bookId = options.bookId;
53
- this.server = options.server;
54
- this.subPrefix = options.subPrefix;
55
- this.bookPath = options.bookPath;
56
-
57
- this.searchXHR = null;
58
- this._cancelSearch.bind(this);
59
- this.cancelSearchRequest.bind(this);
60
-
61
- /** @type { {[pageIndex: number]: SearchInsideMatchBox[]} } */
62
- this._searchBoxesByIndex = {};
63
-
64
- if (this.searchView) { return; }
65
- this.searchView = new SearchView({
66
- br: this,
67
- searchCancelledCallback: () => {
68
- this._cancelSearch();
69
- this.trigger('SearchCanceled', { term: this.searchTerm, instance: this });
70
- }
71
- });
72
- };
73
- })(BookReader.prototype.setup);
74
-
75
- /** @override */
76
- BookReader.prototype.init = (function (super_) {
77
- return function () {
78
- super_.call(this);
79
-
80
- if (this.options.enableSearch && this.options.initialSearchTerm) {
81
- /**
82
- * this.search() take two parameter
83
- * 1. this.options.initialSearchTerm - search term
84
- * 2. {
85
- * goToFirstResult: this.options.goToFirstResult,
86
- * suppressFragmentChange: false // always want to change fragment in URL
87
- * }
88
- */
89
- this.search(
90
- this.options.initialSearchTerm,
91
- { goToFirstResult: this.options.goToFirstResult, suppressFragmentChange: false }
92
- );
93
- }
94
- };
95
- })(BookReader.prototype.init);
96
-
97
- /** @override */
98
- BookReader.prototype.buildToolbarElement = (function (super_) {
99
- return function () {
100
- const $el = super_.call(this);
101
- if (!this.enableSearch) { return; }
102
- if (this.searchView.dom.toolbarSearch) {
103
- $el.find('.BRtoolbarSectionInfo').after(this.searchView.dom.toolbarSearch);
104
- }
105
- return $el;
106
- };
107
- })(BookReader.prototype.buildToolbarElement);
108
-
109
- /** @override */
110
- BookReader.prototype._createPageContainer = (function (super_) {
111
- return function (index) {
112
- const pageContainer = super_.call(this, index);
113
- if (this.enableSearch && pageContainer.page && index in this._searchBoxesByIndex) {
114
- const pageIndex = pageContainer.page.index;
115
- renderBoxesInPageContainerLayer('searchHiliteLayer', this._searchBoxesByIndex[pageIndex], pageContainer.page, pageContainer.$container[0]);
116
- }
117
- return pageContainer;
118
- };
119
- })(BookReader.prototype._createPageContainer);
120
-
121
- /**
122
- * @typedef {object} SearchOptions
123
- * @property {boolean} goToFirstResult
124
- * @property {boolean} disablePopup
125
- * @property {(null|function)} error - @deprecated at v.5.0
126
- * @property {(null|function)} success - @deprecated at v.5.0
127
- */
128
-
129
- /**
130
- * Submits search request
131
- *
132
- * @param {string} term
133
- * @param {SearchOptions} overrides
134
- */
135
- BookReader.prototype.search = function(term = '', overrides = {}) {
136
- /** @type {SearchOptions} */
137
- const defaultOptions = {
138
- goToFirstResult: false, /* jump to the first result (default=false) */
139
- disablePopup: false, /* don't show the modal progress (default=false) */
140
- suppressFragmentChange: false, /* don't change the URL on initial load */
141
- error: null, /* optional error handler (default=null) */
142
- success: null, /* optional success handler (default=null) */
143
-
144
- };
145
- const options = jQuery.extend({}, defaultOptions, overrides);
146
- this.suppressFragmentChange = options.suppressFragmentChange;
147
-
148
- // strip slashes, since this goes in the url
149
- this.searchTerm = term.replace(/\//g, ' ');
150
-
151
- if (!options.suppressFragmentChange) {
152
- this.trigger(BookReader.eventNames.fragmentChange);
153
- }
154
-
155
- // Add quotes to the term. This is to compenstate for the backends default OR query
156
- // term = term.replace(/['"]+/g, '');
157
- // term = '"' + term + '"';
158
-
159
- // Remove the port and userdir
160
- const serverPath = this.server.replace(/:.+/, '');
161
- const baseUrl = `https://${serverPath}${this.searchInsideUrl}?`;
162
-
163
- // Remove subPrefix from end of path
164
- let path = this.bookPath;
165
- const subPrefixWithSlash = `/${this.subPrefix}`;
166
- if (this.bookPath.length - this.bookPath.lastIndexOf(subPrefixWithSlash) == subPrefixWithSlash.length) {
167
- path = this.bookPath.substr(0, this.bookPath.length - subPrefixWithSlash.length);
168
- }
169
-
170
- const urlParams = {
171
- item_id: this.bookId,
172
- doc: this.subPrefix,
173
- path,
174
- q: term,
175
- };
176
-
177
- // NOTE that the API does not expect / (slashes) to be encoded. (%2F) won't work
178
- const paramStr = $.param(urlParams).replace(/%2F/g, '/');
179
-
180
- const url = `${baseUrl}${paramStr}`;
181
-
182
- const cleanup = () => {
183
- this.searchXHR = null;
184
- window.BRSearchInProgress = () => {};
185
- };
186
-
187
- const processSearchResults = (searchInsideResults) => {
188
- if (!this.searchXHR) {
189
- return;
190
- }
191
- const responseHasError = searchInsideResults.error || !searchInsideResults.matches.length;
192
- const hasCustomError = typeof options.error === 'function';
193
- const hasCustomSuccess = typeof options.success === 'function';
194
-
195
- if (responseHasError) {
196
- hasCustomError
197
- ? options.error.call(this, searchInsideResults, options)
198
- : this.BRSearchCallbackError(searchInsideResults, options);
199
- } else {
200
- hasCustomSuccess
201
- ? options.success.call(this, searchInsideResults, options)
202
- : this.BRSearchCallback(searchInsideResults, options);
203
- }
204
- cleanup();
205
- };
206
-
207
- const beforeSend = (xhr) => {
208
- this.searchXHR = xhr;
209
- window.BRSearchInProgress = processSearchResults;
210
- };
211
-
212
- this.trigger('SearchStarted', { term: this.searchTerm, instance: this });
213
- return $.ajax({
214
- url: url,
215
- dataType: 'jsonp',
216
- beforeSend,
217
- jsonpCallback: 'BRSearchInProgress'
218
- }).then(processSearchResults);
219
- };
220
-
221
- /**
222
- * cancels AJAX Call
223
- * emits custom event
224
- */
225
- BookReader.prototype._cancelSearch = function () {
226
- this.searchXHR?.abort();
227
- this.searchView.clearSearchFieldAndResults(false);
228
- this.searchTerm = '';
229
- this.searchXHR = null;
230
- this.searchResults = [];
231
- window.BRSearchInProgress = () => {};
232
- };
233
-
234
- /**
235
- * External function to cancel search
236
- * checks for term & xhr in flight before running
237
- */
238
- BookReader.prototype.cancelSearchRequest = function () {
239
- if (this.searchXHR !== null) {
240
- this._cancelSearch();
241
- this.searchView.toggleSearchPending();
242
- this.trigger('SearchCanceled', { term: this.searchTerm, instance: this });
243
- }
244
- };
245
-
246
- /**
247
- * @typedef {object} SearchInsideMatchBox
248
- * @property {number} page
249
- * @property {number} r
250
- * @property {number} l
251
- * @property {number} b
252
- * @property {number} t
253
- * @property {HTMLDivElement} [div]
254
- */
255
-
256
- /**
257
- * @typedef {object} SearchInsideMatch
258
- * @property {string} text
259
- * @property {Array<{ page: number, boxes: SearchInsideMatchBox[] }>} par
260
- */
261
-
262
- /**
263
- * @typedef {object} SearchInsideResults
264
- * @property {string} error
265
- * @property {SearchInsideMatch[]} matches
266
- * @property {boolean} indexed
267
- */
268
-
269
- /**
270
- * Search Results return handler
271
- * @callback
272
- * @param {SearchInsideResults} results
273
- * @param {object} options
274
- * @param {boolean} options.goToFirstResult
275
- */
276
- BookReader.prototype.BRSearchCallback = function(results, options) {
277
- this.searchResults = results || [];
278
-
279
- this.updateSearchHilites();
280
- this.removeProgressPopup();
281
- if (options.goToFirstResult) {
282
- const pageIndex = this._models.book.leafNumToIndex(results.matches[0].par[0].page);
283
- this._searchPluginGoToResult(pageIndex);
284
- }
285
- this.trigger('SearchCallback', { results, options, instance: this });
286
- };
287
-
288
- /**
289
- * Main search results error handler
290
- * @callback
291
- * @param {SearchInsideResults} results
292
- */
293
- BookReader.prototype.BRSearchCallbackError = function(results) {
294
- this._BRSearchCallbackError(results);
295
- };
296
-
297
- /**
298
- * @private draws search results error
299
- * @callback
300
- * @param {SearchInsideResults} results
301
- * @param {jQuery} $el
302
- * @param {boolean} fade
303
- */
304
- BookReader.prototype._BRSearchCallbackError = function(results) {
305
- this.searchResults = results;
306
- const basePayload = {
307
- term: this.searchTerm,
308
- instance: this,
309
- };
310
- if (results.error) {
311
- const payload = Object.assign({}, basePayload, { results });
312
- this.trigger('SearchCallbackError', payload);
313
- } else if (0 == results.matches.length) {
314
- if (false === results.indexed) {
315
- this.trigger('SearchCallbackBookNotIndexed', basePayload);
316
- return;
317
- }
318
- this.trigger('SearchCallbackEmpty', basePayload);
319
- }
320
- };
321
-
322
- /**
323
- * updates search on-page highlights controller
324
- */
325
- BookReader.prototype.updateSearchHilites = function() {
326
- /** @type {SearchInsideMatch[]} */
327
- const matches = this.searchResults?.matches || [];
328
- /** @type { {[pageIndex: number]: SearchInsideMatch[]} } */
329
- const boxesByIndex = {};
330
-
331
- // Clear any existing svg layers
332
- this.removeSearchHilites();
333
-
334
- // Group by pageIndex
335
- for (const match of matches) {
336
- for (const box of match.par[0].boxes) {
337
- const pageIndex = this.leafNumToIndex(box.page);
338
- const pageMatches = boxesByIndex[pageIndex] || (boxesByIndex[pageIndex] = []);
339
- pageMatches.push(box);
340
- }
341
- }
342
-
343
- // update any already created pages
344
- for (const [pageIndexString, boxes] of Object.entries(boxesByIndex)) {
345
- const pageIndex = parseFloat(pageIndexString);
346
- const page = this._models.book.getPage(pageIndex);
347
- const pageContainers = this.getActivePageContainerElementsForIndex(pageIndex);
348
- pageContainers.forEach(container => renderBoxesInPageContainerLayer('searchHiliteLayer', boxes, page, container));
349
- }
350
-
351
- this._searchBoxesByIndex = boxesByIndex;
352
- };
353
-
354
- /**
355
- * remove search highlights
356
- */
357
- BookReader.prototype.removeSearchHilites = function() {
358
- $(this.getActivePageContainerElements()).find('.searchHiliteLayer').remove();
359
- };
360
-
361
- /**
362
- * @private
363
- * Goes to the page specified. If the page is not viewable, tries to load the page
364
- * FIXME Most of this logic is IA specific, and should be less integrated into here
365
- * or at least more configurable.
366
- * @param {PageIndex} pageIndex
367
- */
368
- BookReader.prototype._searchPluginGoToResult = async function (pageIndex) {
369
- const { book } = this._models;
370
- const page = book.getPage(pageIndex);
371
- let makeUnviewableAtEnd = false;
372
- if (!page.isViewable) {
373
- const resp = await fetch('/services/bookreader/request_page?' + new URLSearchParams({
374
- id: this.options.bookId,
375
- subprefix: this.options.subPrefix,
376
- leafNum: page.leafNum,
377
- })).then(r => r.json());
378
-
379
- for (const leafNum of resp.value) {
380
- book.getPage(book.leafNumToIndex(leafNum)).makeViewable();
381
- }
382
-
383
- // not able to show page; make the page viewable anyways so that it can
384
- // actually open. On IA, it has a fallback to a special error page.
385
- if (!resp.value.length) {
386
- book.getPage(pageIndex).makeViewable();
387
- makeUnviewableAtEnd = true;
388
- }
389
- }
390
- /* this updates the URL */
391
- this.suppressFragmentChange = false;
392
- this.jumpToIndex(pageIndex);
393
-
394
- // Reset it to unviewable if it wasn't resolved
395
- if (makeUnviewableAtEnd) {
396
- book.getPage(pageIndex).makeViewable(false);
397
- }
398
- };
399
-
400
- /**
401
- * Removes all search pins
402
- */
403
- BookReader.prototype.removeSearchResults = function(suppressFragmentChange = false) {
404
- this.removeSearchHilites(); //be sure to set all box.divs to null
405
- this.searchTerm = null;
406
- this.searchResults = null;
407
- if (!suppressFragmentChange) {
408
- this.trigger(BookReader.eventNames.fragmentChange);
409
- }
410
- };
411
-
412
- /**
413
- * Returns true if a search highlight is currently being displayed
414
- * @returns {boolean}
415
- */
416
- BookReader.prototype.searchHighlightVisible = function() {
417
- const results = this.searchResults;
418
- let visiblePages = [];
419
- if (null == results) return false;
420
-
421
- if (this.constMode2up == this.mode) {
422
- visiblePages = [this.twoPage.currentIndexL, this.twoPage.currentIndexR];
423
- } else if (this.constMode1up == this.mode) {
424
- visiblePages = [this.currentIndex()];
425
- } else {
426
- return false;
427
- }
428
-
429
- results.matches.some(match => {
430
- return match.par[0].boxes.some(box => {
431
- const pageIndex = this.leafNumToIndex(box.page);
432
- if (jQuery.inArray(pageIndex, visiblePages) >= 0) {
433
- return true;
434
- }
435
- });
436
- });
437
-
438
- return false;
439
- };