@internetarchive/bookreader 5.0.0-88-alpha.8 → 5.0.0-88-alpha.10

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 (182) hide show
  1. package/dist/esm/BookNavigator/assets/bookmark-colors.js +4 -0
  2. package/dist/esm/BookNavigator/assets/button-base.js +4 -0
  3. package/dist/esm/BookNavigator/assets/ia-logo.js +4 -0
  4. package/dist/esm/BookNavigator/assets/icon_checkmark.js +8 -0
  5. package/dist/esm/BookNavigator/assets/icon_close.js +4 -0
  6. package/dist/esm/BookNavigator/book-navigator.js +612 -0
  7. package/dist/esm/BookNavigator/bookmarks/bookmark-button.js +35 -0
  8. package/dist/esm/BookNavigator/bookmarks/bookmark-edit.js +78 -0
  9. package/dist/esm/BookNavigator/bookmarks/bookmarks-list.js +160 -0
  10. package/dist/esm/BookNavigator/bookmarks/bookmarks-loginCTA.js +24 -0
  11. package/dist/esm/BookNavigator/bookmarks/bookmarks-provider.js +55 -0
  12. package/dist/esm/BookNavigator/bookmarks/ia-bookmarks.js +521 -0
  13. package/dist/esm/BookNavigator/delete-modal-actions.js +29 -0
  14. package/dist/esm/BookNavigator/downloads/downloads-provider.js +84 -0
  15. package/dist/esm/BookNavigator/downloads/downloads.js +69 -0
  16. package/dist/esm/BookNavigator/search/search-provider.js +238 -0
  17. package/dist/esm/BookNavigator/search/search-results.js +161 -0
  18. package/dist/esm/BookNavigator/sharing.js +26 -0
  19. package/dist/esm/BookNavigator/viewable-files.js +94 -0
  20. package/dist/esm/BookNavigator/visual-adjustments/visual-adjustments-provider.js +83 -0
  21. package/dist/esm/BookNavigator/visual-adjustments/visual-adjustments.js +131 -0
  22. package/dist/esm/BookReader/BookModel.js +575 -0
  23. package/dist/esm/BookReader/DragScrollable.js +224 -0
  24. package/dist/esm/BookReader/ImageCache.js +122 -0
  25. package/dist/esm/BookReader/Mode1Up.js +114 -0
  26. package/dist/esm/BookReader/Mode1UpLit.js +579 -0
  27. package/dist/esm/BookReader/Mode2Up.js +106 -0
  28. package/dist/esm/BookReader/Mode2UpLit.js +1020 -0
  29. package/dist/esm/BookReader/ModeCoordinateSpace.js +28 -0
  30. package/dist/esm/BookReader/ModeSmoothZoom.js +318 -0
  31. package/dist/esm/BookReader/ModeThumb.js +366 -0
  32. package/dist/esm/BookReader/Navbar/Navbar.js +253 -0
  33. package/dist/esm/BookReader/PageContainer.js +165 -0
  34. package/dist/esm/BookReader/ReduceSet.js +27 -0
  35. package/dist/esm/BookReader/Toolbar/Toolbar.js +242 -0
  36. package/dist/esm/BookReader/events.js +20 -0
  37. package/dist/esm/BookReader/options.js +331 -0
  38. package/dist/esm/BookReader/utils/HTMLDimensionsCacher.js +48 -0
  39. package/dist/esm/BookReader/utils/ScrollClassAdder.js +31 -0
  40. package/dist/esm/BookReader/utils/SelectionObserver.js +42 -0
  41. package/dist/esm/BookReader/utils/classes.js +37 -0
  42. package/dist/esm/BookReader/utils.js +315 -0
  43. package/dist/esm/BookReader.js +1827 -0
  44. package/dist/esm/assets/icons/1up.svg +12 -0
  45. package/dist/esm/assets/icons/2up.svg +15 -0
  46. package/dist/esm/assets/icons/advance.svg +26 -0
  47. package/dist/esm/assets/icons/chevron-right.svg +1 -0
  48. package/dist/esm/assets/icons/close-circle-dark.svg +1 -0
  49. package/dist/esm/assets/icons/close-circle.svg +1 -0
  50. package/dist/esm/assets/icons/fullscreen.svg +17 -0
  51. package/dist/esm/assets/icons/fullscreen_exit.svg +17 -0
  52. package/dist/esm/assets/icons/hamburger.svg +15 -0
  53. package/dist/esm/assets/icons/left-arrow.svg +12 -0
  54. package/dist/esm/assets/icons/magnify-minus.svg +12 -0
  55. package/dist/esm/assets/icons/magnify-plus.svg +13 -0
  56. package/dist/esm/assets/icons/magnify.svg +15 -0
  57. package/dist/esm/assets/icons/pause.svg +23 -0
  58. package/dist/esm/assets/icons/play.svg +22 -0
  59. package/dist/esm/assets/icons/playback-speed.svg +34 -0
  60. package/dist/esm/assets/icons/read-aloud.svg +22 -0
  61. package/dist/esm/assets/icons/review.svg +22 -0
  62. package/dist/esm/assets/icons/thumbnails.svg +17 -0
  63. package/dist/esm/assets/icons/voice.svg +1 -0
  64. package/dist/esm/assets/icons/volume-full.svg +22 -0
  65. package/dist/esm/assets/images/BRicons.png +0 -0
  66. package/dist/esm/assets/images/BRicons.svg +94 -0
  67. package/dist/esm/assets/images/BRicons_ia.png +0 -0
  68. package/dist/esm/assets/images/back_pages.png +0 -0
  69. package/dist/esm/assets/images/book_bottom_icon.png +0 -0
  70. package/dist/esm/assets/images/book_down_icon.png +0 -0
  71. package/dist/esm/assets/images/book_left_icon.png +0 -0
  72. package/dist/esm/assets/images/book_leftmost_icon.png +0 -0
  73. package/dist/esm/assets/images/book_right_icon.png +0 -0
  74. package/dist/esm/assets/images/book_rightmost_icon.png +0 -0
  75. package/dist/esm/assets/images/book_top_icon.png +0 -0
  76. package/dist/esm/assets/images/book_up_icon.png +0 -0
  77. package/dist/esm/assets/images/books_graphic.svg +177 -0
  78. package/dist/esm/assets/images/booksplit.png +0 -0
  79. package/dist/esm/assets/images/control_pause_icon.png +0 -0
  80. package/dist/esm/assets/images/control_play_icon.png +0 -0
  81. package/dist/esm/assets/images/embed_icon.png +0 -0
  82. package/dist/esm/assets/images/icon-home-ia.png +0 -0
  83. package/dist/esm/assets/images/icon_OL-logo-xs.png +0 -0
  84. package/dist/esm/assets/images/icon_alert-xs.png +0 -0
  85. package/dist/esm/assets/images/icon_book.svg +12 -0
  86. package/dist/esm/assets/images/icon_bookmark.svg +12 -0
  87. package/dist/esm/assets/images/icon_close-pop.png +0 -0
  88. package/dist/esm/assets/images/icon_download.png +0 -0
  89. package/dist/esm/assets/images/icon_gear.svg +14 -0
  90. package/dist/esm/assets/images/icon_hamburger.svg +20 -0
  91. package/dist/esm/assets/images/icon_home.png +0 -0
  92. package/dist/esm/assets/images/icon_home.svg +21 -0
  93. package/dist/esm/assets/images/icon_home_ia.png +0 -0
  94. package/dist/esm/assets/images/icon_indicator.png +0 -0
  95. package/dist/esm/assets/images/icon_info.svg +11 -0
  96. package/dist/esm/assets/images/icon_one_page.svg +8 -0
  97. package/dist/esm/assets/images/icon_pause.svg +1 -0
  98. package/dist/esm/assets/images/icon_play.svg +1 -0
  99. package/dist/esm/assets/images/icon_playback-rate.svg +15 -0
  100. package/dist/esm/assets/images/icon_return.png +0 -0
  101. package/dist/esm/assets/images/icon_search_button.svg +8 -0
  102. package/dist/esm/assets/images/icon_share.svg +9 -0
  103. package/dist/esm/assets/images/icon_skip-ahead.svg +6 -0
  104. package/dist/esm/assets/images/icon_skip-back.svg +13 -0
  105. package/dist/esm/assets/images/icon_speaker.svg +18 -0
  106. package/dist/esm/assets/images/icon_speaker_open.svg +10 -0
  107. package/dist/esm/assets/images/icon_thumbnails.svg +12 -0
  108. package/dist/esm/assets/images/icon_toc.svg +5 -0
  109. package/dist/esm/assets/images/icon_two_pages.svg +9 -0
  110. package/dist/esm/assets/images/icon_zoomer.png +0 -0
  111. package/dist/esm/assets/images/loading.gif +0 -0
  112. package/dist/esm/assets/images/logo_icon.png +0 -0
  113. package/dist/esm/assets/images/marker_chap-off.png +0 -0
  114. package/dist/esm/assets/images/marker_chap-off.svg +11 -0
  115. package/dist/esm/assets/images/marker_chap-off_ia.png +0 -0
  116. package/dist/esm/assets/images/marker_chap-on.png +0 -0
  117. package/dist/esm/assets/images/marker_chap-on.svg +11 -0
  118. package/dist/esm/assets/images/marker_srch-on.svg +11 -0
  119. package/dist/esm/assets/images/marker_srchchap-off.png +0 -0
  120. package/dist/esm/assets/images/marker_srchchap-on.png +0 -0
  121. package/dist/esm/assets/images/nav_control-dn.png +0 -0
  122. package/dist/esm/assets/images/nav_control-dn_ia.png +0 -0
  123. package/dist/esm/assets/images/nav_control-up.png +0 -0
  124. package/dist/esm/assets/images/nav_control-up_ia.png +0 -0
  125. package/dist/esm/assets/images/nav_control.png +0 -0
  126. package/dist/esm/assets/images/one_page_mode_icon.png +0 -0
  127. package/dist/esm/assets/images/paper-badge.png +0 -0
  128. package/dist/esm/assets/images/print_icon.png +0 -0
  129. package/dist/esm/assets/images/progressbar.gif +0 -0
  130. package/dist/esm/assets/images/right_edges.png +0 -0
  131. package/dist/esm/assets/images/slider.png +0 -0
  132. package/dist/esm/assets/images/slider_ia.png +0 -0
  133. package/dist/esm/assets/images/thumbnail_mode_icon.png +0 -0
  134. package/dist/esm/assets/images/transparent.png +0 -0
  135. package/dist/esm/assets/images/two_page_mode_icon.png +0 -0
  136. package/dist/esm/assets/images/unviewable_page.png +0 -0
  137. package/dist/esm/assets/images/zoom_in_icon.png +0 -0
  138. package/dist/esm/assets/images/zoom_out_icon.png +0 -0
  139. package/dist/esm/css/BookReader.scss +85 -0
  140. package/dist/esm/css/_BRBookmarks.scss +29 -0
  141. package/dist/esm/css/_BRComponent.scss +13 -0
  142. package/dist/esm/css/_BRfloat.scss +197 -0
  143. package/dist/esm/css/_BRicon.scss +54 -0
  144. package/dist/esm/css/_BRmain.scss +262 -0
  145. package/dist/esm/css/_BRnav.scss +354 -0
  146. package/dist/esm/css/_BRpages.scss +213 -0
  147. package/dist/esm/css/_BRsearch.scss +268 -0
  148. package/dist/esm/css/_BRtoolbar.scss +84 -0
  149. package/dist/esm/css/_BRvendor.scss +5 -0
  150. package/dist/esm/css/_TextSelection.scss +108 -0
  151. package/dist/esm/css/_colorbox.scss +52 -0
  152. package/dist/esm/css/_controls.scss +257 -0
  153. package/dist/esm/css/_icons.scss +121 -0
  154. package/dist/esm/ia-bookreader/ia-bookreader.js +141 -0
  155. package/dist/esm/jquery-wrapper.js +3 -0
  156. package/dist/esm/plugins/plugin.archive_analytics.js +72 -0
  157. package/dist/esm/plugins/plugin.autoplay.js +119 -0
  158. package/dist/esm/plugins/plugin.chapters.js +288 -0
  159. package/dist/esm/plugins/plugin.iframe.js +44 -0
  160. package/dist/esm/plugins/plugin.iiif.js +146 -0
  161. package/dist/esm/plugins/plugin.resume.js +66 -0
  162. package/dist/esm/plugins/plugin.text_selection.js +621 -0
  163. package/dist/esm/plugins/plugin.vendor-fullscreen.js +227 -0
  164. package/dist/esm/plugins/search/plugin.search.js +499 -0
  165. package/dist/esm/plugins/search/utils.js +42 -0
  166. package/dist/esm/plugins/search/view.js +360 -0
  167. package/dist/esm/plugins/tts/AbstractTTSEngine.js +282 -0
  168. package/dist/esm/plugins/tts/FestivalTTSEngine.js +192 -0
  169. package/dist/esm/plugins/tts/PageChunk.js +105 -0
  170. package/dist/esm/plugins/tts/PageChunkIterator.js +155 -0
  171. package/dist/esm/plugins/tts/WebTTSEngine.js +364 -0
  172. package/dist/esm/plugins/tts/plugin.tts.js +315 -0
  173. package/dist/esm/plugins/tts/tooltip_dict.js +14 -0
  174. package/dist/esm/plugins/tts/utils.js +79 -0
  175. package/dist/esm/plugins/url/UrlPlugin.js +197 -0
  176. package/dist/esm/plugins/url/plugin.url.js +212 -0
  177. package/dist/esm/util/browserSniffing.js +56 -0
  178. package/dist/esm/util/debouncer.js +25 -0
  179. package/dist/esm/util/docCookies.js +75 -0
  180. package/dist/esm/util/strings.js +34 -0
  181. package/jsconfig.json +1 -0
  182. package/package.json +1 -7
@@ -0,0 +1,366 @@
1
+ // @ts-check
2
+ import { notInArray, clamp } from './utils.js';
3
+ import { EVENTS } from './events.js';
4
+ import { DragScrollable } from './DragScrollable.js';
5
+ /** @typedef {import('../BookREader.js').default} BookReader */
6
+ /** @typedef {import('./BookModel.js').PageIndex} PageIndex */
7
+ /** @typedef {import('./BookModel.js').BookModel} BookModel */
8
+
9
+ /** @typedef {JQuery} $lazyLoadImgPlaceholder * jQuery element with data attributes: leaf, reduce */
10
+
11
+ export class ModeThumb {
12
+ /**
13
+ * @param {BookReader} br
14
+ * @param {BookModel} bookModel
15
+ */
16
+ constructor(br, bookModel) {
17
+ this.br = br;
18
+ this.book = bookModel;
19
+ }
20
+
21
+ /**
22
+ * Draws the thumbnail view
23
+ * @param {number} [seekIndex] If seekIndex is defined, the view will be drawn
24
+ * with that page visible (without any animated scrolling).
25
+ *
26
+ * Creates place holder for image to load after gallery has been drawn
27
+ */
28
+ drawLeafs(seekIndex) {
29
+ var _this = this;
30
+ var {
31
+ floor
32
+ } = Math;
33
+ var {
34
+ book
35
+ } = this;
36
+ var viewWidth = this.br.refs.$brContainer.prop('scrollWidth') - 20; // width minus buffer
37
+
38
+ var leafHeight;
39
+ var rightPos = 0;
40
+ var bottomPos = 0;
41
+ var maxRight = 0;
42
+ var currentRow = 0;
43
+ var leafIndex = 0;
44
+ /** @type {Array<{ leafs?: Array<{num: PageIndex, left: number}>, height?: number, top?: number }>} */
45
+ var leafMap = [];
46
+
47
+ // Will be set to top of requested seek index, if set
48
+ var seekTop;
49
+
50
+ // Calculate the position of every thumbnail. $$$ cache instead of calculating on every draw
51
+ // make `leafMap`
52
+ for (var page of book.pagesIterator({
53
+ combineConsecutiveUnviewables: true
54
+ })) {
55
+ var leafWidth = this.br.thumbWidth;
56
+ if (rightPos + (leafWidth + this.br.thumbPadding) > viewWidth) {
57
+ currentRow++;
58
+ rightPos = 0;
59
+ leafIndex = 0;
60
+ }
61
+
62
+ // Init current row in leafMap
63
+ if (!leafMap[currentRow]) {
64
+ leafMap[currentRow] = {};
65
+ }
66
+ if (!leafMap[currentRow].leafs) {
67
+ leafMap[currentRow].leafs = [];
68
+ leafMap[currentRow].height = 0;
69
+ leafMap[currentRow].top = 0;
70
+ }
71
+ leafMap[currentRow].leafs[leafIndex] = {
72
+ num: page.index,
73
+ left: rightPos
74
+ };
75
+ leafHeight = floor(page.height * this.br.thumbWidth / page.width);
76
+ if (leafHeight > leafMap[currentRow].height) {
77
+ leafMap[currentRow].height = leafHeight;
78
+ }
79
+ if (leafIndex === 0) {
80
+ bottomPos += this.br.thumbPadding + leafMap[currentRow].height;
81
+ }
82
+ rightPos += leafWidth + this.br.thumbPadding;
83
+ if (rightPos > maxRight) {
84
+ maxRight = rightPos;
85
+ }
86
+ leafIndex++;
87
+ if (page.index == seekIndex) {
88
+ seekTop = bottomPos - this.br.thumbPadding - leafMap[currentRow].height;
89
+ }
90
+ }
91
+
92
+ // reset the bottom position based on thumbnails
93
+ this.br.refs.$brPageViewEl.height(bottomPos);
94
+ var pageViewBuffer = floor((this.br.refs.$brContainer.prop('scrollWidth') - maxRight) / 2) - 14;
95
+
96
+ // If seekTop is defined, seeking was requested and target found
97
+ if (typeof seekTop != 'undefined') {
98
+ this.br.refs.$brContainer.scrollTop(seekTop);
99
+ }
100
+ var scrollTop = this.br.refs.$brContainer.prop('scrollTop');
101
+ var scrollBottom = scrollTop + this.br.refs.$brContainer.height();
102
+ var leafTop = 0;
103
+ var leafBottom = 0;
104
+ var rowsToDisplay = [];
105
+ var imagesToDisplay = [];
106
+
107
+ // Visible leafs with least/greatest index
108
+ var leastVisible = book.getNumLeafs() - 1;
109
+ var mostVisible = 0;
110
+
111
+ // Determine the thumbnails in view
112
+ for (var i = 0; i < leafMap.length; i++) {
113
+ if (!leafMap[i]) {
114
+ continue;
115
+ }
116
+ leafBottom += this.br.thumbPadding + leafMap[i].height;
117
+ var topInView = leafTop >= scrollTop && leafTop <= scrollBottom;
118
+ var bottomInView = leafBottom >= scrollTop && leafBottom <= scrollBottom;
119
+ var middleInView = leafTop <= scrollTop && leafBottom >= scrollBottom;
120
+ if (topInView || bottomInView || middleInView) {
121
+ rowsToDisplay.push(i);
122
+ if (leafMap[i].leafs[0].num < leastVisible) {
123
+ leastVisible = leafMap[i].leafs[0].num;
124
+ }
125
+ if (leafMap[i].leafs[leafMap[i].leafs.length - 1].num > mostVisible) {
126
+ mostVisible = leafMap[i].leafs[leafMap[i].leafs.length - 1].num;
127
+ }
128
+ }
129
+ if (leafTop > leafMap[i].top) {
130
+ leafMap[i].top = leafTop;
131
+ }
132
+ leafTop = leafBottom;
133
+ }
134
+ // at this point, `rowsToDisplay` now has all the rows in view
135
+
136
+ // create a buffer of preloaded rows before and after the visible rows
137
+ var firstRow = rowsToDisplay[0];
138
+ var lastRow = rowsToDisplay[rowsToDisplay.length - 1];
139
+ for (var _i = 1; _i < this.br.thumbRowBuffer + 1; _i++) {
140
+ if (lastRow + _i < leafMap.length) {
141
+ rowsToDisplay.push(lastRow + _i);
142
+ }
143
+ }
144
+ for (var _i2 = 1; _i2 < this.br.thumbRowBuffer; _i2++) {
145
+ if (firstRow - _i2 >= 0) {
146
+ rowsToDisplay.push(firstRow - _i2);
147
+ }
148
+ }
149
+ rowsToDisplay.sort((a, b) => a - b);
150
+
151
+ // Create the thumbnail divs and images (lazy loaded)
152
+ for (var row of rowsToDisplay) {
153
+ if (notInArray(row, this.br.displayedRows)) {
154
+ if (!leafMap[row]) {
155
+ continue;
156
+ }
157
+ var _loop = function _loop(leaf) {
158
+ var leafWidth = _this.br.thumbWidth;
159
+ var leafHeight = floor(book.getPageHeight(leaf) * _this.br.thumbWidth / book.getPageWidth(leaf));
160
+ var leafTop = leafMap[row].top;
161
+ var left = leafLeft + pageViewBuffer;
162
+ if ('rl' == _this.br.pageProgression) {
163
+ left = viewWidth - leafWidth - left;
164
+ }
165
+ left += _this.br.thumbPadding;
166
+ imagesToDisplay.push(leaf);
167
+
168
+ /* get thumbnail's reducer */
169
+ var idealReduce = floor(book.getPageWidth(leaf) / _this.br.thumbWidth);
170
+ var nearestFactor2 = 2 * Math.round(idealReduce / 2);
171
+ var thumbReduce = nearestFactor2;
172
+ var pageContainer = _this.br._createPageContainer(leaf).update({
173
+ dimensions: {
174
+ width: leafWidth,
175
+ height: leafHeight,
176
+ top: leafTop,
177
+ left
178
+ },
179
+ reduce: thumbReduce
180
+ });
181
+ pageContainer.$container.data('leaf', leaf).on('mouseup', event => {
182
+ // We want to suppress the fragmentChange triggers in `updateFirstIndex` and `switchMode`
183
+ // because otherwise it repeatedly triggers listeners and we get in an infinite loop.
184
+ // We manually trigger the `fragmentChange` once at the end.
185
+ _this.br.updateFirstIndex(leaf, {
186
+ suppressFragmentChange: true
187
+ });
188
+ // as per request in webdev-4042, we want to switch 1-up mode while clicking on thumbnail leafs
189
+ _this.br.switchMode(_this.br.constMode1up, {
190
+ suppressFragmentChange: true
191
+ });
192
+
193
+ // shift viewModeOrder after clicking on thumbsnail leaf
194
+ var nextModeID = _this.br.viewModeOrder.shift();
195
+ _this.br.viewModeOrder.push(nextModeID);
196
+ _this.br._components.navbar.updateViewModeButton($('.viewmode'), 'twopg', 'Two-page view');
197
+ _this.br.trigger(EVENTS.fragmentChange);
198
+ event.stopPropagation();
199
+ });
200
+ _this.br.refs.$brPageViewEl.append(pageContainer.$container);
201
+ };
202
+ for (var {
203
+ num: leaf,
204
+ left: leafLeft
205
+ } of leafMap[row].leafs) {
206
+ _loop(leaf);
207
+ }
208
+ }
209
+ }
210
+
211
+ // Remove thumbnails that are not to be displayed
212
+ for (var _row of this.br.displayedRows) {
213
+ if (notInArray(_row, rowsToDisplay)) {
214
+ for (var {
215
+ num: index
216
+ } of (_leafMap$_row = leafMap[_row]) === null || _leafMap$_row === void 0 ? void 0 : _leafMap$_row.leafs) {
217
+ var _leafMap$_row;
218
+ if (!(imagesToDisplay !== null && imagesToDisplay !== void 0 && imagesToDisplay.includes(index))) {
219
+ var _this$br$$;
220
+ (_this$br$$ = this.br.$(".pagediv".concat(index))) === null || _this$br$$ === void 0 || _this$br$$.remove();
221
+ }
222
+ }
223
+ }
224
+ }
225
+
226
+ // Update which page is considered current to make sure a visible page is the current one
227
+ var currentIndex = this.br.currentIndex();
228
+ if (currentIndex < leastVisible) {
229
+ this.br.updateFirstIndex(leastVisible);
230
+ } else if (currentIndex > mostVisible) {
231
+ this.br.updateFirstIndex(mostVisible);
232
+ }
233
+
234
+ // remember what rows are displayed
235
+ this.br.displayedRows = rowsToDisplay.slice();
236
+
237
+ // remove previous highlights
238
+ this.br.$('.BRpagedivthumb_highlight').removeClass('BRpagedivthumb_highlight');
239
+
240
+ // highlight current page
241
+ this.br.$('.pagediv' + this.br.currentIndex()).addClass('BRpagedivthumb_highlight');
242
+ }
243
+
244
+ /**
245
+ * Replaces placeholder image with real one
246
+ *
247
+ * @param {$lazyLoadImgPlaceholder} imgPlaceholder
248
+ */
249
+ lazyLoadImage(imgPlaceholder) {
250
+ var leaf = $(imgPlaceholder).data('leaf');
251
+ var reduce = $(imgPlaceholder).data('reduce');
252
+ var $img = this.br.imageCache.image(leaf, reduce);
253
+ var $parent = $(imgPlaceholder).parent();
254
+ /* March 16, 2021 (isa) - manually append & remove, `replaceWith` currently loses closure scope */
255
+ $($parent).append($img);
256
+ $(imgPlaceholder).remove();
257
+ }
258
+
259
+ /**
260
+ * @param {'in' | 'out'} direction
261
+ */
262
+ zoom(direction) {
263
+ var oldColumns = this.br.thumbColumns;
264
+ switch (direction) {
265
+ case 'in':
266
+ this.br.thumbColumns -= 1;
267
+ break;
268
+ case 'out':
269
+ this.br.thumbColumns += 1;
270
+ break;
271
+ default:
272
+ console.error("Unsupported direction: ".concat(direction));
273
+ }
274
+
275
+ // Limit zoom in/out columns
276
+ this.br.thumbColumns = clamp(this.br.thumbColumns, this.br.options.thumbMinZoomColumns, this.br.options.thumbMaxZoomColumns);
277
+ if (this.br.thumbColumns != oldColumns) {
278
+ this.br.displayedRows = []; /* force a gallery redraw */
279
+ this.prepare();
280
+ }
281
+ }
282
+
283
+ /**
284
+ * Returns the width per thumbnail to display the requested number of columns
285
+ * Note: #BRpageview must already exist since its width is used to calculate the
286
+ * thumbnail width
287
+ * @param {number} thumbnailColumns
288
+ */
289
+ getThumbnailWidth(thumbnailColumns) {
290
+ var DEFAULT_THUMBNAIL_WIDTH = 100;
291
+ var padding = (thumbnailColumns + 1) * this.br.thumbPadding;
292
+ var width = (this.br.refs.$brPageViewEl.width() - padding) / (thumbnailColumns + 0.5); // extra 0.5 is for some space at sides
293
+ var idealThumbnailWidth = Math.floor(width);
294
+ return idealThumbnailWidth > 0 ? idealThumbnailWidth : DEFAULT_THUMBNAIL_WIDTH;
295
+ }
296
+ prepare() {
297
+ this.br.refs.$brContainer.empty();
298
+ this.br.refs.$brContainer.css({
299
+ overflowY: 'scroll',
300
+ overflowX: 'auto'
301
+ });
302
+ this.br.refs.$brPageViewEl = $("<div class='BRpageview'></div>");
303
+ this.br.refs.$brContainer.append(this.br.refs.$brPageViewEl);
304
+ this.dragScrollable = this.dragScrollable || new DragScrollable(this.br.refs.$brContainer[0], {
305
+ preventDefault: true
306
+ });
307
+ this.br.bindGestures(this.br.refs.$brContainer);
308
+
309
+ // $$$ keep select enabled for now since disabling it breaks keyboard
310
+ // nav in FF 3.6 (https://bugs.edge.launchpad.net/bookreader/+bug/544666)
311
+ // disableSelect(this.br.$('#BRpageview'));
312
+ this.br.thumbWidth = this.getThumbnailWidth(this.br.thumbColumns);
313
+ this.br.reduce = this.book.getPageWidth(0) / this.br.thumbWidth;
314
+ this.br.displayedRows = [];
315
+ // Draw leafs with current index directly in view (no animating to the index)
316
+ this.drawLeafs(this.br.currentIndex());
317
+ this.br.updateBrClasses();
318
+ }
319
+
320
+ /**
321
+ * @param {PageIndex} index
322
+ */
323
+ jumpToIndex(index) {
324
+ var {
325
+ floor
326
+ } = Math;
327
+ var {
328
+ book
329
+ } = this;
330
+ var viewWidth = this.br.refs.$brContainer.prop('scrollWidth') - 20; // width minus buffer
331
+ var leafWidth = this.br.thumbWidth;
332
+ var leafTop = 0;
333
+ var rightPos = 0;
334
+ var bottomPos = 0;
335
+ var rowHeight = 0;
336
+ var leafIndex = 0;
337
+ for (var i = 0; i <= index; i++) {
338
+ if (rightPos + (leafWidth + this.br.thumbPadding) > viewWidth) {
339
+ rightPos = 0;
340
+ rowHeight = 0;
341
+ leafIndex = 0;
342
+ }
343
+ var leafHeight = floor(book.getPageHeight(leafIndex) * this.br.thumbWidth / book.getPageWidth(leafIndex));
344
+ if (leafHeight > rowHeight) {
345
+ rowHeight = leafHeight;
346
+ }
347
+ if (leafIndex == 0) {
348
+ leafTop = bottomPos;
349
+ bottomPos += this.br.thumbPadding + rowHeight;
350
+ }
351
+ rightPos += leafWidth + this.br.thumbPadding;
352
+ leafIndex++;
353
+ }
354
+ this.br.updateFirstIndex(index);
355
+ if (this.br.refs.$brContainer.prop('scrollTop') == leafTop) {
356
+ this.br.drawLeafs();
357
+ } else {
358
+ this.br.animating = true;
359
+ this.br.refs.$brContainer.stop(true).animate({
360
+ scrollTop: leafTop
361
+ }, 'fast', () => {
362
+ this.br.animating = false;
363
+ });
364
+ }
365
+ }
366
+ }
@@ -0,0 +1,253 @@
1
+ /** @typedef {import("../../BookReader.js").default} BookReader */
2
+
3
+ import 'jquery-ui/ui/widget.js';
4
+ import 'jquery-ui/ui/widgets/mouse.js';
5
+ import 'jquery-ui/ui/widgets/slider.js';
6
+ import { EVENTS } from '../events.js';
7
+ import { throttle } from '../utils.js';
8
+ export class Navbar {
9
+ /**
10
+ * @param {BookReader} br
11
+ */
12
+ constructor(br) {
13
+ this.br = br;
14
+
15
+ /** @type {JQuery} */
16
+ this.$root = null;
17
+ /** @type {JQuery} */
18
+ this.$nav = null;
19
+ /** @type {number} */
20
+ this.maxPageNum = null;
21
+
22
+ /** @type {Object} controls will be switch over "this.maximumControls" */
23
+ this.minimumControls = ['viewmode'];
24
+ /** @type {Object} controls will be switch over "this.minimumControls" */
25
+ this.maximumControls = ['book_left', 'book_right', 'zoom_in', 'zoom_out', 'onepg', 'twopg', 'thumb'];
26
+ this.updateNavIndexThrottled = throttle(this.updateNavIndex.bind(this), 250, false);
27
+ }
28
+ controlFor(controlName) {
29
+ var option = this.br.options.controls[controlName];
30
+ if (!option.visible) {
31
+ return '';
32
+ }
33
+ if (option.template) {
34
+ return "<li>".concat(option.template(this.br), "</li>");
35
+ }
36
+ return "<li>\n <button class=\"BRicon ".concat(option.className, "\" title=\"").concat(option.label, "\">\n <div class=\"icon icon-").concat(option.iconClassName, "\"></div>\n <span class=\"BRtooltip\">").concat(option.label, "</span>\n </button>\n </li>");
37
+ }
38
+
39
+ /** @private */
40
+ _renderControls() {
41
+ return ['bookLeft', 'bookRight', 'onePage', 'twoPage', 'thumbnail', 'viewmode', 'zoomOut', 'zoomIn', 'fullScreen'].map(mode => this.controlFor(mode)).join('');
42
+ }
43
+
44
+ /** @private */
45
+ _bindViewModeButton() {
46
+ var {
47
+ br
48
+ } = this;
49
+ var viewModeOptions = br.options.controls.viewmode;
50
+ var viewModes = [{
51
+ mode: br.constMode1up,
52
+ className: 'onepg',
53
+ title: 'One-page view'
54
+ }, {
55
+ mode: br.constMode2up,
56
+ className: 'twopg',
57
+ title: 'Two-page view'
58
+ }, {
59
+ mode: br.constModeThumb,
60
+ className: 'thumb',
61
+ title: 'Thumbnail view'
62
+ }].filter(mode => !viewModeOptions.excludedModes.includes(mode.mode));
63
+ var viewModeOrder = viewModes.map(m => m.mode);
64
+ if (viewModeOptions.excludedModes.includes(br.mode)) {
65
+ br.switchMode(viewModeOrder[0]);
66
+ }
67
+
68
+ // Reorder the viewModeOrder so the current view mode is at the end
69
+ var currentModeIndex = viewModeOrder.indexOf(br.mode);
70
+ for (var i = 0; i <= currentModeIndex; i++) {
71
+ viewModeOrder.push(viewModeOrder.shift());
72
+ }
73
+ if (viewModes.length < 2) {
74
+ this.$nav.find(".".concat(viewModeOptions.className)).remove();
75
+ }
76
+ this.br.bind(EVENTS.PostInit, () => {
77
+ var $button = this.$nav.find(".".concat(viewModeOptions.className)).off('.bindNavigationHandlers').on('click', e => {
78
+ var nextModeID = viewModeOrder.shift();
79
+ var newViewMode = viewModes.find(m => m.mode === nextModeID);
80
+ var nextViewMode = viewModes.find(m => m.mode === viewModeOrder[0]);
81
+ viewModeOrder.push(nextModeID);
82
+ br.viewModeOrder = viewModeOrder;
83
+ this.updateViewModeButton($(e.currentTarget), nextViewMode.className, nextViewMode.title);
84
+ br.switchMode(newViewMode.mode);
85
+ });
86
+ var currentViewModeButton = viewModes.find(m => m.mode === viewModeOrder[0]);
87
+ this.updateViewModeButton($button, currentViewModeButton.className, currentViewModeButton.title);
88
+ });
89
+ }
90
+
91
+ /**
92
+ * Toggle viewmode button to change page view
93
+ */
94
+ updateViewModeButton($button, iconClass, tooltipText) {
95
+ $button.attr('title', tooltipText).find('.icon').removeClass().addClass("icon icon-".concat(iconClass)).end().find('.BRtooltip').text(tooltipText);
96
+ }
97
+
98
+ /**
99
+ * Switch navbar controls on mobile and desktop
100
+ */
101
+ switchNavbarControls() {
102
+ // we don't want navbar controls switching with liner-notes
103
+ if (this.br.options.bookType !== 'linerNotes') {
104
+ if (this.br.refs.$brContainer.prop('clientWidth') < 640) {
105
+ this.showMinimumNavbarControls();
106
+ } else {
107
+ this.showMaximumNavbarControls();
108
+ }
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Switch Book Navbar controls to minimised
114
+ * NOTE: only `this.minimumControls` and `this.maximumControls` switch on resize
115
+ */
116
+ showMinimumNavbarControls() {
117
+ this.minimumControls.forEach(control => {
118
+ var element = document.querySelector(".controls .".concat(control));
119
+ if (element) element.classList.remove('hide');
120
+ });
121
+ this.maximumControls.forEach(control => {
122
+ var element = document.querySelector(".controls .".concat(control));
123
+ if (element) element.classList.add('hide');
124
+ });
125
+ }
126
+
127
+ /**
128
+ * Switch Book Navbar controls to maximized
129
+ * NOTE: only `this.minimumControls` and `this.maximumControls` switch on resize
130
+ */
131
+ showMaximumNavbarControls() {
132
+ this.maximumControls.forEach(control => {
133
+ var element = document.querySelector(".controls .".concat(control));
134
+ if (element) element.classList.remove('hide');
135
+ });
136
+ this.minimumControls.forEach(control => {
137
+ var element = document.querySelector(".controls .".concat(control));
138
+ if (element) element.classList.add('hide');
139
+ });
140
+ }
141
+
142
+ /**
143
+ * Initialize the navigation bar (bottom)
144
+ * @return {JQuery}
145
+ */
146
+ init() {
147
+ var {
148
+ br
149
+ } = this;
150
+ var {
151
+ navbarTitle: title
152
+ } = br.options;
153
+ var isRTL = br.pageProgression === 'rl';
154
+ var bookFlipLeft = isRTL ? 'book_flip_next' : 'book_flip_prev';
155
+ var bookFlipRight = isRTL ? 'book_flip_prev' : 'book_flip_next';
156
+ this.br.options.controls['bookLeft'].className = "book_left ".concat(bookFlipLeft);
157
+ this.br.options.controls['bookRight'].className = "book_right ".concat(bookFlipRight);
158
+ br.refs.$BRfooter = this.$root = $("<div class=\"BRfooter\"></div>");
159
+ br.refs.$BRnav = this.$nav = $("<div class=\"BRnav BRnavDesktop\">\n ".concat(title ? "<div class=\"BRnavTitle\">".concat(title, "</div>") : '', "\n <nav class=\"BRcontrols\">\n <ul class=\"controls\">\n <li class=\"scrubber\">\n <div class=\"BRnavpos\">\n <div class=\"BRpager\"></div>\n <div class=\"BRnavline\"></div>\n </div>\n <p><span class='BRcurrentpage'></span></p>\n </li>\n ").concat(this._renderControls(), "\n </ul>\n </nav>\n </div>"));
160
+ this.$root.append(this.$nav);
161
+ br.refs.$br.append(this.$root);
162
+ var $slider = this.$root.find('.BRpager').slider({
163
+ animate: true,
164
+ min: 0,
165
+ max: br.book.getNumLeafs() - 1,
166
+ value: br.currentIndex(),
167
+ range: "min"
168
+ });
169
+ $slider.on('slide', (event, ui) => {
170
+ this.updateNavPageNum(ui.value);
171
+ return true;
172
+ });
173
+ $slider.on('slidechange', (event, ui) => {
174
+ this.updateNavPageNum(ui.value);
175
+ // recursion prevention for jumpToIndex
176
+ if ($slider.data('swallowchange')) {
177
+ $slider.data('swallowchange', false);
178
+ } else {
179
+ br.jumpToIndex(ui.value);
180
+ }
181
+ return true;
182
+ });
183
+ br.options.controls.viewmode.visible && this._bindViewModeButton();
184
+ this.updateNavPageNum(br.currentIndex());
185
+ return this.$nav;
186
+ }
187
+
188
+ /**
189
+ * Returns the textual representation of the current page for the navbar
190
+ * @param {number} index
191
+ * @return {string}
192
+ */
193
+ getNavPageNumString(index) {
194
+ var {
195
+ br
196
+ } = this;
197
+ // Accessible index starts at 0 (alas) so we add 1 to make human
198
+ var pageNum = br.book.getPageNum(index);
199
+ var pageType = br.book.getPageProp(index, 'pageType');
200
+ var numLeafs = br.book.getNumLeafs();
201
+ if (!this.maxPageNum) {
202
+ // Calculate Max page num (used for pagination display)
203
+ var maxPageNum = 0;
204
+ var pageNumVal;
205
+ for (var i = 0; i < numLeafs; i++) {
206
+ pageNumVal = parseFloat(br.book.getPageNum(i));
207
+ if (!isNaN(pageNumVal) && pageNumVal > maxPageNum) {
208
+ maxPageNum = pageNumVal;
209
+ }
210
+ }
211
+ this.maxPageNum = maxPageNum;
212
+ }
213
+ return getNavPageNumHtml(index, numLeafs, pageNum, pageType, this.maxPageNum);
214
+ }
215
+
216
+ /**
217
+ * Renders the navbar string to the DOM
218
+ * @param {number} index
219
+ */
220
+ updateNavPageNum(index) {
221
+ this.$root.find('.BRcurrentpage').html(this.getNavPageNumString(index));
222
+ }
223
+
224
+ /**
225
+ * Update the nav bar display - does not cause navigation.
226
+ * @param {number} index
227
+ */
228
+ updateNavIndex(index) {
229
+ // We want to update the value, but normally moving the slider
230
+ // triggers jumpToIndex which triggers this method
231
+ index = index !== undefined ? index : this.br.currentIndex();
232
+ this.$root.find('.BRpager').data('swallowchange', true).slider('value', index);
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Renders the html for the page string
238
+ * @param {number} index
239
+ * @param {number} numLeafs
240
+ * @param {number|string} pageNum
241
+ * @param {*} pageType - Deprecated
242
+ * @param {number} maxPageNum
243
+ * @return {string}
244
+ */
245
+ export function getNavPageNumHtml(index, numLeafs, pageNum, pageType, maxPageNum) {
246
+ var pageIsAsserted = pageNum[0] != 'n';
247
+ if (!pageIsAsserted) {
248
+ var pageIndex = index + 1;
249
+ return "(".concat(pageIndex, " of ").concat(numLeafs, ")"); // Page (8 of 10)
250
+ }
251
+ var bookLengthLabel = maxPageNum && parseFloat(pageNum) ? " of ".concat(maxPageNum) : '';
252
+ return "".concat(pageNum).concat(bookLengthLabel);
253
+ }