@internetarchive/bookreader 5.0.0-6-14 → 5.0.0-60

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