@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,1372 +0,0 @@
1
- // @ts-check
2
- // effect.js gives acces to extra easing function (e.g. easeInSine)
3
- import 'jquery-ui/ui/effect.js';
4
- import { clamp } from './utils.js';
5
- import { EVENTS } from './events.js';
6
- import { ModeSmoothZoom } from "./ModeSmoothZoom.js";
7
- import { HTMLDimensionsCacher } from './utils/HTMLDimensionsCacher.js';
8
- import { DragScrollable } from './DragScrollable.js';
9
-
10
- /** @typedef {import('../BookReader.js').default} BookReader */
11
- /** @typedef {import('./BookModel.js').BookModel} BookModel */
12
- /** @typedef {import('./BookModel.js').PageIndex} PageIndex */
13
- /** @typedef {import('./options.js').BookReaderOptions} BookReaderOptions */
14
- /** @typedef {import('./PageContainer.js').PageContainer} PageContainer */
15
- /** @typedef {import('./ModeSmoothZoom').SmoothZoomable} SmoothZoomable */
16
-
17
- /** @implements {SmoothZoomable} */
18
- export class Mode2Up {
19
- /**
20
- * @param {BookReader} br
21
- * @param {BookModel} bookModel
22
- */
23
- constructor(br, bookModel) {
24
- this.br = br;
25
- this.book = bookModel;
26
-
27
- /** @type {HTMLDivElement} */
28
- this.leafEdgeL = null;
29
- /** @type {HTMLDivElement} */
30
- this.leafEdgeR = null;
31
-
32
- /** @type {{ [index: number]: PageContainer }} */
33
- this.pageContainers = {};
34
-
35
- /** @type {ModeSmoothZoom} */
36
- this.smoothZoomer = null;
37
- this._scale = 1;
38
- this.scaleCenter = { x: 0.5, y: 0.5 };
39
- }
40
-
41
- get $container() {
42
- return this.br.refs.$brContainer[0];
43
- }
44
- get $visibleWorld() {
45
- return this.br.refs.$brTwoPageView?.[0];
46
- }
47
-
48
- get scale() { return this._scale; }
49
- set scale(newVal) {
50
- this.$visibleWorld.style.transform = `scale(${newVal})`;
51
- this.updateViewportOnZoom(newVal, this._scale);
52
- this._scale = newVal;
53
- }
54
-
55
- /**
56
- * @param {PageIndex} index
57
- */
58
- jumpToIndex(index) {
59
- // By checking against min/max we do nothing if requested index
60
- // is current
61
- if (index < Math.min(this.br.twoPage.currentIndexL, this.br.twoPage.currentIndexR)) {
62
- this.flipBackToIndex(index);
63
- } else if (index > Math.max(this.br.twoPage.currentIndexL, this.br.twoPage.currentIndexR)) {
64
- this.flipFwdToIndex(index);
65
- }
66
- }
67
-
68
- /**
69
- * Draws book spread,
70
- * sets event handlers,
71
- * sets: `this.br.displayedIndices`
72
- * updates toolbar zoom
73
- * Important: `this.br.refs.$brTwoPageView` parent container must be emptied before calling
74
- */
75
- drawLeafs() {
76
- const $twoPageViewEl = this.br.refs.$brTwoPageView;
77
- const indexL = this.br.twoPage.currentIndexL;
78
- const indexR = this.br.twoPage.currentIndexR;
79
-
80
- this.createPageContainer(indexL).$container
81
- .css(this.leftLeafCss)
82
- .appendTo($twoPageViewEl);
83
- this.createPageContainer(indexR).$container
84
- .css(this.rightLeafCss)
85
- .appendTo($twoPageViewEl);
86
-
87
- this.displayedIndices = [this.br.twoPage.currentIndexL, this.br.twoPage.currentIndexR];
88
- this.br.displayedIndices = this.displayedIndices;
89
- this.br.updateToolbarZoom(this.br.reduce);
90
- this.br.trigger('pageChanged');
91
- }
92
-
93
- /**
94
- * @param {1} direction
95
- */
96
- zoom(direction) {
97
- this.br.stopFlipAnimations();
98
-
99
- // Recalculate autofit factors
100
- this.calculateReductionFactors();
101
-
102
- // Get new zoom state
103
- const reductionFactor = this.br.nextReduce(this.br.reduce, direction, this.br.twoPage.reductionFactors);
104
- if ((this.br.reduce == reductionFactor.reduce) && (this.br.twoPage.autofit == reductionFactor.autofit)) {
105
- // Same zoom
106
- return;
107
- }
108
- this.br.twoPage.autofit = reductionFactor.autofit;
109
- this.br.reduce = reductionFactor.reduce;
110
- this.br.pageScale = this.br.reduce; // preserve current reduce
111
-
112
- // Preserve view center position
113
- const oldCenter = this.getViewCenter();
114
-
115
- // Prepare view with new center to minimize visual glitches
116
- const drawNewSpread = true;
117
- this.prepareTwoPageView(oldCenter.percentageX, oldCenter.percentageY, drawNewSpread);
118
- }
119
-
120
- /**
121
- * Resize spread containers, does not prefetch
122
- * uses `this.br.twoPage` properties
123
- */
124
- resizeSpread() {
125
- this.br.resizeBRcontainer(false); // no animation
126
- this.calculateSpreadSize();
127
-
128
- this.br.refs?.$brTwoPageView.css(this.mainContainerCss);
129
- this.centerView(); // let function self adjust
130
-
131
- $(this.br.twoPage.coverDiv).css(this.spreadCoverCss); // click sheath is memoized somehow
132
- const $spreadLayers = this.br.refs.$brTwoPageView;
133
-
134
- $spreadLayers.find('.BRleafEdgeR')?.css(this.leafEdgeRCss);
135
- $spreadLayers.find('.BRleafEdgeL')?.css(this.leafEdgeLCss);
136
- $spreadLayers.find('.BRgutter')?.css(this.spineCss);
137
-
138
- const indexL = this.br.twoPage.currentIndexL;
139
- const indexR = this.br.twoPage.currentIndexR;
140
- this.pageContainers[indexL].$container.css(this.leftLeafCss);
141
- this.pageContainers[indexR].$container.css(this.rightLeafCss);
142
- }
143
-
144
- /**
145
- * @param {number} centerPercentageX
146
- * @param {number} centerPercentageY
147
- * @param {Boolean} drawNewSpread
148
- */
149
- prepareTwoPageView(centerPercentageX, centerPercentageY, drawNewSpread = false) {
150
- // Some decisions about two page view:
151
- //
152
- // Both pages will be displayed at the same height, even if they were different physical/scanned
153
- // sizes. This simplifies the animation (from a design as well as technical standpoint). We
154
- // examine the page aspect ratios (in calculateSpreadSize) and use the page with the most "normal"
155
- // aspect ratio to determine the height.
156
- //
157
- // The two page view div is resized to keep the middle of the book in the middle of the div
158
- // even as the page sizes change. To e.g. keep the middle of the book in the middle of the BRcontent
159
- // div requires adjusting the offset of BRtwpageview and/or scrolling in BRcontent.
160
- const startingReduce = this.br.reduce;
161
- const startingIndices = this.br.displayedIndices;
162
-
163
- this.br.refs.$brContainer.empty();
164
- this.br.refs.$brContainer.css('overflow', 'auto');
165
-
166
- // We want to display two facing pages. We may be missing
167
- // one side of the spread because it is the first/last leaf,
168
- // foldouts, missing pages, etc
169
-
170
- const targetLeaf = clamp(this.br.firstIndex, this.br.firstDisplayableIndex(), this.br.lastDisplayableIndex());
171
- const currentSpreadIndices = this.book.getSpreadIndices(targetLeaf);
172
- this.br.twoPage.currentIndexL = currentSpreadIndices[0];
173
- this.br.twoPage.currentIndexR = currentSpreadIndices[1];
174
-
175
- this.calculateSpreadSize(); //sets this.br.reduce, twoPage.width, twoPage.height and others
176
-
177
- /* check if calculations have changed that warrant a new book draw */
178
- const sameReducer = startingReduce == this.br.reduce;
179
- const sameStart = startingIndices == this.br.displayedIndices;
180
- const hasNewDisplayPagesOrDimensions = !sameStart || (sameStart && !sameReducer);
181
-
182
- if (drawNewSpread || hasNewDisplayPagesOrDimensions) {
183
- this.prunePageContainers();
184
- this.prefetch();
185
- }
186
-
187
- // Add the two page view
188
- // $$$ Can we get everything set up and then append?
189
- this.br.refs.$brTwoPageView = this.br.refs.$brTwoPageView || $('<div class="BRtwopageview"></div>');
190
- const $twoPageViewEl = this.br.refs.$brTwoPageView;
191
- $twoPageViewEl.empty();
192
- $twoPageViewEl[0].style.transformOrigin = '0 0';
193
- this.br.refs.$brContainer.append($twoPageViewEl);
194
-
195
- // Attaches to first child, so must come after we add the page view
196
- this.dragScrollable = this.dragScrollable || new DragScrollable(this.br.refs.$brContainer[0], {
197
- preventDefault: true,
198
- // Only handle mouse events; let browser/HammerJS handle touch
199
- dragstart: 'mousedown',
200
- dragcontinue: 'mousemove',
201
- dragend: 'mouseup',
202
- });
203
-
204
- this.attachMouseHandlers();
205
-
206
- // $$$ calculate container size first
207
- this.br.refs?.$brTwoPageView.css(this.mainContainerCss);
208
-
209
- // This will trump the incoming coordinates
210
- // in order to center book when zooming out
211
- if (this.br.twoPage.totalWidth < this.br.refs.$brContainer.prop('clientWidth')) {
212
- centerPercentageX = 0.5;
213
- }
214
- if (this.br.twoPage.totalHeight < this.br.refs.$brContainer.prop('clientHeight')) {
215
- centerPercentageY = 0.5;
216
- }
217
-
218
- this.centerView(centerPercentageX, centerPercentageY);
219
-
220
- // then set
221
- this.br.twoPage.coverDiv = document.createElement('div');
222
- $(this.br.twoPage.coverDiv).attr('class', 'BRbookcover').css(this.spreadCoverCss).appendTo(this.br.refs.$brTwoPageView);
223
-
224
- this.leafEdgeR = document.createElement('div');
225
- this.leafEdgeR.className = 'BRleafEdgeR';
226
- $(this.leafEdgeR).css(this.leafEdgeRCss).appendTo(this.br.refs.$brTwoPageView);
227
-
228
- this.leafEdgeL = document.createElement('div');
229
- this.leafEdgeL.className = 'BRleafEdgeL';
230
- $(this.leafEdgeL).css(this.leafEdgeLCss).appendTo(this.br.refs.$brTwoPageView);
231
-
232
- const div = document.createElement('div');
233
- $(div).attr('class', 'BRgutter').css(this.spineCss).appendTo(this.br.refs.$brTwoPageView);
234
-
235
- this.preparePopUp();
236
-
237
- this.br.displayedIndices = [];
238
-
239
- this.drawLeafs();
240
- this.br.updateToolbarZoom(this.br.reduce);
241
- this.br.updateBrClasses();
242
-
243
- this.smoothZoomer = this.smoothZoomer || new ModeSmoothZoom(this);
244
- this.smoothZoomer.attach();
245
-
246
- this.htmlDimensionsCacher = this.htmlDimensionsCacher || new HTMLDimensionsCacher(this.$container);
247
- }
248
-
249
- unprepare() {
250
- // Mode2Up attaches these listeners to the main BR container, so we need to
251
- // detach these or it will cause issues for the other modes.
252
- this.smoothZoomer.detach();
253
- }
254
-
255
- /**
256
- * @param {number} newScale
257
- * @param {number} oldScale
258
- */
259
- updateViewportOnZoom(newScale, oldScale) {
260
- const container = this.br.refs.$brContainer[0];
261
- const { scrollTop: T, scrollLeft: L } = container;
262
- const W = this.htmlDimensionsCacher.clientWidth;
263
- const H = this.htmlDimensionsCacher.clientHeight;
264
-
265
- // Scale factor change
266
- const F = newScale / oldScale;
267
-
268
- // Where in the viewport the zoom is centered on
269
- const XPOS = this.scaleCenter.x;
270
- const YPOS = this.scaleCenter.y;
271
- const oldCenter = {
272
- x: L + XPOS * W,
273
- y: T + YPOS * H,
274
- };
275
- const newCenter = {
276
- x: F * oldCenter.x,
277
- y: F * oldCenter.y,
278
- };
279
- container.scrollTop = newCenter.y - YPOS * H;
280
- container.scrollLeft = newCenter.x - XPOS * W;
281
-
282
- // Also update the visible page containers to load in highres if necessary
283
- this.pageContainers[this.br.twoPage.currentIndexL]?.update({ reduce: this.br.reduce / newScale });
284
- this.pageContainers[this.br.twoPage.currentIndexR]?.update({ reduce: this.br.reduce / newScale });
285
- }
286
-
287
- prunePageContainers() {
288
- for (const index in this.pageContainers) {
289
- if ((index != this.br.twoPage.currentIndexL) && (index != this.br.twoPage.currentIndexR)) {
290
- $(this.pageContainers[index].$container).remove();
291
- }
292
- if ((index < this.br.twoPage.currentIndexL - 4) || (index > this.br.twoPage.currentIndexR + 4)) {
293
- delete this.pageContainers[index];
294
- }
295
- }
296
- }
297
-
298
- /**
299
- * This function prepares the "View Page n" popup that shows while the mouse is
300
- * over the left/right "stack of sheets" edges. It also binds the mouse
301
- * events for these divs.
302
- */
303
- preparePopUp() {
304
- this.br.twoPagePopUp = document.createElement('div');
305
- this.br.twoPagePopUp.className = 'BRtwoPagePopUp';
306
- $(this.br.twoPagePopUp).css({
307
- zIndex: '1000'
308
- }).appendTo(this.br.refs.$brContainer);
309
- $(this.br.twoPagePopUp).hide();
310
-
311
- const leafEdges = [
312
- {
313
- $leafEdge: $(this.leafEdgeL),
314
- /** @type {function(number): PageIndex} */
315
- jumpIndexForPageX: this.jumpIndexForLeftEdgePageX.bind(this),
316
- leftOffset: () => -$(this.br.twoPagePopUp).width() + 120,
317
- },
318
- {
319
- $leafEdge: $(this.leafEdgeR),
320
- /** @type {function(number): PageIndex} */
321
- jumpIndexForPageX: this.jumpIndexForRightEdgePageX.bind(this),
322
- leftOffset: () => -120,
323
- },
324
- ];
325
-
326
- for (const { $leafEdge, jumpIndexForPageX, leftOffset } of leafEdges) {
327
- $leafEdge.on('mouseenter', () => $(this.br.twoPagePopUp).show());
328
- $leafEdge.on('mouseleave', () => $(this.br.twoPagePopUp).hide());
329
-
330
- $leafEdge.on('click', e => {
331
- this.br.trigger(EVENTS.stop);
332
- this.br.jumpToIndex(jumpIndexForPageX(e.pageX));
333
- });
334
-
335
- $leafEdge.on('mousemove', e => {
336
- const jumpIndex = clamp(jumpIndexForPageX(e.pageX), 0, this.book.getNumLeafs() - 1);
337
- $(this.br.twoPagePopUp).text(`View ${this.book.getPageName(jumpIndex)}`);
338
-
339
- // $$$ TODO: Make sure popup is positioned so that it is in view
340
- // (https://bugs.edge.launchpad.net/gnubook/+bug/327456)
341
- $(this.br.twoPagePopUp).css({
342
- left: `${e.pageX - this.br.refs.$brContainer.offset().left + this.br.refs.$brContainer.scrollLeft() + leftOffset()}px`,
343
- top: `${e.pageY - this.br.refs.$brContainer.offset().top + this.br.refs.$brContainer.scrollTop()}px`
344
- });
345
- });
346
- }
347
- }
348
-
349
- setSpreadIndices() {
350
- const targetLeaf = clamp(this.br.firstIndex, this.br.firstDisplayableIndex(), this.br.lastDisplayableIndex());
351
- const currentSpreadIndices = this.book.getSpreadIndices(targetLeaf);
352
- this.br.twoPage.currentIndexL = currentSpreadIndices[0];
353
- this.br.twoPage.currentIndexR = currentSpreadIndices[1];
354
- }
355
-
356
- /**
357
- * Calculates 2-page spread dimensions based on this.br.twoPage.currentIndexL and
358
- * this.br.twoPage.currentIndexR
359
- * This function sets this.br.twoPage.height, twoPage.width
360
- */
361
- calculateSpreadSize() {
362
- const firstIndex = this.br.twoPage.currentIndexL;
363
- const secondIndex = this.br.twoPage.currentIndexR;
364
-
365
- // Calculate page sizes and total leaf width
366
- let spreadSize;
367
- if ( this.br.twoPage.autofit) {
368
- spreadSize = this.getIdealSpreadSize(firstIndex, secondIndex);
369
- } else {
370
- // set based on reduction factor
371
- spreadSize = this.getSpreadSizeFromReduce(firstIndex, secondIndex, this.br.reduce);
372
- }
373
- // Both pages together
374
- this.br.twoPage.height = spreadSize.height || 0;
375
- this.br.twoPage.width = spreadSize.width || 0;
376
-
377
- // Individual pages
378
- this.br.twoPage.scaledWL = this.getPageWidth(firstIndex) || 0;
379
- this.br.twoPage.scaledWR = this.getPageWidth(secondIndex) || 0;
380
-
381
- // Leaf edges
382
- this.br.twoPage.edgeWidth = spreadSize.totalLeafEdgeWidth; // The combined width of both edges
383
- this.br.twoPage.leafEdgeWidthL = this.br.leafEdgeWidth(this.br.twoPage.currentIndexL);
384
- this.br.twoPage.leafEdgeWidthR = this.br.twoPage.edgeWidth - this.br.twoPage.leafEdgeWidthL;
385
-
386
-
387
- // Book cover
388
- // The width of the book cover div. The combined width of both pages, twice the width
389
- // of the book cover internal padding (2*10) and the page edges
390
- this.br.twoPage.bookCoverDivWidth = this.coverWidth(this.br.twoPage.scaledWL + this.br.twoPage.scaledWR);
391
- // The height of the book cover div
392
- this.br.twoPage.bookCoverDivHeight = this.br.twoPage.height + 2 * this.br.twoPage.coverInternalPadding;
393
-
394
-
395
- // We calculate the total width and height for the div so that we can make the book
396
- // spine centered
397
- const leftGutterOffset = this.gutterOffsetForIndex(firstIndex);
398
- const leftWidthFromCenter = this.br.twoPage.scaledWL - leftGutterOffset + this.br.twoPage.leafEdgeWidthL;
399
- const rightWidthFromCenter = this.br.twoPage.scaledWR + leftGutterOffset + this.br.twoPage.leafEdgeWidthR;
400
- const largestWidthFromCenter = Math.max( leftWidthFromCenter, rightWidthFromCenter );
401
- this.br.twoPage.totalWidth = 2 * (largestWidthFromCenter + this.br.twoPage.coverInternalPadding + this.br.twoPage.coverExternalPadding);
402
- this.br.twoPage.totalHeight = this.br.twoPage.height + 2 * (this.br.twoPage.coverInternalPadding + this.br.twoPage.coverExternalPadding);
403
-
404
- // We want to minimize the unused space in two-up mode (maximize the amount of page
405
- // shown). We give width to the leaf edges and these widths change (though the sum
406
- // of the two remains constant) as we flip through the book. With the book
407
- // cover centered and fixed in the BRcontainer div the page images will meet
408
- // at the "gutter" which is generally offset from the center.
409
- this.br.twoPage.middle = this.br.twoPage.totalWidth >> 1;
410
- this.br.twoPage.gutter = this.br.twoPage.middle + this.gutterOffsetForIndex(firstIndex);
411
-
412
- // The left edge of the book cover moves depending on the width of the pages
413
- // $$$ change to getter
414
- this.br.twoPage.bookCoverDivLeft = this.br.twoPage.gutter - this.br.twoPage.scaledWL - this.br.twoPage.leafEdgeWidthL - this.br.twoPage.coverInternalPadding;
415
- // The top edge of the book cover stays a fixed distance from the top
416
- this.br.twoPage.bookCoverDivTop = this.br.twoPage.coverExternalPadding;
417
-
418
- // Book spine
419
- this.br.twoPage.bookSpineDivHeight = this.br.twoPage.height + 2 * this.br.twoPage.coverInternalPadding;
420
- this.br.twoPage.bookSpineDivLeft = this.br.twoPage.middle - (this.br.twoPage.bookSpineDivWidth >> 1);
421
- this.br.twoPage.bookSpineDivTop = this.br.twoPage.bookCoverDivTop;
422
-
423
- this.br.reduce = spreadSize.reduce < 0 ? this.br.reduce : spreadSize.reduce; // $$$ really set this here?
424
- }
425
-
426
- /**
427
- *
428
- * @param {number} firstIndex
429
- * @param {number} secondIndex
430
- * @return {{ width: number, height: number, totalLeafEdgeWidth: number, reduce: number}}
431
- */
432
- getIdealSpreadSize(firstIndex, secondIndex) {
433
- const ideal = {};
434
-
435
- // We check which page is closest to a "normal" page and use that to set the height
436
- // for both pages. This means that foldouts and other odd size pages will be displayed
437
- // smaller than the nominal zoom amount.
438
- const canon5Dratio = 1.5;
439
-
440
- const first = {
441
- height: this.book._getPageHeight(firstIndex),
442
- width: this.book._getPageWidth(firstIndex)
443
- };
444
-
445
- const second = {
446
- height: this.book._getPageHeight(secondIndex),
447
- width: this.book._getPageWidth(secondIndex)
448
- };
449
-
450
- const firstIndexRatio = first.height / first.width;
451
- const secondIndexRatio = second.height / second.width;
452
-
453
- let ratio;
454
- if (Math.abs(firstIndexRatio - canon5Dratio) < Math.abs(secondIndexRatio - canon5Dratio)) {
455
- ratio = firstIndexRatio;
456
- } else {
457
- ratio = secondIndexRatio;
458
- }
459
-
460
- const totalLeafEdgeWidth = Math.floor(this.book.getNumLeafs() * 0.1);
461
- const maxLeafEdgeWidth = Math.floor(this.br.refs.$brContainer.prop('clientWidth') * 0.1);
462
- ideal.totalLeafEdgeWidth = Math.min(totalLeafEdgeWidth, maxLeafEdgeWidth);
463
-
464
- const widthOutsidePages = 2 * (this.br.twoPage.coverInternalPadding + this.br.twoPage.coverExternalPadding) + ideal.totalLeafEdgeWidth;
465
- const heightOutsidePages = 2 * (this.br.twoPage.coverInternalPadding + this.br.twoPage.coverExternalPadding);
466
-
467
- ideal.width = (this.br.refs.$brContainer.width() - widthOutsidePages) >> 1;
468
- ideal.width = ideal.width > 10 ? ideal.width - 10 : 1; // $$$ fudge factor
469
-
470
- ideal.height = this.br.refs.$brContainer.height() - heightOutsidePages;
471
- ideal.height = ideal.height > 15 ? ideal.height - 15 : 1; // $$$ fudge factor
472
-
473
- if (ideal.height / ratio <= ideal.width) {
474
- //use height
475
- ideal.width = Math.floor(ideal.height / ratio) || 1;
476
- } else {
477
- //use width
478
- ideal.height = Math.floor(ideal.width * ratio) || 1;
479
- }
480
-
481
- // $$$ check this logic with large spreads
482
- ideal.reduce = Math.round(((first.height + second.height) / 2) / ideal.height);
483
-
484
- return ideal;
485
- }
486
-
487
- /**
488
- * Returns the spread size calculated from the reduction factor for the given pages
489
- * @param {number} firstIndex
490
- * @param {number} secondIndex
491
- * @return {Object}
492
- */
493
- getSpreadSizeFromReduce(firstIndex, secondIndex, reduce) {
494
- const spreadSize = {};
495
- // $$$ Scale this based on reduce?
496
- const totalLeafEdgeWidth = Math.floor(this.book.getNumLeafs() * 0.1);
497
- // $$$ Assumes leaf edge width constant at all zoom levels
498
- const maxLeafEdgeWidth = Math.floor(this.br.refs.$brContainer.prop('clientWidth') * 0.1);
499
- spreadSize.totalLeafEdgeWidth = Math.min(totalLeafEdgeWidth, maxLeafEdgeWidth);
500
-
501
- // $$$ Possibly incorrect -- we should make height "dominant"
502
- const nativeWidth = this.book._getPageWidth(firstIndex) + this.book._getPageWidth(secondIndex);
503
- const nativeHeight = this.book._getPageHeight(firstIndex) + this.book._getPageHeight(secondIndex);
504
- spreadSize.height = Math.floor( (nativeHeight / 2) / this.br.reduce );
505
- spreadSize.width = Math.floor( (nativeWidth / 2) / this.br.reduce );
506
- spreadSize.reduce = reduce;
507
-
508
- return spreadSize;
509
- }
510
-
511
- /**
512
- * Returns the current ideal reduction factor
513
- * @return {number}
514
- */
515
- getAutofitReduce() {
516
- const spreadSize = this.getIdealSpreadSize(this.br.twoPage.currentIndexL, this.br.twoPage.currentIndexR);
517
- return spreadSize.reduce;
518
- }
519
-
520
- /**
521
- * Returns true if the pages extend past the edge of the view
522
- * @deprecated slated for deprecation by v5.0.0
523
- * @return {boolean}
524
- */
525
- isZoomedIn() {
526
- let isZoomedIn = false;
527
- if (this.br.twoPage.autofit != 'auto') {
528
- if (this.br.reduce < this.getAutofitReduce()) {
529
- isZoomedIn = true;
530
- }
531
- }
532
- return isZoomedIn;
533
- }
534
-
535
- calculateReductionFactors() {
536
- this.br.twoPage.reductionFactors = this.br.reductionFactors.concat([
537
- {
538
- reduce: this.getIdealSpreadSize( this.br.twoPage.currentIndexL, this.br.twoPage.currentIndexR ).reduce,
539
- autofit: 'auto'
540
- }
541
- ]);
542
- this.br.twoPage.reductionFactors.sort(this.br._reduceSort);
543
- }
544
-
545
- /**
546
- * Set the cursor for two page view
547
- * @deprecated Since version 4.3.3. Will be deleted in version 5.0
548
- */
549
- setCursor() {
550
- console.warn('Call to deprecated method, Mode2Up.setCursor. No-op.');
551
- }
552
-
553
- /**
554
- * @param {Number|null} index to flip back one spread, pass index=null
555
- */
556
- flipBackToIndex(index) {
557
- if (this.br.constMode1up == this.br.mode) return;
558
- if (this.br.animating) return;
559
-
560
- if (null != this.br.leafEdgeTmp) {
561
- alert('error: leafEdgeTmp should be null!');
562
- return;
563
- }
564
-
565
- if (null == index) {
566
- const {currentIndexL, currentIndexR} = this.br.twoPage;
567
- const minDisplayedIndex = Math.min(currentIndexL, currentIndexR);
568
- const prev = this.book.getPage(minDisplayedIndex).findPrev({ combineConsecutiveUnviewables: true });
569
- if (!prev) return;
570
- index = prev.index;
571
- // Can only flip to a left page
572
- // (downstream code handles index = -1, so this is ok I guess)
573
- if (prev.pageSide == 'R') index--;
574
- }
575
-
576
- this.br.updateNavIndexThrottled(index);
577
-
578
- const previousIndices = this.book.getSpreadIndices(index);
579
-
580
- if (previousIndices[0] < this.br.firstDisplayableIndex() || previousIndices[1] < this.br.firstDisplayableIndex()) {
581
- return;
582
- }
583
-
584
- this.br.animating = true;
585
-
586
- if ('rl' != this.br.pageProgression) {
587
- // Assume LTR and we are going backward
588
- this.prepareFlipLeftToRight(previousIndices[0], previousIndices[1]);
589
- this.flipLeftToRight(previousIndices[0], previousIndices[1]);
590
- } else {
591
- // RTL and going backward
592
- this.prepareFlipRightToLeft(previousIndices[0], previousIndices[1]);
593
- this.flipRightToLeft(previousIndices[0], previousIndices[1]);
594
- }
595
- }
596
-
597
- /**
598
- * Flips the page on the left towards the page on the right
599
- * @param {number} newIndexL
600
- * @param {number} newIndexR
601
- */
602
- flipLeftToRight(newIndexL, newIndexR) {
603
- this.br.refs.$brContainer.addClass("BRpageFlipping");
604
- const leftLeaf = this.br.twoPage.currentIndexL;
605
-
606
- const oldLeafEdgeWidthL = this.br.leafEdgeWidth(this.br.twoPage.currentIndexL);
607
- const newLeafEdgeWidthL = this.br.leafEdgeWidth(newIndexL);
608
- const leafEdgeTmpW = oldLeafEdgeWidthL - newLeafEdgeWidthL;
609
-
610
- const currWidthL = this.getPageWidth(leftLeaf);
611
- const newWidthL = this.getPageWidth(newIndexL);
612
- const newWidthR = this.getPageWidth(newIndexR);
613
-
614
- const top = this.top();
615
- const gutter = this.br.twoPage.middle + this.gutterOffsetForIndex(newIndexL);
616
-
617
- //animation strategy:
618
- // 0. remove search highlight, if any.
619
- // 1. create a new div, called leafEdgeTmp to represent the leaf edge between the leftmost edge
620
- // of the left leaf and where the user clicked in the leaf edge.
621
- // Note that if this function was triggered by left() and not a
622
- // mouse click, the width of leafEdgeTmp is very small (zero px).
623
- // 2. animate both leafEdgeTmp to the gutter (without changing its width) and animate
624
- // leftLeaf to width=0.
625
- // 3. When step 2 is finished, animate leafEdgeTmp to right-hand side of new right leaf
626
- // (left=gutter+newWidthR) while also animating the new right leaf from width=0 to
627
- // its new full width.
628
- // 4. After step 3 is finished, do the following:
629
- // - remove leafEdgeTmp from the dom.
630
- // - resize and move the right leaf edge (leafEdgeR) to left=gutter+newWidthR
631
- // and width=twoPage.edgeWidth-newLeafEdgeWidthL.
632
- // - resize and move the left leaf edge (leafEdgeL) to left=gutter-newWidthL-newLeafEdgeWidthL
633
- // and width=newLeafEdgeWidthL.
634
- // - resize the back cover (twoPage.coverDiv) to left=gutter-newWidthL-newLeafEdgeWidthL-10
635
- // and width=newWidthL+newWidthR+twoPage.edgeWidth+20
636
- // - move new left leaf (newIndexL) forward to zindex=2 so it can receive clicks.
637
- // - remove old left and right leafs from the dom [prunePageContainers()].
638
- // - prefetch new adjacent leafs.
639
- // - set up click handlers for both new left and right leafs.
640
- // - redraw the search highlight.
641
- // - update the pagenum box and the url.
642
-
643
- const $twoPageViewEl = this.br.refs.$brTwoPageView;
644
- const leftEdgeTmpLeft = gutter - currWidthL - leafEdgeTmpW;
645
-
646
- this.br.leafEdgeTmp = document.createElement('div');
647
- this.br.leafEdgeTmp.className = 'BRleafEdgeTmp';
648
- $(this.br.leafEdgeTmp).css({
649
- width: `${leafEdgeTmpW}px`,
650
- height: `${this.br.twoPage.height}px`,
651
- left: `${leftEdgeTmpLeft}px`,
652
- top: `${top}px`,
653
- zIndex: 1000,
654
- }).appendTo($twoPageViewEl);
655
-
656
- $(this.leafEdgeL).css({
657
- width: `${newLeafEdgeWidthL}px`,
658
- left: `${gutter - currWidthL - newLeafEdgeWidthL}px`
659
- });
660
-
661
- // Left gets the offset of the current left leaf from the document
662
- const left = this.pageContainers[leftLeaf].$container.offset().left;
663
- // $$$ This seems very similar to the gutter. May be able to consolidate the logic.
664
- const right = `${$twoPageViewEl.prop('clientWidth') - left - this.pageContainers[leftLeaf].$container.width() + $twoPageViewEl.offset().left - 2}px`;
665
-
666
- // We change the left leaf to right positioning
667
- // $$$ This causes animation glitches during resize. See https://bugs.edge.launchpad.net/gnubook/+bug/328327
668
- this.pageContainers[leftLeaf].$container.css({
669
- right,
670
- left: ''
671
- });
672
-
673
- $(this.br.leafEdgeTmp).animate({left: gutter}, this.br.flipSpeed, 'easeInSine');
674
-
675
- this.pageContainers[leftLeaf].$container.animate({width: '0px'}, this.br.flipSpeed, 'easeInSine', () => {
676
-
677
- $(this.br.leafEdgeTmp).animate({left: `${gutter + newWidthR}px`}, this.br.flipSpeed, 'easeOutSine');
678
-
679
- this.br.$('.BRgutter').css({left: `${gutter - this.br.twoPage.bookSpineDivWidth * 0.5}px`});
680
-
681
- this.pageContainers[newIndexR].$container.animate({width: `${newWidthR}px`}, this.br.flipSpeed, 'easeOutSine', () => {
682
- this.pageContainers[newIndexL].$container.css('zIndex', 2);
683
-
684
- $(this.leafEdgeR).css({
685
- // Moves the right leaf edge
686
- width: `${this.br.twoPage.edgeWidth - newLeafEdgeWidthL}px`,
687
- left: `${gutter + newWidthR}px`
688
- });
689
-
690
- $(this.leafEdgeL).css({
691
- // Moves and resizes the left leaf edge
692
- width: `${newLeafEdgeWidthL}px`,
693
- left: `${gutter - newWidthL - newLeafEdgeWidthL}px`
694
- });
695
-
696
- // Resizes the brown border div
697
- $(this.br.twoPage.coverDiv).css({
698
- width: `${this.coverWidth(newWidthL + newWidthR)}px`,
699
- left: `${gutter - newWidthL - newLeafEdgeWidthL - this.br.twoPage.coverInternalPadding}px`
700
- });
701
-
702
- $(this.br.leafEdgeTmp).remove();
703
- this.br.leafEdgeTmp = null;
704
-
705
- // $$$ TODO refactor with opposite direction flip
706
-
707
- this.br.twoPage.currentIndexL = newIndexL;
708
- this.br.twoPage.currentIndexR = newIndexR;
709
- this.br.twoPage.scaledWL = newWidthL;
710
- this.br.twoPage.scaledWR = newWidthR;
711
- this.br.twoPage.gutter = gutter;
712
-
713
- this.br.updateFirstIndex(this.br.twoPage.currentIndexL);
714
- this.br.displayedIndices = [newIndexL, newIndexR];
715
- this.prunePageContainers();
716
- this.br.animating = false;
717
-
718
- this.resizeSpread();
719
-
720
- if (this.br.animationFinishedCallback) {
721
- this.br.animationFinishedCallback();
722
- this.br.animationFinishedCallback = null;
723
- }
724
-
725
- this.br.refs.$brContainer.removeClass("BRpageFlipping");
726
- this.br.textSelectionPlugin?.stopPageFlip(this.br.refs.$brContainer);
727
- this.centerView();
728
- this.br.trigger('pageChanged');
729
-
730
- // get next previous batch immediately
731
- this.prunePageContainers();
732
- this.createPageContainer(newIndexL - 2);
733
- this.createPageContainer(newIndexR - 2);
734
- this.createPageContainer(newIndexL - 3);
735
- this.createPageContainer(newIndexR - 3);
736
- });
737
- });
738
- }
739
-
740
- /**
741
- * @param {PageIndex} index
742
- */
743
- createPageContainer(index) {
744
- if (!this.pageContainers[index]) {
745
- this.pageContainers[index] = this.br._createPageContainer(index);
746
- }
747
- this.pageContainers[index].update({ reduce: this.br.reduce / this.scale });
748
- return this.pageContainers[index];
749
- }
750
-
751
- /**
752
- * Whether we flip left or right is dependent on the page progression
753
- * to flip forward one spread, pass index=null
754
- * @param {number} index
755
- */
756
- flipFwdToIndex(index) {
757
- if (this.br.animating) return;
758
-
759
- if (null != this.br.leafEdgeTmp) {
760
- alert('error: leafEdgeTmp should be null!');
761
- return;
762
- }
763
-
764
- if (null == index) {
765
- // Need to use the max here, since it could be a right to left book
766
- const {currentIndexL, currentIndexR} = this.br.twoPage;
767
- const maxDisplayedIndex = Math.max(currentIndexL, currentIndexR);
768
- const nextPage = this.book.getPage(maxDisplayedIndex).findNext({ combineConsecutiveUnviewables: true });
769
- if (!nextPage) return;
770
- index = nextPage.index;
771
- }
772
- if (index > this.br.lastDisplayableIndex()) return;
773
-
774
- this.br.updateNavIndexThrottled(index);
775
-
776
- this.br.animating = true;
777
-
778
- const nextIndices = this.book.getSpreadIndices(index);
779
-
780
- if ('rl' != this.br.pageProgression) {
781
- // We did not specify RTL
782
- this.prepareFlipRightToLeft(nextIndices[0], nextIndices[1]);
783
- this.flipRightToLeft(nextIndices[0], nextIndices[1]);
784
- } else {
785
- // RTL
786
- this.prepareFlipLeftToRight(nextIndices[0], nextIndices[1]);
787
- this.flipLeftToRight(nextIndices[0], nextIndices[1]);
788
- }
789
- }
790
-
791
- /**
792
- * Flip from left to right and show the nextL and nextR indices on those sides
793
- * $$$ better not to have to pass gutter in
794
- * @param {number} newIndexL
795
- * @param {number} newIndexR
796
- */
797
- flipRightToLeft(newIndexL, newIndexR) {
798
- this.br.refs.$brContainer.addClass("BRpageFlipping");
799
-
800
- const oldLeafEdgeWidthL = this.br.leafEdgeWidth(this.br.twoPage.currentIndexL);
801
- const oldLeafEdgeWidthR = this.br.twoPage.edgeWidth - oldLeafEdgeWidthL;
802
- const newLeafEdgeWidthL = this.br.leafEdgeWidth(newIndexL);
803
- const newLeafEdgeWidthR = this.br.twoPage.edgeWidth - newLeafEdgeWidthL;
804
-
805
- const leafEdgeTmpW = oldLeafEdgeWidthR - newLeafEdgeWidthR;
806
-
807
- const top = this.top();
808
- const scaledW = this.getPageWidth(this.br.twoPage.currentIndexR);
809
-
810
- const middle = this.br.twoPage.middle;
811
- const gutter = middle + this.gutterOffsetForIndex(newIndexL);
812
-
813
- const $twoPageViewEl = this.br.refs.$brTwoPageView;
814
-
815
- this.br.leafEdgeTmp = document.createElement('div');
816
- this.br.leafEdgeTmp.className = 'BRleafEdgeTmp';
817
- $(this.br.leafEdgeTmp).css({
818
- width: `${leafEdgeTmpW}px`,
819
- height: `${this.br.twoPage.height}px`,
820
- left: `${gutter + scaledW}px`,
821
- top: `${top}px`,
822
- zIndex:1000
823
- }).appendTo($twoPageViewEl);
824
-
825
- const newWidthL = this.getPageWidth(newIndexL);
826
- const newWidthR = this.getPageWidth(newIndexR);
827
-
828
- $(this.leafEdgeR).css({width: `${newLeafEdgeWidthR}px`, left: `${gutter + newWidthR}px` });
829
- const speed = this.br.flipSpeed;
830
-
831
- $(this.br.leafEdgeTmp).animate({left: gutter}, speed, 'easeInSine');
832
- this.pageContainers[this.br.twoPage.currentIndexR].$container.animate({width: '0px'}, speed, 'easeInSine', () => {
833
- this.br.$('BRgutter').css({left: `${gutter - this.br.twoPage.bookSpineDivWidth * 0.5}px`});
834
- $(this.br.leafEdgeTmp).animate({left: `${gutter - newWidthL - leafEdgeTmpW}px`}, speed, 'easeOutSine');
835
- this.pageContainers[newIndexL].$container.animate({width: `${newWidthL}px`}, speed, 'easeOutSine', () => {
836
- this.pageContainers[newIndexR].$container.css('zIndex', 2);
837
-
838
- $(this.leafEdgeL).css({
839
- width: `${newLeafEdgeWidthL}px`,
840
- left: `${gutter - newWidthL - newLeafEdgeWidthL}px`
841
- });
842
-
843
- // Resizes the book cover
844
- $(this.br.twoPage.coverDiv).css({
845
- width: `${this.coverWidth(newWidthL + newWidthR)}px`,
846
- left: `${gutter - newWidthL - newLeafEdgeWidthL - this.br.twoPage.coverInternalPadding}px`
847
- });
848
-
849
- $(this.br.leafEdgeTmp).remove();
850
- this.br.leafEdgeTmp = null;
851
-
852
- this.br.twoPage.currentIndexL = newIndexL;
853
- this.br.twoPage.currentIndexR = newIndexR;
854
- this.br.twoPage.scaledWL = newWidthL;
855
- this.br.twoPage.scaledWR = newWidthR;
856
- this.br.twoPage.gutter = gutter;
857
-
858
- this.br.updateFirstIndex(this.br.twoPage.currentIndexL);
859
- this.br.displayedIndices = [newIndexL, newIndexR];
860
- this.prunePageContainers();
861
- this.br.animating = false;
862
-
863
- this.resizeSpread();
864
-
865
- if (this.br.animationFinishedCallback) {
866
- this.br.animationFinishedCallback();
867
- this.br.animationFinishedCallback = null;
868
- }
869
-
870
- this.br.refs.$brContainer.removeClass("BRpageFlipping");
871
- this.br.textSelectionPlugin?.stopPageFlip(this.br.refs.$brContainer);
872
- this.centerView();
873
- this.br.trigger('pageChanged');
874
-
875
- this.prunePageContainers();
876
- this.createPageContainer(newIndexL + 2);
877
- this.createPageContainer(newIndexR + 2);
878
- this.createPageContainer(newIndexL + 3);
879
- this.createPageContainer(newIndexR + 3);
880
- });
881
- });
882
- }
883
-
884
- attachMouseHandlers() {
885
- this.br.refs.$brTwoPageView
886
- .off('mouseup').on('mouseup', ev => {
887
- if (ev.which == 3) {
888
- // right click
889
- return !this.br.protected;
890
- }
891
-
892
- const $page = $(ev.target).closest('.BRpagecontainer');
893
- if ($page.data('side') == 'L') this.br.left();
894
- else if ($page.data('side') == 'R') this.br.right();
895
- });
896
- }
897
-
898
- /**
899
- * Prepare to flip the left page towards the right. This corresponds to moving
900
- * backward when the page progression is left to right.
901
- * @param {number} prevL
902
- * @param {number} prevR
903
- */
904
- prepareFlipLeftToRight(prevL, prevR) {
905
- this.createPageContainer(prevL, true);
906
- this.createPageContainer(prevR, true);
907
-
908
- const $twoPageViewEl = this.br.refs.$brTwoPageView;
909
- const height = this.book._getPageHeight(prevL);
910
- const width = this.book._getPageWidth(prevL);
911
- const middle = this.br.twoPage.middle;
912
- const top = this.top();
913
- const scaledW = this.br.twoPage.height * width / height; // $$$ assumes height of page is dominant
914
-
915
- // The gutter is the dividing line between the left and right pages.
916
- // It is offset from the middle to create the illusion of thickness to the pages
917
- const gutter = middle + this.gutterOffsetForIndex(prevL);
918
-
919
- const leftCSS = {
920
- left: `${gutter - scaledW}px`,
921
- right: '', // clear right property
922
- top: `${top}px`,
923
- height: this.br.twoPage.height,
924
- width: `${scaledW}px`,
925
- zIndex: 1
926
- };
927
-
928
- this.pageContainers[prevL].$container
929
- .css(leftCSS)
930
- .appendTo($twoPageViewEl);
931
-
932
- const rightCSS = {
933
- left: `${gutter}px`,
934
- right: '',
935
- top: `${top}px`,
936
- height: this.br.twoPage.height,
937
- width: '0',
938
- zIndex: 2
939
- };
940
-
941
- this.pageContainers[prevR].$container
942
- .css(rightCSS)
943
- .appendTo($twoPageViewEl);
944
- }
945
-
946
- /**
947
- * // $$$ mang we're adding an extra pixel in the middle. See https://bugs.edge.launchpad.net/gnubook/+bug/411667
948
- */
949
- prepareFlipRightToLeft(nextL, nextR) {
950
- this.createPageContainer(nextL, true);
951
- this.createPageContainer(nextR, true);
952
-
953
- const $twoPageViewEl = this.br.refs.$brTwoPageView;
954
- let height = this.book._getPageHeight(nextR);
955
- let width = this.book._getPageWidth(nextR);
956
- const middle = this.br.twoPage.middle;
957
- const top = this.top();
958
- let scaledW = this.br.twoPage.height * width / height;
959
-
960
- const gutter = middle + this.gutterOffsetForIndex(nextL);
961
-
962
- $(this.pageContainers[nextR].$container).css({
963
- left: `${gutter}px`,
964
- top: `${top}px`,
965
- height: this.br.twoPage.height,
966
- width: `${scaledW}px`,
967
- zIndex: 1,
968
- })
969
- .appendTo($twoPageViewEl);
970
-
971
- height = this.book._getPageHeight(nextL);
972
- width = this.book._getPageWidth(nextL);
973
- scaledW = this.br.twoPage.height * width / height;
974
-
975
- $(this.pageContainers[nextL].$container).css({
976
- right: `${$twoPageViewEl.prop('clientWidth') - gutter}px`,
977
- top: `${top}px`,
978
- height: this.br.twoPage.height,
979
- width: '0px', // Start at 0 width, then grow to the left
980
- zIndex: 2,
981
- })
982
- .appendTo($twoPageViewEl);
983
- }
984
-
985
- getPageWidth(index) {
986
- // We return the width based on the dominant height
987
- const height = this.book._getPageHeight(index);
988
- const width = this.book._getPageWidth(index);
989
- // $$$ we assume width is relative to current spread
990
- return Math.floor(this.br.twoPage.height * width / height);
991
- }
992
-
993
- /**
994
- * Returns the position of the gutter (line between the page images)
995
- */
996
- gutter() {
997
- return this.br.twoPage.middle + this.gutterOffsetForIndex(this.br.twoPage.currentIndexL);
998
- }
999
-
1000
- /**
1001
- * Returns the offset for the top of the page images
1002
- */
1003
- top() {
1004
- return this.br.twoPage.coverExternalPadding + this.br.twoPage.coverInternalPadding; // $$$ + border?
1005
- }
1006
-
1007
- /**
1008
- * Returns the width of the cover div given the total page width
1009
- * @param {number} totalPageWidth
1010
- * @return {number}
1011
- */
1012
- coverWidth(totalPageWidth) {
1013
- return totalPageWidth + this.br.twoPage.edgeWidth + 2 * this.br.twoPage.coverInternalPadding;
1014
- }
1015
-
1016
- /**
1017
- * Returns the percentage offset into twopageview div at the center of container div
1018
- */
1019
- getViewCenter() {
1020
- const { $brContainer, $brTwoPageView } = this.br.refs;
1021
- const center = {};
1022
-
1023
- const containerOffset = $brContainer.offset();
1024
- const viewOffset = $brTwoPageView.offset();
1025
- center.percentageX = (containerOffset.left - viewOffset.left + ($brContainer.prop('clientWidth') >> 1)) / this.br.twoPage.totalWidth;
1026
- center.percentageY = (containerOffset.top - viewOffset.top + ($brContainer.prop('clientHeight') >> 1)) / this.br.twoPage.totalHeight;
1027
-
1028
- return center;
1029
- }
1030
-
1031
- /**
1032
- * Centers the point given by percentage from left,top of twopageview
1033
- * @param {number} [percentageX=0.5]
1034
- * @param {number} [percentageY=0.5]
1035
- */
1036
- centerView(percentageX, percentageY) {
1037
-
1038
- if ('undefined' == typeof(percentageX)) {
1039
- percentageX = 0.5;
1040
- }
1041
- if ('undefined' == typeof(percentageY)) {
1042
- percentageY = 0.5;
1043
- }
1044
-
1045
- const viewWidth = this.br.refs.$brTwoPageView.width();
1046
- const containerClientWidth = this.br.refs.$brContainer.prop('clientWidth');
1047
- const intoViewX = percentageX * viewWidth;
1048
-
1049
- const viewHeight = this.br.refs.$brTwoPageView.height();
1050
- const containerClientHeight = this.br.refs.$brContainer.prop('clientHeight');
1051
- const intoViewY = percentageY * viewHeight;
1052
-
1053
- if (viewWidth < containerClientWidth) {
1054
- // Can fit width without scrollbars - center by adjusting offset
1055
- this.br.refs.$brTwoPageView.css('left', `${(containerClientWidth >> 1) - intoViewX}px`);
1056
- } else {
1057
- // Need to scroll to center
1058
- this.br.refs.$brTwoPageView.css('left', 0);
1059
- this.br.refs.$brContainer.scrollLeft(intoViewX - (containerClientWidth >> 1));
1060
- }
1061
-
1062
- if (viewHeight < containerClientHeight) {
1063
- // Fits with scrollbars - add offset
1064
- this.br.refs.$brTwoPageView.css('top', `${(containerClientHeight >> 1) - intoViewY}px`);
1065
- } else {
1066
- this.br.refs.$brTwoPageView.css('top', 0);
1067
- this.br.refs.$brContainer.scrollTop(intoViewY - (containerClientHeight >> 1));
1068
- }
1069
- }
1070
-
1071
- /**
1072
- * Returns the integer height of the click-to-flip areas at the edges of the book
1073
- * @return {number}
1074
- */
1075
- flipAreaHeight() {
1076
- return Math.floor(this.br.twoPage.height);
1077
- }
1078
-
1079
- /**
1080
- * Returns the the integer width of the flip areas
1081
- * @return {number}
1082
- */
1083
- flipAreaWidth() {
1084
- const max = 100; // $$$ TODO base on view width?
1085
- const min = 10;
1086
-
1087
- const width = this.br.twoPage.width * 0.15;
1088
- return Math.floor(clamp(width, min, max));
1089
- }
1090
-
1091
- /**
1092
- * Returns integer top offset for flip areas
1093
- * @return {number}
1094
- */
1095
- flipAreaTop() {
1096
- return Math.floor(this.br.twoPage.bookCoverDivTop + this.br.twoPage.coverInternalPadding);
1097
- }
1098
-
1099
- /**
1100
- * Left offset for left flip area
1101
- * @return {number}
1102
- */
1103
- leftFlipAreaLeft() {
1104
- return Math.floor(this.br.twoPage.gutter - this.br.twoPage.scaledWL);
1105
- }
1106
-
1107
- /**
1108
- * Left offset for right flip area
1109
- * @return {number}
1110
- */
1111
- rightFlipAreaLeft() {
1112
- return Math.floor(this.br.twoPage.gutter + this.br.twoPage.scaledWR - this.flipAreaWidth());
1113
- }
1114
-
1115
- /**
1116
- * Position calculation shared between search and text-to-speech functions
1117
- */
1118
- setHilightCss(div, index, left, right, top, bottom) {
1119
- // We calculate the reduction factor for the specific page because it can be different
1120
- // for each page in the spread
1121
- const height = this.book._getPageHeight(index);
1122
- const width = this.book._getPageWidth(index);
1123
- const reduce = this.br.twoPage.height / height;
1124
- const scaledW = Math.floor(width * reduce);
1125
-
1126
- const gutter = this.gutter();
1127
- let pageL;
1128
- if ('L' == this.book.getPageSide(index)) {
1129
- pageL = gutter - scaledW;
1130
- } else {
1131
- pageL = gutter;
1132
- }
1133
- const pageT = this.top();
1134
-
1135
- $(div).css({
1136
- width: `${(right - left) * reduce}px`,
1137
- height: `${(bottom - top) * reduce}px`,
1138
- left: `${pageL + left * reduce}px`,
1139
- top: `${pageT + top * reduce}px`
1140
- });
1141
- }
1142
-
1143
- /**
1144
- * Returns the gutter offset for the spread containing the given index.
1145
- * This function supports RTL
1146
- * @param {number} pindex
1147
- * @return {number}
1148
- */
1149
- gutterOffsetForIndex(pindex) {
1150
- // To find the offset of the gutter from the middle we calculate our percentage distance
1151
- // through the book (0..1), remap to (-0.5..0.5) and multiply by the total page edge width
1152
- let offset = Math.floor(((pindex / this.book.getNumLeafs()) - 0.5) * this.br.twoPage.edgeWidth);
1153
-
1154
- // But then again for RTL it's the opposite
1155
- if ('rl' == this.br.pageProgression) {
1156
- offset *= -1;
1157
- }
1158
-
1159
- return offset;
1160
- }
1161
-
1162
- /**
1163
- * Returns the width of the leaf edge div for the page with index given
1164
- * @param {number} pindex
1165
- * @return {number}
1166
- */
1167
- leafEdgeWidth(pindex) {
1168
- // $$$ could there be single pixel rounding errors for L vs R?
1169
- if ((this.book.getPageSide(pindex) == 'L') && (this.br.pageProgression != 'rl')) {
1170
- return Math.floor( (pindex / this.book.getNumLeafs()) * this.br.twoPage.edgeWidth + 0.5);
1171
- } else {
1172
- return Math.floor( (1 - pindex / this.book.getNumLeafs()) * this.br.twoPage.edgeWidth + 0.5);
1173
- }
1174
- }
1175
-
1176
- /**
1177
- * Returns the target jump leaf given a page coordinate (inside the left page edge div)
1178
- * @param {number} pageX
1179
- * @return {PageIndex}
1180
- */
1181
- jumpIndexForLeftEdgePageX(pageX) {
1182
- let jumpIndex;
1183
- if ('rl' != this.br.pageProgression) {
1184
- // LTR - flipping backward
1185
- jumpIndex = this.br.twoPage.currentIndexL - ($(this.leafEdgeL).offset().left + $(this.leafEdgeL).width() - pageX) * 10;
1186
-
1187
- // browser may have resized the div due to font size change -- see https://bugs.launchpad.net/gnubook/+bug/333570
1188
- jumpIndex = clamp(Math.round(jumpIndex), this.br.firstDisplayableIndex(), this.br.twoPage.currentIndexL - 2);
1189
- return jumpIndex;
1190
-
1191
- } else {
1192
- jumpIndex = this.br.twoPage.currentIndexL + ($(this.leafEdgeL).offset().left + $(this.leafEdgeL).width() - pageX) * 10;
1193
- jumpIndex = clamp(Math.round(jumpIndex), this.br.twoPage.currentIndexL + 2, this.br.lastDisplayableIndex());
1194
- return jumpIndex;
1195
- }
1196
- }
1197
-
1198
- /**
1199
- * Returns the target jump leaf given a page coordinate (inside the right page edge div)
1200
- * @param {number} pageX
1201
- * @return {PageIndex}
1202
- */
1203
- jumpIndexForRightEdgePageX(pageX) {
1204
- let jumpIndex;
1205
- if ('rl' != this.br.pageProgression) {
1206
- // LTR
1207
- jumpIndex = this.br.twoPage.currentIndexL + (pageX - $(this.leafEdgeR).offset().left) * 10;
1208
- jumpIndex = clamp(Math.round(jumpIndex), this.br.twoPage.currentIndexL + 2, this.br.lastDisplayableIndex());
1209
- return jumpIndex;
1210
- } else {
1211
- jumpIndex = this.br.twoPage.currentIndexL - (pageX - $(this.leafEdgeR).offset().left) * 10;
1212
- jumpIndex = clamp(Math.round(jumpIndex), this.br.firstDisplayableIndex(), this.br.twoPage.currentIndexL - 2);
1213
- return jumpIndex;
1214
- }
1215
- }
1216
-
1217
- /**
1218
- * Fetches the currently displayed images (if not already fetching)
1219
- * as wells as any nearby pages.
1220
- */
1221
- prefetch() {
1222
- // $$$ We should check here if the current indices have finished
1223
- // loading (with some timeout) before loading more page images
1224
- // See https://bugs.edge.launchpad.net/bookreader/+bug/511391
1225
- const { max, min } = Math;
1226
- const { book } = this;
1227
- const { currentIndexL, currentIndexR } = this.br.twoPage;
1228
- const ADJACENT_PAGES_TO_LOAD = 2;
1229
- // currentIndexL can be -1; getPage returns the last page of the book
1230
- // when given -1, so need to prevent that.
1231
- let lowPage = book.getPage(max(0, min(currentIndexL, currentIndexR)));
1232
- let highPage = book.getPage(max(currentIndexL, currentIndexR));
1233
-
1234
- for (let i = 0; i < ADJACENT_PAGES_TO_LOAD + 2; i++) {
1235
- if (lowPage) {
1236
- this.createPageContainer(lowPage.index);
1237
- lowPage = lowPage.findPrev({ combineConsecutiveUnviewables: true });
1238
- }
1239
-
1240
- if (highPage) {
1241
- this.createPageContainer(highPage.index);
1242
- highPage = highPage.findNext({ combineConsecutiveUnviewables: true });
1243
- }
1244
- }
1245
- }
1246
-
1247
- /* 2up Container Sizes */
1248
-
1249
- /** main positions for inner containers */
1250
- get baseLeafCss() {
1251
- return {
1252
- position: 'absolute',
1253
- right: '',
1254
- top: `${this.top()}px`,
1255
- zIndex: 2,
1256
- };
1257
- }
1258
-
1259
- /** main height for inner containers */
1260
- get heightCss() {
1261
- return {
1262
- height: `${this.br.twoPage.height}px`, // $$$ height forced the same for both pages
1263
- };
1264
- }
1265
-
1266
- /** Left Page sizing */
1267
- get leftLeafCss() {
1268
- return {
1269
- ...this.baseLeafCss,
1270
- ...this.heightCss,
1271
- left: `${this.br.twoPage.gutter - this.br.twoPage.scaledWL}px`,
1272
- width: `${this.br.twoPage.scaledWL}px`,
1273
- };
1274
- }
1275
-
1276
- /** Left side book thickness */
1277
- get leafEdgeLCss() {
1278
- return {
1279
- ...this.heightCss,
1280
- width: `${this.br.twoPage.leafEdgeWidthL}px`,
1281
- left: `${this.br.twoPage.bookCoverDivLeft + this.br.twoPage.coverInternalPadding}px`,
1282
- top: `${this.br.twoPage.bookCoverDivTop + this.br.twoPage.coverInternalPadding}px`,
1283
- border: this.br.twoPage.leafEdgeWidthL === 0 ? 'none' : null
1284
- };
1285
- }
1286
-
1287
- /** Right Page sizing */
1288
- get rightLeafCss() {
1289
- return {
1290
- ...this.baseLeafCss,
1291
- ...this.heightCss,
1292
- left: `${this.br.twoPage.gutter}px`,
1293
- width: `${this.br.twoPage.scaledWR}px`,
1294
- };
1295
- }
1296
-
1297
- /** Right side book thickness */
1298
- get leafEdgeRCss() {
1299
- return {
1300
- ...this.heightCss,
1301
- width: `${this.br.twoPage.leafEdgeWidthR}px`,
1302
- left: `${this.br.twoPage.scaledWL + this.br.twoPage.scaledWR + this.br.twoPage.leafEdgeWidthL}px`,
1303
- top: `${this.br.twoPage.bookCoverDivTop + this.br.twoPage.coverInternalPadding}px`,
1304
- border: this.br.twoPage.leafEdgeWidthR === 0 ? 'none' : null
1305
- };
1306
- }
1307
-
1308
- /** main container sizing */
1309
- get mainContainerCss() {
1310
- return {
1311
- height: `${this.br.twoPage.totalHeight}px`,
1312
- width: `${this.br.twoPage.totalWidth}px`,
1313
- position: 'absolute'
1314
- };
1315
- }
1316
-
1317
- /** book cover sizing */
1318
- get spreadCoverCss() {
1319
- return {
1320
- width: `${this.br.twoPage.bookCoverDivWidth}px`,
1321
- height: `${this.br.twoPage.bookCoverDivHeight}px`,
1322
- visibility: 'visible'
1323
- };
1324
- }
1325
-
1326
- /** book spine sizing */
1327
- get spineCss() {
1328
- return {
1329
- width: `${this.br.twoPage.bookSpineDivWidth}px`,
1330
- height: `${this.br.twoPage.bookSpineDivHeight}px`,
1331
- left: `${this.br.twoPage.gutter - (this.br.twoPage.bookSpineDivWidth / 2)}px`,
1332
- top: `${this.br.twoPage.bookSpineDivTop}px`
1333
- };
1334
- }
1335
- /** end CSS */
1336
- }
1337
-
1338
- /**
1339
- * @implements {BookReaderOptions["twoPage"]}
1340
- * @typedef {object} TwoPageState
1341
- * @property {number} coverInternalPadding
1342
- * @property {number} coverExternalPadding
1343
- *
1344
- * @property {import('./options.js').AutoFitValues} autofit
1345
- * @property {number} width
1346
- * @property {number} height
1347
- * @property {number} currentIndexL
1348
- * @property {number} currentIndexR
1349
- * @property {number} scaledWL
1350
- * @property {number} scaledWR
1351
- * @property {number} gutter
1352
- * @property {Array<{reduce: number, autofit: import('./options.js').AutoFitValues}>} reductionFactors
1353
- * @property {number} totalHeight
1354
- * @property {number} totalWidth
1355
- *
1356
- * @property {HTMLDivElement} coverDiv
1357
- * @property {number} bookCoverDivTop
1358
- * @property {number} bookCoverDivLeft
1359
- * @property {number} bookCoverDivWidth
1360
- * @property {number} bookCoverDivHeight
1361
- *
1362
- * @property {number} leafEdgeWidthL
1363
- * @property {number} leafEdgeWidthR
1364
- *
1365
- * @property {number} bookSpineDivTop
1366
- * @property {number} bookSpineDivLeft
1367
- * @property {number} bookSpineDivWidth
1368
- * @property {number} bookSpineDivHeight
1369
- *
1370
- * @property {number} edgeWidth
1371
- * @property {number} middle
1372
- */