@internetarchive/bookreader 5.0.0-38 → 5.0.0-39

Sign up to get free protection for your applications and to get access to all the features.
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
- };