@internetarchive/bookreader 5.0.0-88-alpha.11 → 5.0.0-89

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/BookReader/BookReader.css +17 -3
  2. package/BookReader/BookReader.js +1 -1
  3. package/BookReader/BookReader.js.map +1 -1
  4. package/BookReader/ia-bookreader-bundle.js +87 -108
  5. package/BookReader/ia-bookreader-bundle.js.map +1 -1
  6. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  7. package/BookReader/plugins/plugin.archive_analytics.js.map +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.iiif.js +1 -1
  11. package/BookReader/plugins/plugin.iiif.js.map +1 -1
  12. package/BookReader/plugins/plugin.resume.js +1 -1
  13. package/BookReader/plugins/plugin.resume.js.map +1 -1
  14. package/BookReader/plugins/plugin.search.js +1 -1
  15. package/BookReader/plugins/plugin.search.js.map +1 -1
  16. package/BookReader/plugins/plugin.text_selection.js +1 -1
  17. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  18. package/BookReader/plugins/plugin.tts.js +1 -1
  19. package/BookReader/plugins/plugin.tts.js.map +1 -1
  20. package/BookReader/plugins/plugin.url.js +1 -1
  21. package/BookReader/plugins/plugin.url.js.map +1 -1
  22. package/CHANGELOG.md +14 -0
  23. package/babel.config.js +12 -30
  24. package/codecov.yml +1 -1
  25. package/jsconfig.json +1 -3
  26. package/package.json +14 -16
  27. package/src/BookNavigator/search/search-results.js +1 -1
  28. package/src/BookReader/ImageCache.js +48 -15
  29. package/src/BookReader/Mode1UpLit.js +56 -86
  30. package/src/BookReader/Mode2UpLit.js +5 -5
  31. package/src/BookReader/Navbar/Navbar.js +53 -11
  32. package/src/BookReader/PageContainer.js +41 -22
  33. package/src/BookReader/options.js +27 -3
  34. package/src/BookReader/utils.js +10 -0
  35. package/src/BookReader.js +120 -21
  36. package/src/BookReaderPlugin.js +44 -0
  37. package/src/css/_BRnav.scss +0 -3
  38. package/src/css/_BRpages.scss +21 -2
  39. package/src/css/_controls.scss +4 -0
  40. package/src/plugins/plugin.archive_analytics.js +84 -78
  41. package/src/plugins/plugin.autoplay.js +98 -102
  42. package/src/plugins/plugin.chapters.js +17 -22
  43. package/src/plugins/plugin.iiif.js +16 -30
  44. package/src/plugins/plugin.resume.js +54 -51
  45. package/src/plugins/plugin.text_selection.js +68 -76
  46. package/src/plugins/tts/AbstractTTSEngine.js +2 -4
  47. package/src/plugins/tts/PageChunk.js +5 -9
  48. package/src/plugins/tts/PageChunkIterator.js +3 -5
  49. package/src/plugins/tts/plugin.tts.js +309 -329
  50. package/src/plugins/url/plugin.url.js +1 -1
  51. package/src/util/strings.js +1 -0
  52. package/tests/e2e/autoplay.test.js +8 -5
  53. package/tests/e2e/helpers/base.js +2 -2
  54. package/tests/e2e/helpers/mockSearch.js +6 -9
  55. package/tests/jest/BookReader/Navbar/Navbar.test.js +16 -3
  56. package/tests/jest/BookReader/PageContainer.test.js +96 -55
  57. package/tests/jest/BookReader/utils.test.js +21 -0
  58. package/tests/jest/BookReader.test.js +13 -12
  59. package/tests/jest/plugins/plugin.archive_analytics.test.js +8 -11
  60. package/tests/jest/plugins/plugin.autoplay.test.js +9 -22
  61. package/tests/jest/plugins/plugin.resume.test.js +19 -32
  62. package/tests/jest/plugins/plugin.text_selection.test.js +23 -24
  63. package/dist/esm/BookNavigator/assets/bookmark-colors.js +0 -4
  64. package/dist/esm/BookNavigator/assets/button-base.js +0 -4
  65. package/dist/esm/BookNavigator/assets/ia-logo.js +0 -4
  66. package/dist/esm/BookNavigator/assets/icon_checkmark.js +0 -8
  67. package/dist/esm/BookNavigator/assets/icon_close.js +0 -4
  68. package/dist/esm/BookNavigator/book-navigator.js +0 -612
  69. package/dist/esm/BookNavigator/bookmarks/bookmark-button.js +0 -35
  70. package/dist/esm/BookNavigator/bookmarks/bookmark-edit.js +0 -78
  71. package/dist/esm/BookNavigator/bookmarks/bookmarks-list.js +0 -160
  72. package/dist/esm/BookNavigator/bookmarks/bookmarks-loginCTA.js +0 -24
  73. package/dist/esm/BookNavigator/bookmarks/bookmarks-provider.js +0 -55
  74. package/dist/esm/BookNavigator/bookmarks/ia-bookmarks.js +0 -521
  75. package/dist/esm/BookNavigator/delete-modal-actions.js +0 -29
  76. package/dist/esm/BookNavigator/downloads/downloads-provider.js +0 -84
  77. package/dist/esm/BookNavigator/downloads/downloads.js +0 -69
  78. package/dist/esm/BookNavigator/search/search-provider.js +0 -238
  79. package/dist/esm/BookNavigator/search/search-results.js +0 -161
  80. package/dist/esm/BookNavigator/sharing.js +0 -26
  81. package/dist/esm/BookNavigator/viewable-files.js +0 -94
  82. package/dist/esm/BookNavigator/visual-adjustments/visual-adjustments-provider.js +0 -83
  83. package/dist/esm/BookNavigator/visual-adjustments/visual-adjustments.js +0 -131
  84. package/dist/esm/BookReader/BookModel.js +0 -575
  85. package/dist/esm/BookReader/DragScrollable.js +0 -224
  86. package/dist/esm/BookReader/ImageCache.js +0 -122
  87. package/dist/esm/BookReader/Mode1Up.js +0 -114
  88. package/dist/esm/BookReader/Mode1UpLit.js +0 -579
  89. package/dist/esm/BookReader/Mode2Up.js +0 -106
  90. package/dist/esm/BookReader/Mode2UpLit.js +0 -1020
  91. package/dist/esm/BookReader/ModeCoordinateSpace.js +0 -28
  92. package/dist/esm/BookReader/ModeSmoothZoom.js +0 -318
  93. package/dist/esm/BookReader/ModeThumb.js +0 -366
  94. package/dist/esm/BookReader/Navbar/Navbar.js +0 -253
  95. package/dist/esm/BookReader/PageContainer.js +0 -165
  96. package/dist/esm/BookReader/ReduceSet.js +0 -27
  97. package/dist/esm/BookReader/Toolbar/Toolbar.js +0 -242
  98. package/dist/esm/BookReader/events.js +0 -20
  99. package/dist/esm/BookReader/options.js +0 -331
  100. package/dist/esm/BookReader/utils/HTMLDimensionsCacher.js +0 -48
  101. package/dist/esm/BookReader/utils/ScrollClassAdder.js +0 -31
  102. package/dist/esm/BookReader/utils/SelectionObserver.js +0 -42
  103. package/dist/esm/BookReader/utils/classes.js +0 -37
  104. package/dist/esm/BookReader/utils.js +0 -315
  105. package/dist/esm/BookReader.js +0 -1828
  106. package/dist/esm/assets/icons/1up.svg +0 -12
  107. package/dist/esm/assets/icons/2up.svg +0 -15
  108. package/dist/esm/assets/icons/advance.svg +0 -26
  109. package/dist/esm/assets/icons/chevron-right.svg +0 -1
  110. package/dist/esm/assets/icons/close-circle-dark.svg +0 -1
  111. package/dist/esm/assets/icons/close-circle.svg +0 -1
  112. package/dist/esm/assets/icons/fullscreen.svg +0 -17
  113. package/dist/esm/assets/icons/fullscreen_exit.svg +0 -17
  114. package/dist/esm/assets/icons/hamburger.svg +0 -15
  115. package/dist/esm/assets/icons/left-arrow.svg +0 -12
  116. package/dist/esm/assets/icons/magnify-minus.svg +0 -12
  117. package/dist/esm/assets/icons/magnify-plus.svg +0 -13
  118. package/dist/esm/assets/icons/magnify.svg +0 -15
  119. package/dist/esm/assets/icons/pause.svg +0 -23
  120. package/dist/esm/assets/icons/play.svg +0 -22
  121. package/dist/esm/assets/icons/playback-speed.svg +0 -34
  122. package/dist/esm/assets/icons/read-aloud.svg +0 -22
  123. package/dist/esm/assets/icons/review.svg +0 -22
  124. package/dist/esm/assets/icons/thumbnails.svg +0 -17
  125. package/dist/esm/assets/icons/voice.svg +0 -1
  126. package/dist/esm/assets/icons/volume-full.svg +0 -22
  127. package/dist/esm/assets/images/BRicons.png +0 -0
  128. package/dist/esm/assets/images/BRicons.svg +0 -94
  129. package/dist/esm/assets/images/BRicons_ia.png +0 -0
  130. package/dist/esm/assets/images/back_pages.png +0 -0
  131. package/dist/esm/assets/images/book_bottom_icon.png +0 -0
  132. package/dist/esm/assets/images/book_down_icon.png +0 -0
  133. package/dist/esm/assets/images/book_left_icon.png +0 -0
  134. package/dist/esm/assets/images/book_leftmost_icon.png +0 -0
  135. package/dist/esm/assets/images/book_right_icon.png +0 -0
  136. package/dist/esm/assets/images/book_rightmost_icon.png +0 -0
  137. package/dist/esm/assets/images/book_top_icon.png +0 -0
  138. package/dist/esm/assets/images/book_up_icon.png +0 -0
  139. package/dist/esm/assets/images/books_graphic.svg +0 -177
  140. package/dist/esm/assets/images/booksplit.png +0 -0
  141. package/dist/esm/assets/images/control_pause_icon.png +0 -0
  142. package/dist/esm/assets/images/control_play_icon.png +0 -0
  143. package/dist/esm/assets/images/embed_icon.png +0 -0
  144. package/dist/esm/assets/images/icon-home-ia.png +0 -0
  145. package/dist/esm/assets/images/icon_OL-logo-xs.png +0 -0
  146. package/dist/esm/assets/images/icon_alert-xs.png +0 -0
  147. package/dist/esm/assets/images/icon_book.svg +0 -12
  148. package/dist/esm/assets/images/icon_bookmark.svg +0 -12
  149. package/dist/esm/assets/images/icon_close-pop.png +0 -0
  150. package/dist/esm/assets/images/icon_download.png +0 -0
  151. package/dist/esm/assets/images/icon_gear.svg +0 -14
  152. package/dist/esm/assets/images/icon_hamburger.svg +0 -20
  153. package/dist/esm/assets/images/icon_home.png +0 -0
  154. package/dist/esm/assets/images/icon_home.svg +0 -21
  155. package/dist/esm/assets/images/icon_home_ia.png +0 -0
  156. package/dist/esm/assets/images/icon_indicator.png +0 -0
  157. package/dist/esm/assets/images/icon_info.svg +0 -11
  158. package/dist/esm/assets/images/icon_one_page.svg +0 -8
  159. package/dist/esm/assets/images/icon_pause.svg +0 -1
  160. package/dist/esm/assets/images/icon_play.svg +0 -1
  161. package/dist/esm/assets/images/icon_playback-rate.svg +0 -15
  162. package/dist/esm/assets/images/icon_return.png +0 -0
  163. package/dist/esm/assets/images/icon_search_button.svg +0 -8
  164. package/dist/esm/assets/images/icon_share.svg +0 -9
  165. package/dist/esm/assets/images/icon_skip-ahead.svg +0 -6
  166. package/dist/esm/assets/images/icon_skip-back.svg +0 -13
  167. package/dist/esm/assets/images/icon_speaker.svg +0 -18
  168. package/dist/esm/assets/images/icon_speaker_open.svg +0 -10
  169. package/dist/esm/assets/images/icon_thumbnails.svg +0 -12
  170. package/dist/esm/assets/images/icon_toc.svg +0 -5
  171. package/dist/esm/assets/images/icon_two_pages.svg +0 -9
  172. package/dist/esm/assets/images/icon_zoomer.png +0 -0
  173. package/dist/esm/assets/images/loading.gif +0 -0
  174. package/dist/esm/assets/images/logo_icon.png +0 -0
  175. package/dist/esm/assets/images/marker_chap-off.png +0 -0
  176. package/dist/esm/assets/images/marker_chap-off.svg +0 -11
  177. package/dist/esm/assets/images/marker_chap-off_ia.png +0 -0
  178. package/dist/esm/assets/images/marker_chap-on.png +0 -0
  179. package/dist/esm/assets/images/marker_chap-on.svg +0 -11
  180. package/dist/esm/assets/images/marker_srch-on.svg +0 -11
  181. package/dist/esm/assets/images/marker_srchchap-off.png +0 -0
  182. package/dist/esm/assets/images/marker_srchchap-on.png +0 -0
  183. package/dist/esm/assets/images/nav_control-dn.png +0 -0
  184. package/dist/esm/assets/images/nav_control-dn_ia.png +0 -0
  185. package/dist/esm/assets/images/nav_control-up.png +0 -0
  186. package/dist/esm/assets/images/nav_control-up_ia.png +0 -0
  187. package/dist/esm/assets/images/nav_control.png +0 -0
  188. package/dist/esm/assets/images/one_page_mode_icon.png +0 -0
  189. package/dist/esm/assets/images/paper-badge.png +0 -0
  190. package/dist/esm/assets/images/print_icon.png +0 -0
  191. package/dist/esm/assets/images/progressbar.gif +0 -0
  192. package/dist/esm/assets/images/right_edges.png +0 -0
  193. package/dist/esm/assets/images/slider.png +0 -0
  194. package/dist/esm/assets/images/slider_ia.png +0 -0
  195. package/dist/esm/assets/images/thumbnail_mode_icon.png +0 -0
  196. package/dist/esm/assets/images/transparent.png +0 -0
  197. package/dist/esm/assets/images/two_page_mode_icon.png +0 -0
  198. package/dist/esm/assets/images/unviewable_page.png +0 -0
  199. package/dist/esm/assets/images/zoom_in_icon.png +0 -0
  200. package/dist/esm/assets/images/zoom_out_icon.png +0 -0
  201. package/dist/esm/css/BookReader.scss +0 -85
  202. package/dist/esm/css/_BRBookmarks.scss +0 -29
  203. package/dist/esm/css/_BRComponent.scss +0 -13
  204. package/dist/esm/css/_BRfloat.scss +0 -197
  205. package/dist/esm/css/_BRicon.scss +0 -54
  206. package/dist/esm/css/_BRmain.scss +0 -262
  207. package/dist/esm/css/_BRnav.scss +0 -354
  208. package/dist/esm/css/_BRpages.scss +0 -213
  209. package/dist/esm/css/_BRsearch.scss +0 -268
  210. package/dist/esm/css/_BRtoolbar.scss +0 -84
  211. package/dist/esm/css/_BRvendor.scss +0 -5
  212. package/dist/esm/css/_TextSelection.scss +0 -108
  213. package/dist/esm/css/_colorbox.scss +0 -52
  214. package/dist/esm/css/_controls.scss +0 -257
  215. package/dist/esm/css/_icons.scss +0 -121
  216. package/dist/esm/ia-bookreader/ia-bookreader.js +0 -141
  217. package/dist/esm/jquery-wrapper.js +0 -3
  218. package/dist/esm/plugins/plugin.archive_analytics.js +0 -72
  219. package/dist/esm/plugins/plugin.autoplay.js +0 -119
  220. package/dist/esm/plugins/plugin.chapters.js +0 -288
  221. package/dist/esm/plugins/plugin.iframe.js +0 -44
  222. package/dist/esm/plugins/plugin.iiif.js +0 -146
  223. package/dist/esm/plugins/plugin.resume.js +0 -66
  224. package/dist/esm/plugins/plugin.text_selection.js +0 -621
  225. package/dist/esm/plugins/plugin.vendor-fullscreen.js +0 -227
  226. package/dist/esm/plugins/search/plugin.search.js +0 -499
  227. package/dist/esm/plugins/search/utils.js +0 -42
  228. package/dist/esm/plugins/search/view.js +0 -360
  229. package/dist/esm/plugins/tts/AbstractTTSEngine.js +0 -282
  230. package/dist/esm/plugins/tts/FestivalTTSEngine.js +0 -192
  231. package/dist/esm/plugins/tts/PageChunk.js +0 -105
  232. package/dist/esm/plugins/tts/PageChunkIterator.js +0 -155
  233. package/dist/esm/plugins/tts/WebTTSEngine.js +0 -364
  234. package/dist/esm/plugins/tts/plugin.tts.js +0 -315
  235. package/dist/esm/plugins/tts/tooltip_dict.js +0 -14
  236. package/dist/esm/plugins/tts/utils.js +0 -79
  237. package/dist/esm/plugins/url/UrlPlugin.js +0 -197
  238. package/dist/esm/plugins/url/plugin.url.js +0 -212
  239. package/dist/esm/util/browserSniffing.js +0 -56
  240. package/dist/esm/util/debouncer.js +0 -25
  241. package/dist/esm/util/docCookies.js +0 -75
  242. package/dist/esm/util/strings.js +0 -34
  243. package/index.js +0 -2
@@ -1,1828 +0,0 @@
1
- function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
2
- function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
3
- /*
4
- Copyright(c)2008-2019 Internet Archive. Software license AGPL version 3.
5
-
6
- This file is part of BookReader.
7
-
8
- BookReader is free software: you can redistribute it and/or modify
9
- it under the terms of the GNU Affero General Public License as published by
10
- the Free Software Foundation, either version 3 of the License, or
11
- (at your option) any later version.
12
-
13
- BookReader is distributed in the hope that it will be useful,
14
- but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- GNU Affero General Public License for more details.
17
-
18
- You should have received a copy of the GNU Affero General Public License
19
- along with BookReader. If not, see <http://www.gnu.org/licenses/>.
20
-
21
- The BookReader source is hosted at http://github.com/internetarchive/bookreader/
22
-
23
- */
24
- // Needed by touch-punch
25
- import 'jquery-ui/ui/widget.js';
26
- import 'jquery-ui/ui/widgets/mouse.js';
27
- import 'jquery-ui-touch-punch';
28
- import jQuery from 'jquery';
29
-
30
- // import PACKAGE_JSON from '../package.json';
31
- import * as utils from './BookReader/utils.js';
32
- import { exposeOverrideable } from './BookReader/utils/classes.js';
33
- import { Navbar } from './BookReader/Navbar/Navbar.js';
34
- import { DEFAULT_OPTIONS, OptionsParseError } from './BookReader/options.js';
35
- /** @typedef {import('./BookReader/options.js').BookReaderOptions} BookReaderOptions */
36
- /** @typedef {import('./BookReader/options.js').ReductionFactor} ReductionFactor */
37
- /** @typedef {import('./BookReader/BookModel.js').PageIndex} PageIndex */
38
- import { EVENTS } from './BookReader/events.js';
39
- import { Toolbar } from './BookReader/Toolbar/Toolbar.js';
40
- import { BookModel } from './BookReader/BookModel.js';
41
- import { Mode1Up } from './BookReader/Mode1Up.js';
42
- import { Mode2Up } from './BookReader/Mode2Up.js';
43
- import { ModeThumb } from './BookReader/ModeThumb';
44
- import { ImageCache } from './BookReader/ImageCache.js';
45
- import { PageContainer } from './BookReader/PageContainer.js';
46
- import { NAMED_REDUCE_SETS } from './BookReader/ReduceSet';
47
-
48
- /**
49
- * BookReader
50
- * @param {BookReaderOptions} options
51
- * TODO document all options properties
52
- * @constructor
53
- */
54
- export default function BookReader() {
55
- var overrides = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
56
- var options = jQuery.extend(true, {}, BookReader.defaultOptions, overrides, BookReader.optionOverrides);
57
- this.setup(options);
58
- }
59
- BookReader.version = '123';
60
-
61
- // Mode constants
62
- /** 1 page view */
63
- BookReader.constMode1up = 1;
64
- /** 2 pages view */
65
- BookReader.constMode2up = 2;
66
- /** thumbnails view */
67
- BookReader.constModeThumb = 3;
68
- /** image cache */
69
- BookReader.imageCache = null;
70
-
71
- // Animation constants
72
- BookReader.constNavAnimationDuration = 300;
73
- BookReader.constResizeAnimationDuration = 100;
74
-
75
- // Names of events that can be triggered via BookReader.prototype.trigger()
76
- BookReader.eventNames = EVENTS;
77
- BookReader.defaultOptions = DEFAULT_OPTIONS;
78
-
79
- /**
80
- * @type {BookReaderOptions}
81
- * This is here, just in case you need to absolutely override an option.
82
- */
83
- BookReader.optionOverrides = {};
84
-
85
- /**
86
- * Setup
87
- * It is separate from the constructor, so plugins can extend.
88
- * @param {BookReaderOptions} options
89
- */
90
- BookReader.prototype.setup = function (options) {
91
- // Store the options used to setup bookreader
92
- this.options = options;
93
-
94
- /** @type {number} @deprecated some past iterations set this */
95
- this.numLeafs = undefined;
96
-
97
- /** Overridden by plugin.search.js */
98
- this.enableSearch = false;
99
-
100
- /**
101
- * Store viewModeOrder states
102
- * @var {boolean}
103
- */
104
- this.viewModeOrder = [];
105
-
106
- /**
107
- * Used to suppress fragment change for init with canonical URLs
108
- * @var {boolean}
109
- */
110
- this.suppressFragmentChange = false;
111
-
112
- /** @type {function(): void} */
113
- this.animationFinishedCallback = null;
114
-
115
- // @deprecated: Instance constants. Use Class constants instead
116
- /** 1 page view */
117
- this.constMode1up = BookReader.constMode1up;
118
- /** 2 pages view */
119
- this.constMode2up = BookReader.constMode2up;
120
- /** thumbnails view */
121
- this.constModeThumb = BookReader.constModeThumb;
122
-
123
- // Private properties below. Configuration should be done with options.
124
- /** @type {number} TODO: Make private */
125
- this.reduce = 8; /* start very small */
126
- this.defaults = options.defaults;
127
- this.padding = options.padding;
128
- this.reduceSet = NAMED_REDUCE_SETS[options.reduceSet];
129
- if (!this.reduceSet) {
130
- console.warn("Invalid reduceSet ".concat(options.reduceSet, ". Ignoring."));
131
- this.reduceSet = NAMED_REDUCE_SETS[DEFAULT_OPTIONS.reduceSet];
132
- }
133
-
134
- /** @type {number}
135
- * can be 1 or 2 or 3 based on the display mode const value
136
- */
137
- this.mode = null;
138
- this.prevReadMode = null;
139
- this.ui = options.ui;
140
- this.uiAutoHide = options.uiAutoHide;
141
- this.thumbWidth = 100; // will be overridden during this._modes.modeThumb.prepare();
142
- this.thumbRowBuffer = options.thumbRowBuffer;
143
- this.thumbColumns = options.thumbColumns;
144
- this.thumbMaxLoading = options.thumbMaxLoading;
145
- this.thumbPadding = options.thumbPadding;
146
- this.displayedRows = [];
147
- this.displayedIndices = [];
148
- this.animating = false;
149
- this.flipSpeed = typeof options.flipSpeed === 'number' ? options.flipSpeed : {
150
- 'fast': 200,
151
- 'slow': 600
152
- }[options.flipSpeed] || 400;
153
- this.flipDelay = options.flipDelay;
154
-
155
- /**
156
- * Represents the first displayed index
157
- * In 2up mode it will be the left page
158
- * In 1 up mode it is the highest page
159
- * @property {number|null} firstIndex
160
- */
161
- this.firstIndex = null;
162
- this.isFullscreenActive = options.startFullscreen || false;
163
- this.lastScroll = null;
164
- this.showLogo = options.showLogo;
165
- this.logoURL = options.logoURL;
166
- this.imagesBaseURL = options.imagesBaseURL;
167
- this.reductionFactors = options.reductionFactors;
168
- this.onePage = options.onePage;
169
- /** @type {import('./BookReader/Mode2Up').TwoPageState} */
170
- this.twoPage = options.twoPage;
171
- this.onePageMinBreakpoint = options.onePageMinBreakpoint;
172
- this.bookTitle = options.bookTitle;
173
- this.bookUrl = options.bookUrl;
174
- this.bookUrlText = options.bookUrlText;
175
- this.bookUrlTitle = options.bookUrlTitle;
176
- this.titleLeaf = options.titleLeaf;
177
- this.metadata = options.metadata;
178
- this.thumbnail = options.thumbnail;
179
- this.bookUrlMoreInfo = options.bookUrlMoreInfo;
180
- this.enableExperimentalControls = options.enableExperimentalControls;
181
- this.el = options.el;
182
- this.pageProgression = options.pageProgression;
183
- this.protected = options.protected;
184
- this.getEmbedCode = options.getEmbedCode;
185
- this.popup = null;
186
-
187
- // Assign the data methods
188
- this.data = options.data;
189
-
190
- /** @type {{[name: string]: JQuery}} */
191
- this.refs = {};
192
-
193
- /** The book being displayed in BookReader*/
194
- this.book = new BookModel(this);
195
- if (options.getNumLeafs) this.book.getNumLeafs = options.getNumLeafs.bind(this);
196
- if (options.getPageWidth) this.book.getPageWidth = options.getPageWidth.bind(this);
197
- if (options.getPageHeight) this.book.getPageHeight = options.getPageHeight.bind(this);
198
- if (options.getPageURI) this.book.getPageURI = options.getPageURI.bind(this);
199
- if (options.getPageSide) this.book.getPageSide = options.getPageSide.bind(this);
200
- if (options.getPageNum) this.book.getPageNum = options.getPageNum.bind(this);
201
- if (options.getPageProp) this.book.getPageProp = options.getPageProp.bind(this);
202
- if (options.getSpreadIndices) this.book.getSpreadIndices = options.getSpreadIndices.bind(this);
203
- if (options.leafNumToIndex) this.book.leafNumToIndex = options.leafNumToIndex.bind(this);
204
-
205
- /**
206
- * @private Components are 'subchunks' of bookreader functionality, usually UI related
207
- * They should be relatively decoupled from each other/bookreader.
208
- * Note there are no hooks right now; components just provide methods that bookreader
209
- * calls at the correct moments.
210
- **/
211
- this._components = {
212
- navbar: new Navbar(this),
213
- toolbar: new Toolbar(this)
214
- };
215
- this._modes = {
216
- mode1Up: new Mode1Up(this, this.book),
217
- mode2Up: new Mode2Up(this, this.book),
218
- modeThumb: new ModeThumb(this, this.book)
219
- };
220
-
221
- /** Stores classes which we want to expose (selectively) some methods as overridable */
222
- this._overrideable = {
223
- 'book': this.book,
224
- '_components.navbar': this._components.navbar,
225
- '_components.toolbar': this._components.toolbar,
226
- '_modes.mode1Up': this._modes.mode1Up,
227
- '_modes.mode2Up': this._modes.mode2Up,
228
- '_modes.modeThumb': this._modes.modeThumb
229
- };
230
-
231
- /** Image cache for general image fetching */
232
- this.imageCache = new ImageCache(this.book, {
233
- useSrcSet: this.options.useSrcSet,
234
- reduceSet: this.reduceSet
235
- });
236
-
237
- /**
238
- * Flag if BookReader has "focus" for keyboard shortcuts
239
- * Initially true, set to false when:
240
- * - BookReader scrolled out of view
241
- * Set to true when:
242
- * - BookReader scrolled into view
243
- */
244
- this.hasKeyFocus = true;
245
- };
246
-
247
- /**
248
- * Get all the HTML Elements that are being/can be rendered.
249
- * Includes cached elements which might be rendered again.
250
- */
251
- BookReader.prototype.getActivePageContainerElements = function () {
252
- var containerEls = Object.values(this._modes.mode2Up.mode2UpLit.pageContainerCache).map(pc => pc.$container[0]).concat(Object.values(this._modes.mode1Up.mode1UpLit.pageContainerCache).map(pc => pc.$container[0]));
253
- if (this.mode == this.constModeThumb) {
254
- containerEls = containerEls.concat(this.$('.BRpagecontainer').toArray());
255
- }
256
- return containerEls;
257
- };
258
-
259
- /**
260
- * Get the HTML Elements for the rendered page. Note there can be more than one, since
261
- * (at least as of writing) different modes can maintain different caches.
262
- * @param {PageIndex} pageIndex
263
- */
264
- BookReader.prototype.getActivePageContainerElementsForIndex = function (pageIndex) {
265
- var _this$_modes$mode2Up$, _this$_modes$mode1Up$;
266
- return [(_this$_modes$mode2Up$ = this._modes.mode2Up.mode2UpLit.pageContainerCache[pageIndex]) === null || _this$_modes$mode2Up$ === void 0 || (_this$_modes$mode2Up$ = _this$_modes$mode2Up$.$container) === null || _this$_modes$mode2Up$ === void 0 ? void 0 : _this$_modes$mode2Up$[0], (_this$_modes$mode1Up$ = this._modes.mode1Up.mode1UpLit.pageContainerCache[pageIndex]) === null || _this$_modes$mode1Up$ === void 0 || (_this$_modes$mode1Up$ = _this$_modes$mode1Up$.$container) === null || _this$_modes$mode1Up$ === void 0 ? void 0 : _this$_modes$mode1Up$[0], ...(this.mode == this.constModeThumb ? this.$(".pagediv".concat(pageIndex)).toArray() : [])].filter(x => x);
267
- };
268
- Object.defineProperty(BookReader.prototype, 'activeMode', {
269
- /** @return {Mode1Up | Mode2Up | ModeThumb} */
270
- get() {
271
- return {
272
- 1: this._modes.mode1Up,
273
- 2: this._modes.mode2Up,
274
- 3: this._modes.modeThumb
275
- }[this.mode];
276
- }
277
- });
278
-
279
- /**
280
- * BookReader.util are static library functions
281
- * At top of file so they can be used below
282
- */
283
- BookReader.util = utils;
284
-
285
- /**
286
- * Helper to merge in params in to a params object.
287
- * It normalizes "page" into the "index" field to disambiguate and prevent concflicts
288
- * @private
289
- */
290
- BookReader.prototype.extendParams = function (params, newParams) {
291
- var modifiedNewParams = $.extend({}, newParams);
292
- if ('undefined' != typeof modifiedNewParams.page) {
293
- var pageIndex = this.book.parsePageString(modifiedNewParams.page);
294
- if (!isNaN(pageIndex)) modifiedNewParams.index = pageIndex;
295
- delete modifiedNewParams.page;
296
- }
297
- $.extend(params, modifiedNewParams);
298
- };
299
-
300
- /**
301
- * Parses params from from various initialization contexts (url, cookie, options)
302
- * @private
303
- * @return {object} the parsed params
304
- */
305
- BookReader.prototype.initParams = function () {
306
- var params = {};
307
- // Flag initializing for updateFromParams()
308
- params.init = true;
309
-
310
- // Flag if page given in defaults or URL (not cookie)
311
- // Used for overriding goToFirstResult in plugin.search.js
312
- // Note: extendParams() converts params.page to index and gets rid of page
313
- // so check and set before extendParams()
314
- params.pageFound = false;
315
-
316
- // True if changing the URL
317
- params.fragmentChange = false;
318
-
319
- // This is ordered from lowest to highest priority
320
-
321
- // If we have a title leaf, use that as the default instead of index 0,
322
- // but only use as default if book has a few pages
323
- if ('undefined' != typeof this.titleLeaf && this.book.getNumLeafs() > 2) {
324
- params.index = this.book.leafNumToIndex(this.titleLeaf);
325
- } else {
326
- params.index = 0;
327
- }
328
-
329
- // this.defaults is a string passed in the url format. eg "page/1/mode/1up"
330
- if (this.defaults) {
331
- var defaultParams = this.paramsFromFragment(this.defaults);
332
- if ('undefined' != typeof defaultParams.page) {
333
- params.pageFound = true;
334
- }
335
- this.extendParams(params, defaultParams);
336
- }
337
-
338
- // Check for Resume plugin
339
- if (this.options.enablePageResume) {
340
- // Check cookies
341
- var val = this.getResumeValue();
342
- if (val !== null) {
343
- // If page index different from default
344
- if (params.index !== val) {
345
- // Show in URL
346
- params.fragmentChange = true;
347
- }
348
- params.index = val;
349
- }
350
- }
351
-
352
- // Check for URL plugin
353
- if (this.options.enableUrlPlugin) {
354
- // Params explicitly set in URL take precedence over all other methods
355
- var urlParams = this.paramsFromFragment(this.urlReadFragment());
356
-
357
- // Get params if hash fragment available with 'history' urlMode
358
- var hasHashURL = !Object.keys(urlParams).length && this.urlReadHashFragment();
359
- if (hasHashURL && this.options.urlMode === 'history') {
360
- urlParams = this.paramsFromFragment(this.urlReadHashFragment());
361
- }
362
-
363
- // If there were any parameters
364
- if (Object.keys(urlParams).length) {
365
- if ('undefined' != typeof urlParams.page) {
366
- params.pageFound = true;
367
- }
368
- this.extendParams(params, urlParams);
369
- // Show in URL
370
- params.fragmentChange = true;
371
- }
372
- }
373
-
374
- // Check for Search plugin
375
- if (this.options.enableSearch) {
376
- // Go to first result only if no default or URL page
377
- this.options.goToFirstResult = !params.pageFound;
378
-
379
- // If initialSearchTerm not set
380
- if (!this.options.initialSearchTerm) {
381
- // Look for any term in URL
382
- if (params.search) {
383
- // Old style: /search/[term]
384
- this.options.initialSearchTerm = params.search;
385
- this.searchTerm = params.search;
386
- } else {
387
- // If we have a query string: q=[term]
388
- var searchParams = new URLSearchParams(this.readQueryString());
389
- var searchTerm = searchParams.get('q');
390
- if (searchTerm) {
391
- this.options.initialSearchTerm = utils.decodeURIComponentPlus(searchTerm);
392
- }
393
- }
394
- }
395
- }
396
-
397
- // Set for init process, return to false at end of init()
398
- this.suppressFragmentChange = !params.fragmentChange;
399
- return params;
400
- };
401
-
402
- /**
403
- * Allow mocking of window.location.search
404
- */
405
- BookReader.prototype.getLocationSearch = function () {
406
- return window.location.search;
407
- };
408
-
409
- /**
410
- * Allow mocking of window.location.hash
411
- */
412
- BookReader.prototype.getLocationHash = function () {
413
- return window.location.hash;
414
- };
415
-
416
- /**
417
- * Return URL or fragment querystring
418
- */
419
- BookReader.prototype.readQueryString = function () {
420
- var queryString = this.getLocationSearch();
421
- if (queryString) {
422
- return queryString;
423
- }
424
- var hash = this.getLocationHash();
425
- var found = hash.search(/\?\w+=/);
426
- return found > -1 ? hash.slice(found) : '';
427
- };
428
-
429
- /**
430
- * Determines the initial mode for starting if a mode is not already
431
- * present in the params argument
432
- * @param {object} params
433
- * @return {1 | 2 | 3} the initial mode
434
- */
435
- BookReader.prototype.getInitialMode = function (params) {
436
- // if mobile breakpoint, we always show this.constMode1up mode
437
- var windowWidth = $(window).width();
438
- var isMobile = windowWidth && windowWidth <= this.onePageMinBreakpoint;
439
- var initialMode;
440
- if (params.mode) {
441
- initialMode = params.mode;
442
- } else if (isMobile) {
443
- initialMode = this.constMode1up;
444
- } else {
445
- initialMode = this.constMode2up;
446
- }
447
- if (!this.canSwitchToMode(initialMode)) {
448
- initialMode = this.constMode1up;
449
- }
450
-
451
- // override defaults mode via `options.defaults` metadata
452
- if (this.options.defaults) {
453
- try {
454
- initialMode = _modeStringToNumber(this.options.defaults);
455
- } catch (e) {
456
- // Can ignore this error
457
- }
458
- }
459
- return initialMode;
460
- };
461
-
462
- /**
463
- * Converts a mode string to a the mode numeric constant
464
- * @param {'mode/1up'|'mode/2up'|'mode/thumb'} modeString
465
- * @return {1 | 2 | 3}
466
- */
467
- export function _modeStringToNumber(modeString) {
468
- var MAPPING = {
469
- 'mode/1up': 1,
470
- 'mode/2up': 2,
471
- 'mode/thumb': 3
472
- };
473
- if (!(modeString in MAPPING)) {
474
- throw new OptionsParseError("Invalid mode string: ".concat(modeString));
475
- }
476
- return MAPPING[modeString];
477
- }
478
-
479
- /**
480
- * This is called by the client to initialize BookReader.
481
- * It renders onto the DOM. It should only be called once.
482
- */
483
- BookReader.prototype.init = function () {
484
- this.init.initComplete = false;
485
- this.pageScale = this.reduce; // preserve current reduce
486
-
487
- var params = this.initParams();
488
- this.firstIndex = params.index ? params.index : 0;
489
-
490
- // Setup Navbars and other UI
491
- this.isTouchDevice = !!('ontouchstart' in window) || !!('msmaxtouchpoints' in window.navigator);
492
- this.refs.$br = $(this.el).empty().removeClass().addClass("ui-" + this.ui).addClass("br-ui-" + this.ui).addClass('BookReader');
493
-
494
- // Add a class if this is a touch enabled device
495
- if (this.isTouchDevice) {
496
- this.refs.$br.addClass("touch");
497
- } else {
498
- this.refs.$br.addClass("no-touch");
499
- }
500
- this.refs.$brContainer = $("<div class='BRcontainer' dir='ltr'></div>");
501
- this.refs.$br.append(this.refs.$brContainer);
502
-
503
- // Explicitly ensure params.mode exists for updateFromParams() below
504
- params.mode = this.getInitialMode(params);
505
-
506
- // Explicitly ensure this.mode exists for initNavbar() below
507
- this.mode = params.mode;
508
-
509
- // Display Navigation
510
- if (this.options.showToolbar) {
511
- this.initToolbar(this.mode, this.ui); // Build inside of toolbar div
512
- }
513
- if (this.options.showNavbar) {
514
- // default navigation
515
- this.initNavbar();
516
- }
517
-
518
- // Switch navbar controls on mobile/desktop
519
- this._components.navbar.switchNavbarControls();
520
- this.resizeBRcontainer();
521
- this.updateFromParams(params);
522
- this.initUIStrings();
523
-
524
- // Bind to events
525
-
526
- this.bindNavigationHandlers();
527
- this.setupKeyListeners();
528
- this.lastScroll = new Date().getTime();
529
- this.refs.$brContainer.on('scroll', this, function (e) {
530
- // Note, this scroll event fires for both user, and js generated calls
531
- // It is functioning in some cases as the primary triggerer for rendering
532
- e.data.lastScroll = new Date().getTime();
533
- if (e.data.constModeThumb == e.data.mode) {
534
- e.data.drawLeafsThrottled();
535
- }
536
- });
537
- if (this.options.autoResize) {
538
- $(window).on('resize', this, function (e) {
539
- e.data.resize();
540
- });
541
- $(window).on("orientationchange", this, function (e) {
542
- e.data.resize();
543
- }.bind(this));
544
- }
545
- if (this.protected) {
546
- this.$('.BRicon.share').hide();
547
- }
548
-
549
- // If not searching, set to allow on-going fragment changes
550
- if (!this.options.initialSearchTerm) {
551
- this.suppressFragmentChange = false;
552
- }
553
- if (this.options.startFullscreen) {
554
- this.enterFullscreen(true);
555
- }
556
- this.init.initComplete = true;
557
- this.trigger(BookReader.eventNames.PostInit);
558
-
559
- // Must be called after this.init.initComplete set to true to allow
560
- // BookReader.prototype.resize to run.
561
- };
562
-
563
- /**
564
- * @param {EVENTS} name
565
- * @param {array | object} [props]
566
- */
567
- BookReader.prototype.trigger = function (name) {
568
- var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this;
569
- var eventName = 'BookReader:' + name;
570
- utils.polyfillCustomEvent(window);
571
- window.dispatchEvent(new CustomEvent(eventName, {
572
- bubbles: true,
573
- composed: true,
574
- detail: {
575
- props
576
- }
577
- }));
578
- $(document).trigger(eventName, props);
579
- };
580
- BookReader.prototype.bind = function (name, callback) {
581
- $(document).on('BookReader:' + name, callback);
582
- };
583
- BookReader.prototype.unbind = function (name, callback) {
584
- $(document).off('BookReader:' + name, callback);
585
- };
586
-
587
- /**
588
- * Resizes based on the container width and height
589
- */
590
- BookReader.prototype.resize = function () {
591
- if (!this.init.initComplete) return;
592
- this.resizeBRcontainer();
593
-
594
- // Switch navbar controls on mobile/desktop
595
- this._components.navbar.switchNavbarControls();
596
- if (this.constMode1up == this.mode) {
597
- if (this.onePage.autofit != 'none') {
598
- this._modes.mode1Up.resizePageView();
599
- this.centerPageView();
600
- } else {
601
- this.centerPageView();
602
- this.displayedIndices = [];
603
- this.drawLeafsThrottled();
604
- }
605
- } else if (this.constModeThumb == this.mode) {
606
- this._modes.modeThumb.prepare();
607
- } else {
608
- this._modes.mode2Up.resizePageView();
609
- }
610
- this.trigger(BookReader.eventNames.resize);
611
- };
612
-
613
- /**
614
- * Binds keyboard and keyboard focus event listeners
615
- */
616
- BookReader.prototype.setupKeyListeners = function () {
617
- // Keyboard focus by BookReader in viewport
618
- //
619
- // Intersection observer and callback sets BookReader keyboard
620
- // "focus" flag off when the BookReader is not in the viewport.
621
- if (window.IntersectionObserver) {
622
- var observer = new IntersectionObserver(entries => {
623
- entries.forEach(entry => {
624
- if (entry.intersectionRatio === 0) {
625
- this.hasKeyFocus = false;
626
- } else {
627
- this.hasKeyFocus = true;
628
- }
629
- });
630
- }, {
631
- root: null,
632
- rootMargin: '0px',
633
- threshold: [0, 0.05, 1]
634
- });
635
- observer.observe(this.refs.$br[0]);
636
- }
637
-
638
- // Keyboard listeners
639
- document.addEventListener('keydown', e => {
640
- // Ignore if BookReader "focus" flag not set
641
- if (!this.hasKeyFocus) {
642
- return;
643
- }
644
-
645
- // Ignore if modifiers are active.
646
- if (e.getModifierState('Control') || e.getModifierState('Alt') || e.getModifierState('Meta') || e.getModifierState('Win') /* hack for IE */) {
647
- return;
648
- }
649
-
650
- // Ignore in input elements
651
- if (utils.isInputActive()) {
652
- return;
653
- }
654
-
655
- // KeyboardEvent code values:
656
- // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values
657
- switch (e.key) {
658
- // Page navigation
659
- case "Home":
660
- e.preventDefault();
661
- this.first();
662
- break;
663
- case "End":
664
- e.preventDefault();
665
- this.last();
666
- break;
667
- case "ArrowDown":
668
- case "PageDown":
669
- case "Down":
670
- // hack for IE and old Gecko
671
- // In 1up and thumb mode page scrolling handled by browser
672
- if (this.constMode2up === this.mode) {
673
- e.preventDefault();
674
- this.next();
675
- }
676
- break;
677
- case "ArrowUp":
678
- case "PageUp":
679
- case "Up":
680
- // hack for IE and old Gecko
681
- // In 1up and thumb mode page scrolling handled by browser
682
- if (this.constMode2up === this.mode) {
683
- e.preventDefault();
684
- this.prev();
685
- }
686
- break;
687
- case "ArrowLeft":
688
- case "Left":
689
- // hack for IE and old Gecko
690
- // No y-scrolling in thumb mode
691
- if (this.constModeThumb != this.mode) {
692
- e.preventDefault();
693
- this.left();
694
- }
695
- break;
696
- case "ArrowRight":
697
- case "Right":
698
- // hack for IE and old Gecko
699
- // No y-scrolling in thumb mode
700
- if (this.constModeThumb != this.mode) {
701
- e.preventDefault();
702
- this.right();
703
- }
704
- break;
705
- // Zoom
706
- case '-':
707
- case 'Subtract':
708
- e.preventDefault();
709
- this.zoom(-1);
710
- break;
711
- case '+':
712
- case '=':
713
- case 'Add':
714
- e.preventDefault();
715
- this.zoom(1);
716
- break;
717
- // Fullscreen
718
- case 'F':
719
- case 'f':
720
- e.preventDefault();
721
- this.toggleFullscreen();
722
- break;
723
- }
724
- });
725
- };
726
- BookReader.prototype.drawLeafs = function () {
727
- if (this.constMode1up == this.mode) {
728
- // Not needed for Mode1Up anymore
729
- return;
730
- } else {
731
- this.activeMode.drawLeafs();
732
- }
733
- };
734
-
735
- /**
736
- * @protected
737
- * @param {PageIndex} index
738
- */
739
- BookReader.prototype._createPageContainer = function (index) {
740
- return new PageContainer(this.book.getPage(index, false), {
741
- isProtected: this.protected,
742
- imageCache: this.imageCache,
743
- loadingImage: this.imagesBaseURL + 'loading.gif'
744
- });
745
- };
746
- BookReader.prototype.bindGestures = function (jElement) {
747
- // TODO support gesture change is only iOS. Support android.
748
- // HACK(2017-01-20) - Momentum scrolling is causing the scroll position
749
- // to jump after zooming in on mobile device. I am able to reproduce
750
- // when you move the book with one finger and then add another
751
- // finger to pinch. Gestures are aware of scroll state.
752
-
753
- var self = this;
754
- var numTouches = 1;
755
- jElement.unbind('touchmove').bind('touchmove', function (e) {
756
- if (e.originalEvent.cancelable) numTouches = e.originalEvent.touches.length;
757
- e.stopPropagation();
758
- });
759
- jElement.unbind('gesturechange').bind('gesturechange', function (e) {
760
- e.preventDefault();
761
- // These are two very important fixes to adjust for the scroll position
762
- // issues described below
763
- if (!(numTouches !== 2 || new Date().getTime() - self.lastScroll < 500)) {
764
- if (e.originalEvent.scale > 1.5) {
765
- self.zoom(1);
766
- } else if (e.originalEvent.scale < 0.6) {
767
- self.zoom(-1);
768
- }
769
- }
770
- });
771
- };
772
-
773
- /**
774
- * A throttled version of drawLeafs
775
- */
776
- BookReader.prototype.drawLeafsThrottled = utils.throttle(BookReader.prototype.drawLeafs, 250 // 250 ms gives quick feedback, but doesn't eat cpu
777
- );
778
-
779
- /**
780
- * @param {number} direction Pass 1 to zoom in, anything else to zoom out
781
- */
782
- BookReader.prototype.zoom = function (direction) {
783
- var _this$textSelectionPl;
784
- if (direction == 1) {
785
- this.activeMode.zoom('in');
786
- } else {
787
- this.activeMode.zoom('out');
788
- }
789
- (_this$textSelectionPl = this.textSelectionPlugin) === null || _this$textSelectionPl === void 0 || _this$textSelectionPl.stopPageFlip(this.refs.$brContainer);
790
- return;
791
- };
792
-
793
- /**
794
- * Resizes the inner container to fit within the visible space to prevent
795
- * the top toolbar and bottom navbar from clipping the visible book
796
- *
797
- * @param { boolean } animate - optional
798
- * When used, BookReader will fill the main container with the book's content.
799
- * This is primarily for 1up view - a follow up animation to the nav animation
800
- * So resize isn't perceived sharp/jerky
801
- */
802
- BookReader.prototype.resizeBRcontainer = function (animate) {
803
- if (animate) {
804
- this.refs.$brContainer.animate({
805
- top: this.getToolBarHeight(),
806
- bottom: this.getFooterHeight()
807
- }, this.constResizeAnimationDuration, 'linear');
808
- } else {
809
- this.refs.$brContainer.css({
810
- top: this.getToolBarHeight(),
811
- bottom: this.getFooterHeight()
812
- });
813
- }
814
- };
815
- BookReader.prototype.centerPageView = function () {
816
- var scrollWidth = this.refs.$brContainer.prop('scrollWidth');
817
- var clientWidth = this.refs.$brContainer.prop('clientWidth');
818
- if (scrollWidth > clientWidth) {
819
- this.refs.$brContainer.prop('scrollLeft', (scrollWidth - clientWidth) / 2);
820
- }
821
- };
822
-
823
- /**
824
- * Quantizes the given reduction factor to closest power of two from set from 12.5% to 200%
825
- * @param {number} reduce
826
- * @param {ReductionFactor[]} reductionFactors
827
- * @return {number}
828
- */
829
- BookReader.prototype.quantizeReduce = function (reduce, reductionFactors) {
830
- var quantized = reductionFactors[0].reduce;
831
- var distance = Math.abs(reduce - quantized);
832
- for (var i = 1; i < reductionFactors.length; i++) {
833
- var newDistance = Math.abs(reduce - reductionFactors[i].reduce);
834
- if (newDistance < distance) {
835
- distance = newDistance;
836
- quantized = reductionFactors[i].reduce;
837
- }
838
- }
839
- return quantized;
840
- };
841
-
842
- /**
843
- * @param {number} currentReduce
844
- * @param {'in' | 'out' | 'auto' | 'height' | 'width'} direction
845
- * @param {ReductionFactor[]} reductionFactors Must be sorted
846
- * @returns {ReductionFactor}
847
- */
848
- BookReader.prototype.nextReduce = function (currentReduce, direction, reductionFactors) {
849
- // XXX add 'closest', to replace quantize function
850
-
851
- if (direction === 'in') {
852
- var newReduceIndex = 0;
853
- for (var i = 1; i < reductionFactors.length; i++) {
854
- if (reductionFactors[i].reduce < currentReduce) {
855
- newReduceIndex = i;
856
- }
857
- }
858
- return reductionFactors[newReduceIndex];
859
- } else if (direction === 'out') {
860
- var lastIndex = reductionFactors.length - 1;
861
- var _newReduceIndex = lastIndex;
862
- for (var _i = lastIndex; _i >= 0; _i--) {
863
- if (reductionFactors[_i].reduce > currentReduce) {
864
- _newReduceIndex = _i;
865
- }
866
- }
867
- return reductionFactors[_newReduceIndex];
868
- } else if (direction === 'auto') {
869
- // If an 'auto' is specified, use that
870
- var autoMatch = reductionFactors.find(rf => rf.autofit == 'auto');
871
- if (autoMatch) return autoMatch;
872
-
873
- // Otherwise, choose the least reduction from height/width
874
- var candidates = reductionFactors.filter(_ref => {
875
- var {
876
- autofit
877
- } = _ref;
878
- return autofit == 'height' || autofit == 'width';
879
- });
880
- var choice = null;
881
- for (var _i2 = 0; _i2 < candidates.length; _i2++) {
882
- if (choice === null || choice.reduce < candidates[_i2].reduce) {
883
- choice = candidates[_i2];
884
- }
885
- }
886
- if (choice) return choice;
887
- } else if (direction === 'height' || direction === 'width') {
888
- // Asked for specific autofit mode
889
- var match = reductionFactors.find(rf => rf.autofit == direction);
890
- if (match) return match;
891
- }
892
- return reductionFactors[0];
893
- };
894
-
895
- /**
896
- * @param {ReductionFactor} a
897
- * @param {ReductionFactor} b
898
- */
899
- BookReader.prototype._reduceSort = (a, b) => a.reduce - b.reduce;
900
-
901
- /**
902
- * Attempts to jump to page
903
- * @param {string}
904
- * @return {boolean} Returns true if page could be found, false otherwise.
905
- */
906
- BookReader.prototype.jumpToPage = function (pageNum) {
907
- var pageIndex = this.book.parsePageString(pageNum);
908
- if ('undefined' != typeof pageIndex) {
909
- this.jumpToIndex(pageIndex);
910
- return true;
911
- }
912
-
913
- // Page not found
914
- return false;
915
- };
916
-
917
- /**
918
- * Check whether the specified index is currently displayed
919
- * @param {PageIndex} index
920
- */
921
- BookReader.prototype._isIndexDisplayed = function (index) {
922
- return this.displayedIndices ? this.displayedIndices.includes(index) : this.currentIndex() == index;
923
- };
924
-
925
- /**
926
- * Changes the current page
927
- * @param {PageIndex} index
928
- * @param {number} [pageX]
929
- * @param {number} [pageY]
930
- * @param {boolean} [noAnimate]
931
- */
932
- BookReader.prototype.jumpToIndex = function (index, pageX, pageY, noAnimate) {
933
- // Don't jump into specific unviewable page
934
- var page = this.book.getPage(index);
935
- if (!page.isViewable && page.unviewablesStart != page.index) {
936
- // If already in unviewable range, jump to end of that range
937
- var alreadyInPreview = this._isIndexDisplayed(page.unviewablesStart);
938
- var newIndex = alreadyInPreview ? page.findNext({
939
- combineConsecutiveUnviewables: true
940
- }).index : page.unviewablesStart;
941
- return this.jumpToIndex(newIndex, pageX, pageY, noAnimate);
942
- }
943
- this.trigger(BookReader.eventNames.stop);
944
- this.activeMode.jumpToIndex(index, pageX, pageY, noAnimate);
945
- };
946
-
947
- /**
948
- * Return mode or 1up if initial thumb
949
- * @param {number}
950
- */
951
- BookReader.prototype.getPrevReadMode = function (mode) {
952
- if (mode === BookReader.constMode1up || mode === BookReader.constMode2up) {
953
- return mode;
954
- } else if (this.prevReadMode === null) {
955
- // Initial thumb, return 1up
956
- return BookReader.constMode1up;
957
- }
958
- };
959
-
960
- /**
961
- * Switches the mode (eg 1up 2up thumb)
962
- * @param {number}
963
- * @param {object} [options]
964
- * @param {boolean} [options.suppressFragmentChange = false]
965
- * @param {boolean} [options.onInit = false] - this
966
- */
967
- BookReader.prototype.switchMode = function (mode) {
968
- var _this$textSelectionPl2;
969
- var {
970
- suppressFragmentChange = false,
971
- init = false,
972
- pageFound = false
973
- } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
974
- // Skip checks before init() complete
975
- if (this.init.initComplete) {
976
- if (mode === this.mode) {
977
- return;
978
- }
979
- if (!this.canSwitchToMode(mode)) {
980
- return;
981
- }
982
- }
983
- this.trigger(BookReader.eventNames.stop);
984
- this.prevReadMode = this.getPrevReadMode(this.mode);
985
- if (this.mode != mode) {
986
- var _this$activeMode$unpr, _this$activeMode;
987
- (_this$activeMode$unpr = (_this$activeMode = this.activeMode).unprepare) === null || _this$activeMode$unpr === void 0 || _this$activeMode$unpr.call(_this$activeMode);
988
- }
989
- this.mode = mode;
990
-
991
- // reinstate scale if moving from thumbnail view
992
- if (this.pageScale !== this.reduce) {
993
- this.reduce = this.pageScale;
994
- }
995
-
996
- // $$$ TODO preserve center of view when switching between mode
997
- // See https://bugs.edge.launchpad.net/gnubook/+bug/416682
998
-
999
- // XXX maybe better to preserve zoom in each mode
1000
- if (this.constMode1up == mode) {
1001
- this._modes.mode1Up.prepare();
1002
- } else if (this.constModeThumb == mode) {
1003
- this.reduce = this.quantizeReduce(this.reduce, this.reductionFactors);
1004
- this._modes.modeThumb.prepare();
1005
- } else {
1006
- this._modes.mode2Up.prepare();
1007
- }
1008
- if (!(this.suppressFragmentChange || suppressFragmentChange)) {
1009
- this.trigger(BookReader.eventNames.fragmentChange);
1010
- }
1011
- var eventName = mode + 'PageViewSelected';
1012
- this.trigger(BookReader.eventNames[eventName]);
1013
- (_this$textSelectionPl2 = this.textSelectionPlugin) === null || _this$textSelectionPl2 === void 0 || _this$textSelectionPl2.stopPageFlip(this.refs.$brContainer);
1014
- };
1015
- BookReader.prototype.updateBrClasses = function () {
1016
- var modeToClass = {};
1017
- modeToClass[this.constMode1up] = 'BRmode1up';
1018
- modeToClass[this.constMode2up] = 'BRmode2up';
1019
- modeToClass[this.constModeThumb] = 'BRmodeThumb';
1020
- this.refs.$br.removeClass('BRmode1up BRmode2up BRmodeThumb').addClass(modeToClass[this.mode]);
1021
- if (this.isFullscreen()) {
1022
- this.refs.$br.addClass('fullscreenActive');
1023
- $(document.body).addClass('BRfullscreenActive');
1024
- } else {
1025
- this.refs.$br.removeClass('fullscreenActive');
1026
- $(document.body).removeClass('BRfullscreenActive');
1027
- }
1028
- };
1029
- BookReader.prototype.isFullscreen = function () {
1030
- return this.isFullscreenActive;
1031
- };
1032
-
1033
- /**
1034
- * Toggles fullscreen
1035
- * @param { boolean } bindKeyboardControls
1036
- */
1037
- BookReader.prototype.toggleFullscreen = /*#__PURE__*/_asyncToGenerator(function* () {
1038
- var bindKeyboardControls = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
1039
- if (this.isFullscreen()) {
1040
- yield this.exitFullScreen();
1041
- } else {
1042
- yield this.enterFullscreen(bindKeyboardControls);
1043
- }
1044
- });
1045
-
1046
- /**
1047
- * Enters fullscreen
1048
- * including:
1049
- * - binds keyboard controls
1050
- * - fires custom event
1051
- * @param { boolean } bindKeyboardControls
1052
- */
1053
- BookReader.prototype.enterFullscreen = /*#__PURE__*/_asyncToGenerator(function* () {
1054
- var _this$textSelectionPl3;
1055
- var bindKeyboardControls = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
1056
- this.refs.$br.addClass('BRfullscreenAnimation');
1057
- var currentIndex = this.currentIndex();
1058
- if (bindKeyboardControls) {
1059
- this._fullscreenCloseHandler = e => {
1060
- if (e.keyCode === 27) this.toggleFullscreen();
1061
- };
1062
- $(document).on("keyup", this._fullscreenCloseHandler);
1063
- }
1064
- var windowWidth = $(window).width();
1065
- if (windowWidth <= this.onePageMinBreakpoint) {
1066
- this.switchMode(this.constMode1up);
1067
- }
1068
- this.isFullscreenActive = true;
1069
- // prioritize class updates so CSS can propagate
1070
- this.updateBrClasses();
1071
- if (this.activeMode instanceof Mode1Up) {
1072
- this.activeMode.mode1UpLit.scale = this.activeMode.mode1UpLit.computeDefaultScale(this.book.getPage(currentIndex));
1073
- // Need the new scale to be applied before calling jumpToIndex
1074
- this.activeMode.mode1UpLit.requestUpdate();
1075
- yield this.activeMode.mode1UpLit.updateComplete;
1076
- }
1077
- this.jumpToIndex(currentIndex);
1078
- (_this$textSelectionPl3 = this.textSelectionPlugin) === null || _this$textSelectionPl3 === void 0 || _this$textSelectionPl3.stopPageFlip(this.refs.$brContainer);
1079
- // Add "?view=theater"
1080
- this.trigger(BookReader.eventNames.fragmentChange);
1081
- // trigger event here, so that animations,
1082
- // class updates happen before book-nav relays to web components
1083
- this.trigger(BookReader.eventNames.fullscreenToggled);
1084
-
1085
- // resize book after all events & css updates
1086
- yield new Promise(resolve => setTimeout(resolve, 0));
1087
- this.resize();
1088
- this.refs.$br.removeClass('BRfullscreenAnimation');
1089
- });
1090
-
1091
- /**
1092
- * Exits fullscreen
1093
- * - toggles fullscreen
1094
- * - binds keyboard controls
1095
- * - fires custom event
1096
- * @param { boolean } bindKeyboardControls
1097
- */
1098
- BookReader.prototype.exitFullScreen = /*#__PURE__*/_asyncToGenerator(function* () {
1099
- var _this$textSelectionPl4;
1100
- this.refs.$br.addClass('BRfullscreenAnimation');
1101
- $(document).off('keyup', this._fullscreenCloseHandler);
1102
- var windowWidth = $(window).width();
1103
- var canShow2up = this.options.controls.twoPage.visible;
1104
- if (canShow2up && windowWidth <= this.onePageMinBreakpoint) {
1105
- this.switchMode(this.constMode2up);
1106
- }
1107
- this.isFullscreenActive = false;
1108
- // Trigger fullscreen event immediately
1109
- // so that book-nav can relay to web components
1110
- this.trigger(BookReader.eventNames.fullscreenToggled);
1111
- this.updateBrClasses();
1112
- yield new Promise(resolve => setTimeout(resolve, 0));
1113
- this.resize();
1114
- if (this.activeMode instanceof Mode1Up) {
1115
- this.activeMode.mode1UpLit.scale = this.activeMode.mode1UpLit.computeDefaultScale(this.book.getPage(this.currentIndex()));
1116
- this.activeMode.mode1UpLit.requestUpdate();
1117
- yield this.activeMode.mode1UpLit.updateComplete;
1118
- }
1119
- (_this$textSelectionPl4 = this.textSelectionPlugin) === null || _this$textSelectionPl4 === void 0 || _this$textSelectionPl4.stopPageFlip(this.refs.$brContainer);
1120
- // Remove "?view=theater"
1121
- this.trigger(BookReader.eventNames.fragmentChange);
1122
- this.refs.$br.removeClass('BRfullscreenAnimation');
1123
- });
1124
-
1125
- /**
1126
- * Returns the currently active index
1127
- * @return {number}
1128
- * @throws
1129
- */
1130
- BookReader.prototype.currentIndex = function () {
1131
- // $$$ we should be cleaner with our idea of which index is active in 1up/2up
1132
- if (this.mode == this.constMode1up || this.mode == this.constModeThumb) {
1133
- return this.firstIndex; // $$$ TODO page in center of view would be better
1134
- } else if (this.mode == this.constMode2up) {
1135
- // Only allow indices that are actually present in book
1136
- return utils.clamp(this.firstIndex, 0, this.book.getNumLeafs() - 1);
1137
- } else {
1138
- throw 'currentIndex called for unimplemented mode ' + this.mode;
1139
- }
1140
- };
1141
-
1142
- /**
1143
- * Setter for this.firstIndex
1144
- * Also triggers an event and updates the navbar slider position
1145
- * @param {number} index
1146
- * @param {object} [options]
1147
- * @param {boolean} [options.suppressFragmentChange = false]
1148
- */
1149
- BookReader.prototype.updateFirstIndex = function (index) {
1150
- var {
1151
- suppressFragmentChange = false
1152
- } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1153
- // If there's no change, do nothing
1154
- if (this.firstIndex === index) return;
1155
- this.firstIndex = index;
1156
- if (!(this.suppressFragmentChange || suppressFragmentChange)) {
1157
- this.trigger(BookReader.eventNames.fragmentChange);
1158
- }
1159
- // If there's an initial search we stop suppressing global URL changes
1160
- // when local suppression ends
1161
- // This seems to correctly handle multiple calls during mode/1up
1162
- if (this.options.initialSearchTerm && !suppressFragmentChange) {
1163
- this.suppressFragmentChange = false;
1164
- }
1165
- this.trigger(BookReader.eventNames.pageChanged);
1166
-
1167
- // event to know if user is actively reading
1168
- this.trigger(BookReader.eventNames.userAction);
1169
- this._components.navbar.updateNavIndexThrottled(index);
1170
- };
1171
-
1172
- /**
1173
- * Flip the right page over onto the left
1174
- */
1175
- BookReader.prototype.right = function () {
1176
- if ('rl' != this.pageProgression) {
1177
- this.next();
1178
- } else {
1179
- this.prev();
1180
- }
1181
- };
1182
-
1183
- /**
1184
- * Flip to the rightmost page
1185
- */
1186
- BookReader.prototype.rightmost = function () {
1187
- if ('rl' != this.pageProgression) {
1188
- this.last();
1189
- } else {
1190
- this.first();
1191
- }
1192
- };
1193
-
1194
- /**
1195
- * Flip the left page over onto the right
1196
- */
1197
- BookReader.prototype.left = function () {
1198
- if ('rl' != this.pageProgression) {
1199
- this.prev();
1200
- } else {
1201
- this.next();
1202
- }
1203
- };
1204
-
1205
- /**
1206
- * Flip to the leftmost page
1207
- */
1208
- BookReader.prototype.leftmost = function () {
1209
- if ('rl' != this.pageProgression) {
1210
- this.first();
1211
- } else {
1212
- this.last();
1213
- }
1214
- };
1215
- BookReader.prototype.next = function () {
1216
- var {
1217
- triggerStop = true
1218
- } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1219
- if (this.constMode2up == this.mode) {
1220
- if (triggerStop) this.trigger(BookReader.eventNames.stop);
1221
- this._modes.mode2Up.mode2UpLit.flipAnimation('next');
1222
- } else {
1223
- if (this.firstIndex < this.book.getNumLeafs() - 1) {
1224
- this.jumpToIndex(this.firstIndex + 1);
1225
- }
1226
- }
1227
- };
1228
- BookReader.prototype.prev = function () {
1229
- var {
1230
- triggerStop = true
1231
- } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1232
- var isOnFrontPage = this.firstIndex < 1;
1233
- if (isOnFrontPage) return;
1234
- if (this.constMode2up == this.mode) {
1235
- if (triggerStop) this.trigger(BookReader.eventNames.stop);
1236
- this._modes.mode2Up.mode2UpLit.flipAnimation('prev');
1237
- } else {
1238
- if (this.firstIndex >= 1) {
1239
- this.jumpToIndex(this.firstIndex - 1);
1240
- }
1241
- }
1242
- };
1243
- BookReader.prototype.first = function () {
1244
- this.jumpToIndex(0);
1245
- };
1246
- BookReader.prototype.last = function () {
1247
- this.jumpToIndex(this.book.getNumLeafs() - 1);
1248
- };
1249
-
1250
- /**
1251
- * @template TClass extends { br: BookReader }
1252
- * Helper method to expose a method onto BookReader from a composed class.
1253
- * Only composed classes in BookReader._overridable can be exposed in this
1254
- * way.
1255
- * @param {new () => TClass} Class
1256
- * @param {keyof BookReader['_overrideable']} classKey
1257
- * @param {keyof TClass} method
1258
- * @param {string} [brMethod]
1259
- */
1260
- function exposeOverrideableMethod(Class, classKey, method) {
1261
- var brMethod = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : method;
1262
- /** @type {function(TClass): BookReader} */
1263
- var classToBr = cls => cls.br;
1264
- /** @type {function(BookReader): TClass} */
1265
- var brToClass = br => br._overrideable[classKey];
1266
- exposeOverrideable(Class, method, classToBr, BookReader, brMethod, brToClass);
1267
- }
1268
-
1269
- /***********************/
1270
- /** Navbar extensions **/
1271
- /***********************/
1272
- /** This cannot be removed yet because plugin.tts.js overrides it */
1273
- BookReader.prototype.initNavbar = Navbar.prototype.init;
1274
- exposeOverrideableMethod(Navbar, '_components.navbar', 'init', 'initNavbar');
1275
-
1276
- /************************/
1277
- /** Toolbar extensions **/
1278
- /************************/
1279
- BookReader.prototype.buildToolbarElement = Toolbar.prototype.buildToolbarElement;
1280
- exposeOverrideableMethod(Toolbar, '_components.toolbar', 'buildToolbarElement');
1281
- BookReader.prototype.initToolbar = Toolbar.prototype.initToolbar;
1282
- exposeOverrideableMethod(Toolbar, '_components.toolbar', 'initToolbar');
1283
- BookReader.prototype.buildShareDiv = Toolbar.prototype.buildShareDiv;
1284
- exposeOverrideableMethod(Toolbar, '_components.toolbar', 'buildShareDiv');
1285
- BookReader.prototype.buildInfoDiv = Toolbar.prototype.buildInfoDiv;
1286
- exposeOverrideableMethod(Toolbar, '_components.toolbar', 'buildInfoDiv');
1287
- BookReader.prototype.getToolBarHeight = Toolbar.prototype.getToolBarHeight;
1288
- exposeOverrideableMethod(Toolbar, '_components.toolbar', 'getToolBarHeight');
1289
-
1290
- /**
1291
- * Bind navigation handlers
1292
- */
1293
- BookReader.prototype.bindNavigationHandlers = function () {
1294
- var self = this;
1295
- var jIcons = this.$('.BRicon');
1296
-
1297
- // Map of jIcon class -> click handler
1298
- var navigationControls = {
1299
- book_left: () => {
1300
- this.trigger(BookReader.eventNames.stop);
1301
- this.left();
1302
- },
1303
- book_right: () => {
1304
- this.trigger(BookReader.eventNames.stop);
1305
- this.right();
1306
- },
1307
- book_top: this.first.bind(this),
1308
- book_bottom: this.last.bind(this),
1309
- book_leftmost: this.leftmost.bind(this),
1310
- book_rightmost: this.rightmost.bind(this),
1311
- onepg: () => {
1312
- this.switchMode(self.constMode1up);
1313
- },
1314
- thumb: () => {
1315
- this.switchMode(self.constModeThumb);
1316
- },
1317
- twopg: () => {
1318
- this.switchMode(self.constMode2up);
1319
- },
1320
- zoom_in: () => {
1321
- this.trigger(BookReader.eventNames.stop);
1322
- this.zoom(1);
1323
- this.trigger(BookReader.eventNames.zoomIn);
1324
- },
1325
- zoom_out: () => {
1326
- this.trigger(BookReader.eventNames.stop);
1327
- this.zoom(-1);
1328
- this.trigger(BookReader.eventNames.zoomOut);
1329
- },
1330
- full: () => {
1331
- if (this.ui == 'embed') {
1332
- var url = this.$('.BRembedreturn a').attr('href');
1333
- window.open(url);
1334
- } else {
1335
- this.toggleFullscreen();
1336
- }
1337
- }
1338
- };
1339
-
1340
- // custom event for auto-loan-renew in ia-book-actions
1341
- // - to know if user is actively reading
1342
- this.$('nav.BRcontrols li button').on('click', () => {
1343
- this.trigger(BookReader.eventNames.userAction);
1344
- });
1345
- var _loop = function _loop(control) {
1346
- jIcons.filter(".".concat(control)).on('click.bindNavigationHandlers', () => {
1347
- navigationControls[control]();
1348
- return false;
1349
- });
1350
- };
1351
- for (var control in navigationControls) {
1352
- _loop(control);
1353
- }
1354
- var $brNavCntlBtmEl = this.$('.BRnavCntlBtm');
1355
- var $brNavCntlTopEl = this.$('.BRnavCntlTop');
1356
- this.$('.BRnavCntl').click(function () {
1357
- var promises = [];
1358
- // TODO don't use magic constants
1359
- // TODO move this to a function
1360
- if ($brNavCntlBtmEl.hasClass('BRdn')) {
1361
- if (self.refs.$BRtoolbar) promises.push(self.refs.$BRtoolbar.animate({
1362
- top: self.getToolBarHeight() * -1
1363
- }).promise());
1364
- promises.push(self.$('.BRfooter').animate({
1365
- bottom: self.getFooterHeight() * -1
1366
- }).promise());
1367
- $brNavCntlBtmEl.addClass('BRup').removeClass('BRdn');
1368
- $brNavCntlTopEl.addClass('BRdn').removeClass('BRup');
1369
- self.$('.BRnavCntlBtm.BRnavCntl').animate({
1370
- height: '45px'
1371
- });
1372
- self.$('.BRnavCntl').delay(1000).animate({
1373
- opacity: .75
1374
- }, 1000);
1375
- } else {
1376
- if (self.refs.$BRtoolbar) promises.push(self.refs.$BRtoolbar.animate({
1377
- top: 0
1378
- }).promise());
1379
- promises.push(self.$('.BRfooter').animate({
1380
- bottom: 0
1381
- }).promise());
1382
- $brNavCntlBtmEl.addClass('BRdn').removeClass('BRup');
1383
- $brNavCntlTopEl.addClass('BRup').removeClass('BRdn');
1384
- self.$('.BRnavCntlBtm.BRnavCntl').animate({
1385
- height: '30px'
1386
- });
1387
- self.$('.BRvavCntl').animate({
1388
- opacity: 1
1389
- });
1390
- }
1391
- $.when.apply($, promises).done(function () {
1392
- // Only do full resize in auto mode and need to recalc. size
1393
- if (self.mode == self.constMode2up && self.twoPage.autofit != null && self.twoPage.autofit != 'none') {
1394
- self.resize();
1395
- } else if (self.mode == self.constMode1up && self.onePage.autofit != null && self.onePage.autofit != 'none') {
1396
- self.resize();
1397
- } else {
1398
- // Don't do a full resize to avoid redrawing images
1399
- self.resizeBRcontainer();
1400
- }
1401
- });
1402
- });
1403
- $brNavCntlBtmEl.on("mouseover", function () {
1404
- if ($(this).hasClass('BRup')) {
1405
- self.$('.BRnavCntl').animate({
1406
- opacity: 1
1407
- }, 250);
1408
- }
1409
- }).on("mouseleave", function () {
1410
- if ($(this).hasClass('BRup')) {
1411
- self.$('.BRnavCntl').animate({
1412
- opacity: .75
1413
- }, 250);
1414
- }
1415
- });
1416
- $brNavCntlTopEl.on("mouseover", function () {
1417
- if ($(this).hasClass('BRdn')) {
1418
- self.$('.BRnavCntl').animate({
1419
- opacity: 1
1420
- }, 250);
1421
- }
1422
- }).on("mouseleave", function () {
1423
- if ($(this).hasClass('BRdn')) {
1424
- self.$('.BRnavCntl').animate({
1425
- opacity: .75
1426
- }, 250);
1427
- }
1428
- });
1429
- };
1430
-
1431
- /**************************/
1432
- /** BookModel extensions **/
1433
- /**************************/
1434
- // Must modify petabox extension, which expects this on the prototype
1435
- // before removing.
1436
- BookReader.prototype.getPageURI = BookModel.prototype.getPageURI;
1437
- exposeOverrideableMethod(BookModel, 'book', 'getPageURI');
1438
-
1439
- // Parameter related functions
1440
-
1441
- /**
1442
- * Update from the params object
1443
- * @param {Object}
1444
- */
1445
- BookReader.prototype.updateFromParams = function (params) {
1446
- // Set init, fragment change options for switchMode()
1447
- var {
1448
- mode = 0,
1449
- init = false,
1450
- fragmentChange = false
1451
- } = params;
1452
- if (mode) {
1453
- this.switchMode(mode, {
1454
- init: init,
1455
- suppressFragmentChange: !fragmentChange
1456
- });
1457
- }
1458
-
1459
- // $$$ process /zoom
1460
- // We only respect page if index is not set
1461
- if ('undefined' != typeof params.index) {
1462
- if (params.index != this.currentIndex()) {
1463
- this.jumpToIndex(params.index);
1464
- }
1465
- } else if ('undefined' != typeof params.page) {
1466
- // $$$ this assumes page numbers are unique
1467
- if (params.page != this.book.getPageNum(this.currentIndex())) {
1468
- this.jumpToPage(params.page);
1469
- }
1470
- }
1471
-
1472
- // process /search
1473
- // @deprecated for urlMode 'history'
1474
- // Continues to work for urlMode 'hash'
1475
- if (this.enableSearch && 'undefined' != typeof params.search) {
1476
- if (this.searchTerm !== params.search) {
1477
- this.$('.BRsearchInput').val(params.search);
1478
- }
1479
- }
1480
-
1481
- // $$$ process /region
1482
- // $$$ process /highlight
1483
-
1484
- // $$$ process /theme
1485
- if (this.enableThemesPlugin && 'undefined' != typeof params.theme) {
1486
- this.updateTheme(params.theme);
1487
- }
1488
- };
1489
-
1490
- /**
1491
- * Returns true if we can switch to the requested mode
1492
- * @param {number} mode
1493
- * @return {boolean}
1494
- */
1495
- BookReader.prototype.canSwitchToMode = function (mode) {
1496
- if (mode == this.constMode2up || mode == this.constModeThumb) {
1497
- // check there are enough pages to display
1498
- // $$$ this is a workaround for the mis-feature that we can't display
1499
- // short books in 2up mode
1500
- if (this.book.getNumLeafs() < 2) {
1501
- return false;
1502
- }
1503
- }
1504
- return true;
1505
- };
1506
-
1507
- /**
1508
- * Returns the page URI or transparent image if out of range
1509
- * Also makes the reduce argument optional
1510
- * @param {number} index
1511
- * @param {number} [reduce]
1512
- * @param {number} [rotate]
1513
- * @return {string}
1514
- */
1515
- BookReader.prototype._getPageURI = function (index, reduce, rotate) {
1516
- var page = this.book.getPage(index, false);
1517
- // Synthesize page
1518
- if (!page) return this.imagesBaseURL + "transparent.png";
1519
- if ('undefined' == typeof reduce) {
1520
- // reduce not passed in
1521
- // $$$ this probably won't work for thumbnail mode
1522
- reduce = page.height / this.twoPage.height;
1523
- }
1524
- return page.getURI(reduce, rotate);
1525
- };
1526
-
1527
- /**
1528
- * @param {string} msg
1529
- * @param {function|undefined} onCloseCallback
1530
- */
1531
- BookReader.prototype.showProgressPopup = function (msg, onCloseCallback) {
1532
- if (this.popup) return;
1533
- this.popup = document.createElement("div");
1534
- $(this.popup).prop('className', 'BRprogresspopup');
1535
- if (typeof onCloseCallback === 'function') {
1536
- var closeButton = document.createElement('button');
1537
- closeButton.setAttribute('title', 'close');
1538
- closeButton.setAttribute('class', 'close-popup');
1539
- var icon = document.createElement('span');
1540
- icon.setAttribute('class', 'icon icon-close-dark');
1541
- $(closeButton).append(icon);
1542
- closeButton.addEventListener('click', () => {
1543
- onCloseCallback();
1544
- this.removeProgressPopup();
1545
- });
1546
- $(this.popup).append(closeButton);
1547
- }
1548
- var bar = document.createElement("div");
1549
- $(bar).css({
1550
- height: '20px'
1551
- }).prop('className', 'BRprogressbar');
1552
- $(this.popup).append(bar);
1553
- if (msg) {
1554
- var msgdiv = document.createElement("div");
1555
- msgdiv.innerHTML = msg;
1556
- $(this.popup).append(msgdiv);
1557
- }
1558
- $(this.popup).appendTo(this.refs.$br);
1559
- };
1560
- BookReader.prototype.removeProgressPopup = function () {
1561
- $(this.popup).remove();
1562
- this.$('.BRprogresspopup').remove();
1563
- this.popup = null;
1564
- };
1565
-
1566
- /**
1567
- * Can be overridden
1568
- */
1569
- BookReader.prototype.initUIStrings = function () {
1570
- // Navigation handlers will be bound after all UI is in place -- makes moving icons between
1571
- // the toolbar and nav bar easier
1572
-
1573
- // Setup tooltips -- later we could load these from a file for i18n
1574
- var titles = {
1575
- '.logo': 'Go to Archive.org',
1576
- // $$$ update after getting OL record
1577
- '.zoom_in': 'Zoom in',
1578
- '.zoom_out': 'Zoom out',
1579
- '.onepg': 'One-page view',
1580
- '.twopg': 'Two-page view',
1581
- '.thumb': 'Thumbnail view',
1582
- '.print': 'Print this page',
1583
- '.embed': 'Embed BookReader',
1584
- '.link': 'Link to this book (and page)',
1585
- '.bookmark': 'Bookmark this page',
1586
- '.share': 'Share this book',
1587
- '.info': 'About this book',
1588
- '.full': 'Toggle fullscreen',
1589
- '.book_left': 'Flip left',
1590
- '.book_right': 'Flip right',
1591
- '.play': 'Play',
1592
- '.pause': 'Pause',
1593
- '.BRdn': 'Show/hide nav bar',
1594
- // Would have to keep updating on state change to have just "Hide nav bar"
1595
- '.BRup': 'Show/hide nav bar',
1596
- '.book_top': 'First page',
1597
- '.book_bottom': 'Last page',
1598
- '.book_leftmost': 'First page',
1599
- '.book_rightmost': 'Last page'
1600
- };
1601
- if ('rl' == this.pageProgression) {
1602
- titles['.book_leftmost'] = 'Last page';
1603
- titles['.book_rightmost'] = 'First page';
1604
- }
1605
- for (var icon in titles) {
1606
- this.$(icon).prop('title', titles[icon]);
1607
- }
1608
- };
1609
-
1610
- /**
1611
- * Reloads images. Useful when some images might have failed.
1612
- */
1613
- BookReader.prototype.reloadImages = function () {
1614
- this.refs.$brContainer.find('img').each(function (index, elem) {
1615
- if (!elem.complete || elem.naturalHeight === 0) {
1616
- var src = elem.src;
1617
- elem.src = '';
1618
- setTimeout(function () {
1619
- elem.src = src;
1620
- }, 1000);
1621
- }
1622
- });
1623
- };
1624
-
1625
- /**
1626
- * @param {boolean} ignoreDisplay - bypass the display check
1627
- * @return {number}
1628
- */
1629
- BookReader.prototype.getFooterHeight = function () {
1630
- var $heightEl = this.mode == this.constMode2up ? this.refs.$BRfooter : this.refs.$BRnav;
1631
- if ($heightEl && this.refs.$BRfooter) {
1632
- var outerHeight = $heightEl.outerHeight();
1633
- var bottom = parseInt(this.refs.$BRfooter.css('bottom'));
1634
- if (!isNaN(outerHeight) && !isNaN(bottom)) {
1635
- return outerHeight + bottom;
1636
- }
1637
- }
1638
- return 0;
1639
- };
1640
-
1641
- // Basic Usage built-in Methods (can be overridden through options)
1642
- // This implementation uses options.data value for populating BookReader
1643
-
1644
- /**
1645
- * Create a params object from the current parameters.
1646
- * @return {Object}
1647
- */
1648
- BookReader.prototype.paramsFromCurrent = function () {
1649
- var params = {};
1650
-
1651
- // Path params
1652
- var index = this.currentIndex();
1653
- var pageNum = this.book.getPageNum(index);
1654
- if (pageNum === 0 || pageNum) {
1655
- params.page = pageNum;
1656
- }
1657
- params.index = index;
1658
- params.mode = this.mode;
1659
-
1660
- // Unused params
1661
- // $$$ highlight
1662
- // $$$ region
1663
-
1664
- // Querystring params
1665
- // View
1666
- var fullscreenView = 'theater';
1667
- if (this.isFullscreenActive) {
1668
- params.view = fullscreenView;
1669
- }
1670
- // Search
1671
- if (this.enableSearch) {
1672
- params.search = this.searchTerm;
1673
- }
1674
- return params;
1675
- };
1676
-
1677
- /**
1678
- * Return an object with configuration parameters from a fragment string.
1679
- *
1680
- * Fragments are formatted as a URL path but may be used outside of URLs as a
1681
- * serialization format for BookReader parameters
1682
- *
1683
- * @see http://openlibrary.org/dev/docs/bookurls for fragment syntax
1684
- *
1685
- * @param {string} fragment initial # is allowed for backwards compatibility
1686
- * but is deprecated
1687
- * @return {Object}
1688
- */
1689
- BookReader.prototype.paramsFromFragment = function (fragment) {
1690
- var params = {};
1691
-
1692
- // For backwards compatibility we allow an initial # character
1693
- // (as from window.location.hash) but don't require it
1694
- if (fragment.substr(0, 1) == '#') {
1695
- fragment = fragment.substr(1);
1696
- }
1697
-
1698
- // Simple #nn syntax
1699
- var oldStyleLeafNum = parseInt(/^\d+$/.exec(fragment));
1700
- if (!isNaN(oldStyleLeafNum)) {
1701
- params.index = oldStyleLeafNum;
1702
-
1703
- // Done processing if using old-style syntax
1704
- return params;
1705
- }
1706
-
1707
- // Split into key-value pairs
1708
- var urlArray = fragment.split('/');
1709
- var urlHash = {};
1710
- for (var i = 0; i < urlArray.length; i += 2) {
1711
- urlHash[urlArray[i]] = urlArray[i + 1];
1712
- }
1713
-
1714
- // Mode
1715
- if ('1up' == urlHash['mode']) {
1716
- params.mode = this.constMode1up;
1717
- } else if ('2up' == urlHash['mode']) {
1718
- params.mode = this.constMode2up;
1719
- } else if ('thumb' == urlHash['mode']) {
1720
- params.mode = this.constModeThumb;
1721
- }
1722
-
1723
- // Index and page
1724
- if ('undefined' != typeof urlHash['page']) {
1725
- // page was set -- may not be int
1726
- params.page = decodeURIComponent(urlHash['page']);
1727
- }
1728
-
1729
- // $$$ process /region
1730
- // $$$ process /search
1731
-
1732
- if (urlHash['search'] != undefined) {
1733
- params.search = utils.decodeURIComponentPlus(urlHash['search']);
1734
- }
1735
-
1736
- // $$$ process /highlight
1737
-
1738
- // $$$ process /theme
1739
- if (urlHash['theme'] != undefined) {
1740
- params.theme = urlHash['theme'];
1741
- }
1742
- return params;
1743
- };
1744
-
1745
- /**
1746
- * Create a fragment string from the params object.
1747
- *
1748
- * Fragments are formatted as a URL path but may be used outside of URLs as a
1749
- * serialization format for BookReader parameters
1750
- *
1751
- * @see https://openlibrary.org/dev/docs/bookurls for fragment syntax
1752
- *
1753
- * @param {Object} params
1754
- * @param {string} [urlMode]
1755
- * @return {string}
1756
- */
1757
- BookReader.prototype.fragmentFromParams = function (params) {
1758
- var urlMode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'hash';
1759
- var fragments = [];
1760
- if ('undefined' != typeof params.page) {
1761
- fragments.push('page', encodeURIComponent(params.page));
1762
- } else {
1763
- if ('undefined' != typeof params.index) {
1764
- // Don't have page numbering but we do have the index
1765
- fragments.push('page', 'n' + params.index);
1766
- }
1767
- }
1768
-
1769
- // $$$ highlight
1770
- // $$$ region
1771
-
1772
- // mode
1773
- if ('undefined' != typeof params.mode) {
1774
- if (params.mode == this.constMode1up) {
1775
- fragments.push('mode', '1up');
1776
- } else if (params.mode == this.constMode2up) {
1777
- fragments.push('mode', '2up');
1778
- } else if (params.mode == this.constModeThumb) {
1779
- fragments.push('mode', 'thumb');
1780
- } else {
1781
- throw 'fragmentFromParams called with unknown mode ' + params.mode;
1782
- }
1783
- }
1784
-
1785
- // search
1786
- if (params.search && urlMode === 'hash') {
1787
- fragments.push('search', utils.encodeURIComponentPlus(params.search));
1788
- }
1789
- return fragments.join('/');
1790
- };
1791
-
1792
- /**
1793
- * Create, update querystring from the params object
1794
- *
1795
- * Handles:
1796
- * view=
1797
- * q=
1798
- * @param {Object} params
1799
- * @param {string} currQueryString
1800
- * @param {string} [urlMode]
1801
- * @return {string}
1802
- */
1803
- BookReader.prototype.queryStringFromParams = function (params, currQueryString) {
1804
- var urlMode = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'hash';
1805
- var newParams = new URLSearchParams(currQueryString);
1806
- if (params.view) {
1807
- // Set ?view=theater when fullscreen
1808
- newParams.set('view', params.view);
1809
- } else {
1810
- // Remove
1811
- newParams.delete('view');
1812
- }
1813
- if (params.search && urlMode === 'history') {
1814
- newParams.set('q', params.search);
1815
- }
1816
- // https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/toString
1817
- // Note: This method returns the query string without the question mark.
1818
- var result = newParams.toString();
1819
- return result ? '?' + result : '';
1820
- };
1821
-
1822
- /**
1823
- * Helper to select within instance's elements
1824
- */
1825
- BookReader.prototype.$ = function (selector) {
1826
- return this.refs.$br.find(selector);
1827
- };
1828
- window.BookReader = BookReader;