@internetarchive/bookreader 5.0.0-8 → 5.0.0-80

Sign up to get free protection for your applications and to get access to all the features.
Files changed (313) hide show
  1. package/.eslintrc.js +17 -15
  2. package/.github/workflows/node.js.yml +73 -10
  3. package/.github/workflows/npm-publish.yml +6 -20
  4. package/.testcaferc.js +10 -0
  5. package/BookReader/BookReader.css +398 -1133
  6. package/BookReader/BookReader.js +1 -1
  7. package/BookReader/BookReader.js.LICENSE.txt +20 -20
  8. package/BookReader/BookReader.js.map +1 -1
  9. package/BookReader/ia-bookreader-bundle.js +1782 -0
  10. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +7 -0
  11. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  12. package/BookReader/icons/1up.svg +1 -1
  13. package/BookReader/icons/2up.svg +1 -1
  14. package/BookReader/icons/advance.svg +1 -1
  15. package/BookReader/icons/chevron-right.svg +1 -1
  16. package/BookReader/icons/close-circle-dark.svg +1 -1
  17. package/BookReader/icons/close-circle.svg +1 -1
  18. package/BookReader/icons/fullscreen.svg +1 -1
  19. package/BookReader/icons/fullscreen_exit.svg +1 -1
  20. package/BookReader/icons/hamburger.svg +1 -1
  21. package/BookReader/icons/left-arrow.svg +1 -1
  22. package/BookReader/icons/magnify-minus.svg +1 -1
  23. package/BookReader/icons/magnify-plus.svg +1 -1
  24. package/BookReader/icons/magnify.svg +1 -1
  25. package/BookReader/icons/pause.svg +1 -1
  26. package/BookReader/icons/play.svg +1 -1
  27. package/BookReader/icons/playback-speed.svg +1 -1
  28. package/BookReader/icons/read-aloud.svg +1 -1
  29. package/BookReader/icons/review.svg +1 -1
  30. package/BookReader/icons/thumbnails.svg +1 -1
  31. package/BookReader/icons/voice.svg +1 -0
  32. package/BookReader/icons/volume-full.svg +1 -1
  33. package/BookReader/images/BRicons.svg +3 -3
  34. package/BookReader/images/books_graphic.svg +1 -1
  35. package/BookReader/images/icon_book.svg +1 -1
  36. package/BookReader/images/icon_bookmark.svg +1 -1
  37. package/BookReader/images/icon_gear.svg +1 -1
  38. package/BookReader/images/icon_hamburger.svg +1 -1
  39. package/BookReader/images/icon_home.svg +1 -1
  40. package/BookReader/images/icon_info.svg +1 -1
  41. package/BookReader/images/icon_one_page.svg +1 -1
  42. package/BookReader/images/icon_pause.svg +1 -1
  43. package/BookReader/images/icon_play.svg +1 -1
  44. package/BookReader/images/icon_playback-rate.svg +1 -1
  45. package/BookReader/images/icon_search_button.svg +1 -1
  46. package/BookReader/images/icon_share.svg +1 -1
  47. package/BookReader/images/icon_skip-ahead.svg +1 -1
  48. package/BookReader/images/icon_skip-back.svg +1 -1
  49. package/BookReader/images/icon_speaker.svg +1 -1
  50. package/BookReader/images/icon_speaker_open.svg +1 -1
  51. package/BookReader/images/icon_thumbnails.svg +1 -1
  52. package/BookReader/images/icon_toc.svg +1 -1
  53. package/BookReader/images/icon_two_pages.svg +1 -1
  54. package/BookReader/images/marker_chap-off.svg +1 -1
  55. package/BookReader/images/marker_chap-on.svg +1 -1
  56. package/BookReader/images/marker_srch-on.svg +1 -1
  57. package/BookReader/jquery-3.js +2 -0
  58. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  59. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  60. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  61. package/BookReader/plugins/plugin.autoplay.js +1 -1
  62. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  63. package/BookReader/plugins/plugin.chapters.js +25 -1
  64. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
  65. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  66. package/BookReader/plugins/plugin.iframe.js +1 -1
  67. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  68. package/BookReader/plugins/plugin.iiif.js +2 -0
  69. package/BookReader/plugins/plugin.iiif.js.map +1 -0
  70. package/BookReader/plugins/plugin.resume.js +1 -1
  71. package/BookReader/plugins/plugin.resume.js.map +1 -1
  72. package/BookReader/plugins/plugin.search.js +2 -1
  73. package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
  74. package/BookReader/plugins/plugin.search.js.map +1 -1
  75. package/BookReader/plugins/plugin.text_selection.js +2 -1
  76. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
  77. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  78. package/BookReader/plugins/plugin.tts.js +1 -1
  79. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
  80. package/BookReader/plugins/plugin.tts.js.map +1 -1
  81. package/BookReader/plugins/plugin.url.js +1 -1
  82. package/BookReader/plugins/plugin.url.js.map +1 -1
  83. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
  84. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  85. package/BookReader/webcomponents-bundle.js +3 -0
  86. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  87. package/BookReader/webcomponents-bundle.js.map +1 -0
  88. package/BookReaderDemo/BookReaderDemo.css +18 -19
  89. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -3
  90. package/BookReaderDemo/BookReaderJSAutoplay.js +4 -1
  91. package/BookReaderDemo/BookReaderJSSimple.js +1 -0
  92. package/BookReaderDemo/IADemoBr.js +147 -0
  93. package/BookReaderDemo/demo-advanced.html +2 -2
  94. package/BookReaderDemo/demo-autoplay.html +2 -3
  95. package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
  96. package/BookReaderDemo/demo-fullscreen-mobile.html +3 -5
  97. package/BookReaderDemo/demo-fullscreen.html +2 -4
  98. package/BookReaderDemo/demo-iiif.html +99 -12
  99. package/BookReaderDemo/demo-internetarchive.html +214 -18
  100. package/BookReaderDemo/demo-multiple.html +2 -1
  101. package/BookReaderDemo/demo-preview-pages.html +2 -1
  102. package/BookReaderDemo/demo-simple.html +2 -1
  103. package/BookReaderDemo/demo-vendor-fullscreen.html +2 -4
  104. package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
  105. package/BookReaderDemo/immersion-1up.html +2 -2
  106. package/BookReaderDemo/immersion-mode.html +2 -4
  107. package/BookReaderDemo/toggle_controls.html +3 -2
  108. package/BookReaderDemo/view_mode.html +2 -1
  109. package/BookReaderDemo/viewmode-cycle.html +2 -3
  110. package/CHANGELOG.md +536 -33
  111. package/README.md +14 -1
  112. package/babel.config.js +20 -0
  113. package/codecov.yml +6 -0
  114. package/index.html +4 -1
  115. package/jsconfig.json +19 -0
  116. package/netlify.toml +9 -0
  117. package/package.json +70 -60
  118. package/renovate.json +52 -0
  119. package/scripts/preversion.js +0 -1
  120. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  121. package/src/BookNavigator/assets/button-base.js +4 -2
  122. package/src/BookNavigator/assets/ia-logo.js +17 -0
  123. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  124. package/src/BookNavigator/assets/icon_close.js +1 -1
  125. package/src/BookNavigator/book-navigator.js +590 -0
  126. package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
  127. package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
  128. package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
  129. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
  130. package/src/BookNavigator/bookmarks/bookmarks-provider.js +27 -17
  131. package/src/BookNavigator/bookmarks/ia-bookmarks.js +116 -67
  132. package/src/BookNavigator/delete-modal-actions.js +1 -1
  133. package/src/BookNavigator/downloads/downloads-provider.js +36 -21
  134. package/src/BookNavigator/downloads/downloads.js +41 -25
  135. package/src/BookNavigator/search/search-provider.js +49 -27
  136. package/src/BookNavigator/search/search-results.js +23 -9
  137. package/src/BookNavigator/sharing.js +27 -0
  138. package/src/BookNavigator/viewable-files.js +95 -0
  139. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -10
  140. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +3 -3
  141. package/src/BookReader/BookModel.js +64 -34
  142. package/src/BookReader/DragScrollable.js +233 -0
  143. package/src/BookReader/Mode1Up.js +56 -351
  144. package/src/BookReader/Mode1UpLit.js +388 -0
  145. package/src/BookReader/Mode2Up.js +73 -1318
  146. package/src/BookReader/Mode2UpLit.js +776 -0
  147. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  148. package/src/BookReader/ModeSmoothZoom.js +312 -0
  149. package/src/BookReader/ModeThumb.js +18 -12
  150. package/src/BookReader/Navbar/Navbar.js +14 -40
  151. package/src/BookReader/PageContainer.js +81 -6
  152. package/src/BookReader/ReduceSet.js +1 -1
  153. package/src/BookReader/Toolbar/Toolbar.js +10 -37
  154. package/src/BookReader/events.js +2 -3
  155. package/src/BookReader/options.js +27 -2
  156. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  157. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  158. package/src/BookReader/utils/SelectionObserver.js +45 -0
  159. package/src/BookReader/utils.js +118 -13
  160. package/src/BookReader.js +427 -1061
  161. package/src/assets/icons/magnify-minus.svg +3 -7
  162. package/src/assets/icons/magnify-plus.svg +3 -7
  163. package/src/assets/icons/voice.svg +1 -0
  164. package/src/css/BookReader.scss +1 -5
  165. package/src/css/_BRBookmarks.scss +1 -1
  166. package/src/css/_BRComponent.scss +1 -1
  167. package/src/css/_BRmain.scss +16 -3
  168. package/src/css/_BRnav.scss +12 -39
  169. package/src/css/_BRpages.scss +149 -40
  170. package/src/css/_BRsearch.scss +68 -25
  171. package/src/css/_BRtoolbar.scss +5 -5
  172. package/src/css/_TextSelection.scss +87 -27
  173. package/src/css/_colorbox.scss +2 -2
  174. package/src/css/_controls.scss +20 -7
  175. package/src/css/_icons.scss +1 -1
  176. package/src/ia-bookreader/ia-bookreader.js +224 -0
  177. package/src/plugins/plugin.archive_analytics.js +3 -3
  178. package/src/plugins/plugin.autoplay.js +5 -11
  179. package/src/plugins/plugin.chapters.js +237 -191
  180. package/src/plugins/plugin.iiif.js +151 -0
  181. package/src/plugins/plugin.resume.js +3 -3
  182. package/src/plugins/plugin.text_selection.js +464 -134
  183. package/src/plugins/plugin.vendor-fullscreen.js +4 -4
  184. package/src/plugins/search/plugin.search.js +142 -125
  185. package/src/plugins/search/utils.js +43 -0
  186. package/src/plugins/search/view.js +33 -58
  187. package/src/plugins/tts/AbstractTTSEngine.js +71 -40
  188. package/src/plugins/tts/FestivalTTSEngine.js +13 -14
  189. package/src/plugins/tts/PageChunk.js +15 -21
  190. package/src/plugins/tts/PageChunkIterator.js +8 -12
  191. package/src/plugins/tts/WebTTSEngine.js +87 -71
  192. package/src/plugins/tts/plugin.tts.js +96 -127
  193. package/src/plugins/tts/utils.js +15 -25
  194. package/src/plugins/url/UrlPlugin.js +191 -0
  195. package/src/plugins/{plugin.url.js → url/plugin.url.js} +45 -16
  196. package/src/util/browserSniffing.js +22 -0
  197. package/src/util/docCookies.js +21 -2
  198. package/tests/e2e/README.md +37 -0
  199. package/tests/e2e/autoplay.test.js +2 -2
  200. package/tests/e2e/base.test.js +8 -16
  201. package/tests/e2e/helpers/base.js +53 -48
  202. package/tests/e2e/helpers/debug.js +1 -1
  203. package/tests/e2e/helpers/params.js +17 -0
  204. package/tests/e2e/helpers/rightToLeft.js +8 -14
  205. package/tests/e2e/helpers/search.js +73 -0
  206. package/tests/e2e/models/Navigation.js +20 -37
  207. package/tests/e2e/rightToLeft.test.js +4 -5
  208. package/tests/e2e/viewmode.test.js +40 -33
  209. package/tests/jest/BookNavigator/book-navigator.test.js +661 -0
  210. package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
  211. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
  212. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
  213. package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
  214. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
  215. package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
  216. package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
  217. package/tests/{karma → jest}/BookNavigator/search/search-results.test.js +109 -60
  218. package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
  219. package/tests/jest/BookNavigator/viewable-files/viewable-files-provider.test.js +80 -0
  220. package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
  221. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +74 -14
  222. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +193 -0
  223. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  224. package/tests/jest/BookReader/Mode1UpLit.test.js +73 -0
  225. package/tests/jest/BookReader/Mode2Up.test.js +98 -0
  226. package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
  227. package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
  228. package/tests/jest/BookReader/ModeSmoothZoom.test.js +218 -0
  229. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  230. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +10 -10
  231. package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +88 -6
  232. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  233. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
  234. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  235. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  236. package/tests/jest/BookReader/utils/SelectionObserver.test.js +57 -0
  237. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  238. package/tests/jest/BookReader/utils.test.js +229 -0
  239. package/tests/jest/BookReader.keyboard.test.js +190 -0
  240. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
  241. package/tests/{BookReader.test.js → jest/BookReader.test.js} +26 -37
  242. package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
  243. package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +4 -4
  244. package/tests/jest/plugins/plugin.chapters.test.js +195 -0
  245. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
  246. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
  247. package/tests/jest/plugins/plugin.text_selection.test.js +317 -0
  248. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  249. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +25 -47
  250. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +39 -6
  251. package/tests/jest/plugins/search/utils.js +25 -0
  252. package/tests/jest/plugins/search/utils.test.js +29 -0
  253. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +29 -9
  254. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  255. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  256. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  257. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +47 -1
  258. package/tests/{plugins → jest/plugins}/tts/utils.test.js +1 -60
  259. package/tests/jest/plugins/url/UrlPlugin.test.js +198 -0
  260. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +53 -14
  261. package/tests/jest/setup.js +3 -0
  262. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  263. package/tests/jest/util/docCookies.test.js +24 -0
  264. package/tests/{util → jest/util}/strings.test.js +1 -1
  265. package/tests/{utils.js → jest/utils.js} +38 -0
  266. package/webpack.config.js +12 -6
  267. package/.babelrc +0 -12
  268. package/.dependabot/config.yml +0 -6
  269. package/.testcaferc.json +0 -5
  270. package/BookReader/bookreader-component-bundle.js +0 -1450
  271. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  272. package/BookReader/bookreader-component-bundle.js.map +0 -1
  273. package/BookReader/jquery-1.10.1.js +0 -2
  274. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  275. package/BookReader/plugins/plugin.menu_toggle.js +0 -2
  276. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  277. package/BookReader/plugins/plugin.mobile_nav.js +0 -2
  278. package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
  279. package/BookReaderDemo/IIIFBookReader.js +0 -207
  280. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  281. package/BookReaderDemo/demo-iiif.js +0 -26
  282. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  283. package/karma.conf.js +0 -23
  284. package/src/BookNavigator/BookModel.js +0 -14
  285. package/src/BookNavigator/BookNavigator.js +0 -446
  286. package/src/BookNavigator/assets/book-loader.js +0 -27
  287. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  288. package/src/BookNavigator/search/a-search-result.js +0 -55
  289. package/src/BookReader/DebugConsole.js +0 -54
  290. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  291. package/src/ItemNavigator/ItemNavigator.js +0 -376
  292. package/src/ItemNavigator/providers/sharing.js +0 -29
  293. package/src/css/_MobileNav.scss +0 -194
  294. package/src/dragscrollable-br.js +0 -261
  295. package/src/lit-wrapper.js +0 -2
  296. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  297. package/src/plugins/plugin.mobile_nav.js +0 -287
  298. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  299. package/tests/BookReader/DebugConsole.test.js +0 -25
  300. package/tests/BookReader/Mode1Up.test.js +0 -164
  301. package/tests/BookReader/Mode2Up.test.js +0 -247
  302. package/tests/BookReader/utils.test.js +0 -109
  303. package/tests/e2e/helpers/desktopSearch.js +0 -72
  304. package/tests/e2e/helpers/mobileSearch.js +0 -85
  305. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  306. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  307. package/tests/karma/BookNavigator/search/search-provider.test.js +0 -23
  308. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  309. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  310. package/tests/plugins/plugin.chapters.test.js +0 -130
  311. package/tests/plugins/plugin.mobile_nav.test.js +0 -66
  312. package/tests/plugins/plugin.text_selection.test.js +0 -203
  313. package/tests/util/docCookies.test.js +0 -15
@@ -0,0 +1,590 @@
1
+ // eslint-disable-next-line no-unused-vars
2
+ import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
3
+ // eslint-disable-next-line no-unused-vars
4
+ import { ModalManager } from '@internetarchive/modal-manager';
5
+ import { css, html, LitElement, nothing } from 'lit';
6
+ import SearchProvider from './search/search-provider.js';
7
+ import DownloadProvider from './downloads/downloads-provider.js';
8
+ import VisualAdjustmentProvider from './visual-adjustments/visual-adjustments-provider.js';
9
+ import BookmarksProvider from './bookmarks/bookmarks-provider.js';
10
+ import SharingProvider from './sharing.js';
11
+ import ViewableFilesProvider from './viewable-files.js';
12
+ import iaLogo from './assets/ia-logo.js';
13
+
14
+ const events = {
15
+ menuUpdated: 'menuUpdated',
16
+ updateSideMenu: 'updateSideMenu',
17
+ PostInit: 'PostInit',
18
+ ViewportInFullScreen: 'ViewportInFullScreen',
19
+ };
20
+ export class BookNavigator extends LitElement {
21
+ static get properties() {
22
+ return {
23
+ itemMD: { type: Object },
24
+ bookReaderLoaded: { type: Boolean },
25
+ bookreader: { type: Object },
26
+ bookIsRestricted: { type: Boolean },
27
+ downloadableTypes: { type: Array },
28
+ isAdmin: { type: Boolean },
29
+ lendingInitialized: { type: Boolean },
30
+ lendingStatus: { type: Object },
31
+ menuProviders: { type: Object },
32
+ menuShortcuts: { type: Array },
33
+ signedIn: { type: Boolean },
34
+ loaded: { type: Boolean },
35
+ sharedObserver: { type: Object, attribute: false },
36
+ modal: { type: Object, attribute: false },
37
+ fullscreenBranding: { type: Object },
38
+ };
39
+ }
40
+
41
+ constructor() {
42
+ super();
43
+ this.itemMD = undefined;
44
+ this.loaded = false;
45
+ this.bookReaderCannotLoad = false;
46
+ this.bookReaderLoaded = false;
47
+ this.bookreader = null;
48
+ this.bookIsRestricted = false;
49
+ this.downloadableTypes = [];
50
+ this.isAdmin = false;
51
+ this.lendingInitialized = false;
52
+ this.lendingStatus = {};
53
+ this.menuProviders = {};
54
+ this.menuShortcuts = [];
55
+ this.signedIn = false;
56
+ /** @type {ModalManager} */
57
+ this.modal = undefined;
58
+ /** @type {SharedResizeObserver} */
59
+ this.sharedObserver = undefined;
60
+ this.fullscreenBranding = iaLogo;
61
+ // Untracked properties
62
+ this.sharedObserverHandler = undefined;
63
+ this.brWidth = 0;
64
+ this.brHeight = 0;
65
+ this.shortcutOrder = [
66
+ /**
67
+ * sets exit FS button (`this.fullscreenBranding1)
68
+ * when `br.options.enableFSLogoShortcut`
69
+ */
70
+ 'fullscreen',
71
+ 'volumes',
72
+ 'chapters',
73
+ 'search',
74
+ 'bookmarks'
75
+ ];
76
+ }
77
+
78
+ disconnectedCallback() {
79
+ this.sharedObserver.removeObserver({
80
+ target: this.mainBRContainer,
81
+ handler: this.sharedObserverHandler
82
+ });
83
+ }
84
+
85
+ firstUpdated() {
86
+ this.bindEventListeners();
87
+ this.emitPostInit();
88
+ this.loaded = true;
89
+ }
90
+
91
+ updated(changed) {
92
+ if (!this.bookreader || !this.itemMD || !this.bookReaderLoaded) {
93
+ return;
94
+ }
95
+
96
+ const reload = changed.has('loaded') && this.loaded;
97
+ if (reload
98
+ || changed.has('itemMD')
99
+ || changed.has('bookreader')
100
+ || changed.has('signedIn')
101
+ || changed.has('isAdmin')
102
+ || changed.has('modal')) {
103
+ this.initializeBookSubmenus();
104
+ }
105
+
106
+ if (changed.has('sharedObserver') && this.bookreader) {
107
+ this.loadSharedObserver();
108
+ this.initializeBookSubmenus();
109
+ }
110
+
111
+ if (changed.has('downloadableTypes')) {
112
+ this.initializeBookSubmenus();
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Global event emitter for when Book Navigator loads
118
+ */
119
+ emitPostInit() {
120
+ // emit global event when book nav has loaded with current bookreader selector
121
+ this.dispatchEvent(new CustomEvent(`BrBookNav:${events.PostInit}`, {
122
+ detail: { brSelector: this.bookreader?.el },
123
+ bubbles: true,
124
+ composed: true,
125
+ }));
126
+ }
127
+
128
+ /**
129
+ * @typedef {{
130
+ * baseHost: string,
131
+ * modal: ModalManager,
132
+ * sharedObserver: SharedResizeObserver,
133
+ * bookreader: BookReader,
134
+ * item: Item,
135
+ * signedIn: boolean,
136
+ * isAdmin: boolean,
137
+ * onProviderChange: (BookReader, object) => void,
138
+ * }} baseProviderConfig
139
+ *
140
+ * @return {baseProviderConfig}
141
+ */
142
+ get baseProviderConfig() {
143
+ return {
144
+ baseHost: this.baseHost,
145
+ modal: this.modal,
146
+ sharedObserver: this.sharedObserver,
147
+ bookreader: this.bookreader,
148
+ item: this.itemMD,
149
+ signedIn: this.signedIn,
150
+ isAdmin: this.isAdmin,
151
+ onProviderChange: () => {}
152
+ };
153
+ }
154
+
155
+ get isWideEnoughToOpenMenu() {
156
+ return this.brWidth >= 640;
157
+ }
158
+ /**
159
+ * Instantiates books submenus & their update callbacks
160
+ *
161
+ * NOTE: we are doing our best to scope bookreader's instance.
162
+ * If your submenu provider uses a bookreader instance to read, manually
163
+ * manipulate BookReader, please update the navigator's instance of it
164
+ * to keep it in sync.
165
+ */
166
+ initializeBookSubmenus() {
167
+ const providers = {
168
+ visualAdjustments: new VisualAdjustmentProvider({
169
+ ...this.baseProviderConfig,
170
+ /** Update menu contents */
171
+ onProviderChange: () => {
172
+ this.updateMenuContents();
173
+ },
174
+ }),
175
+ };
176
+
177
+ if (this.baseProviderConfig.item) {
178
+ // Share options currently rely on IA item metadata
179
+ providers.share = new SharingProvider(this.baseProviderConfig);
180
+ }
181
+
182
+ if (this.shouldShowDownloadsMenu()) {
183
+ providers.downloads = new DownloadProvider(this.baseProviderConfig);
184
+ }
185
+
186
+ if (this.bookreader.options.enableSearch) {
187
+ providers.search = new SearchProvider({
188
+ ...this.baseProviderConfig,
189
+ /**
190
+ * Search specific menu updates
191
+ * @param {BookReader} brInstance
192
+ * @param {{ searchCanceled: boolean }} searchUpdates
193
+ */
194
+ onProviderChange: (brInstance = null, searchUpdates = {}) => {
195
+ if (brInstance) {
196
+ /* refresh br instance reference */
197
+ this.bookreader = brInstance;
198
+ }
199
+
200
+ this.updateMenuContents();
201
+
202
+ if (searchUpdates.openMenu === false) {
203
+ return;
204
+ }
205
+
206
+ if (this.isWideEnoughToOpenMenu && !searchUpdates?.searchCanceled) {
207
+ /* open side search menu */
208
+ setTimeout(() => {
209
+ this.updateSideMenu('search', 'open');
210
+ }, 0);
211
+ }
212
+ },
213
+ });
214
+ }
215
+
216
+ if (this.bookreader.options.enableBookmarks) {
217
+ providers.bookmarks = new BookmarksProvider({
218
+ ...this.baseProviderConfig,
219
+ onProviderChange: (bookmarks) => {
220
+ const method = Object.keys(bookmarks).length ? 'add' : 'remove';
221
+ this[`${method}MenuShortcut`]('bookmarks');
222
+ this.updateMenuContents();
223
+ }
224
+ });
225
+ }
226
+
227
+ // add shortcut for volumes if multipleBooksList exists
228
+ if (this.bookreader.options.enableMultipleBooks) {
229
+ providers.volumes = new ViewableFilesProvider({
230
+ ...this.baseProviderConfig,
231
+ onProviderChange: (brInstance = null, volumesUpdates = {}) => {
232
+ if (brInstance) {
233
+ /* refresh br instance reference */
234
+ this.bookreader = brInstance;
235
+ }
236
+ this.updateMenuContents();
237
+ if (this.isWideEnoughToOpenMenu) {
238
+ /* open side search menu */
239
+ setTimeout(() => {
240
+ this.updateSideMenu('volumes', 'open');
241
+ });
242
+ }
243
+ }
244
+ });
245
+ }
246
+
247
+ Object.assign(this.menuProviders, providers);
248
+ this.addMenuShortcut('search');
249
+ this.addMenuShortcut('volumes');
250
+ this.updateMenuContents();
251
+ }
252
+
253
+ /** gets element that houses the bookreader in light dom */
254
+ get mainBRContainer() {
255
+ return document.querySelector(this.bookreader?.el);
256
+ }
257
+
258
+ /** Fullscreen Shortcut */
259
+ addFullscreenShortcut() {
260
+ const closeFS = {
261
+ icon: this.fullscreenShortcut,
262
+ id: 'fullscreen',
263
+ };
264
+ this.menuShortcuts.push(closeFS);
265
+ this.sortMenuShortcuts();
266
+ this.emitMenuShortcutsUpdated();
267
+ }
268
+
269
+ deleteFullscreenShortcut() {
270
+ const updatedShortcuts = this.menuShortcuts.filter(({ id }) => {
271
+ return id !== 'fullscreen';
272
+ });
273
+ this.menuShortcuts = updatedShortcuts;
274
+ this.sortMenuShortcuts();
275
+ this.emitMenuShortcutsUpdated();
276
+ }
277
+
278
+ closeFullscreen() {
279
+ this.bookreader.exitFullScreen();
280
+ }
281
+
282
+ get fullscreenShortcut() {
283
+ return html`
284
+ <button
285
+ @click=${() => this.closeFullscreen()}
286
+ title="Exit fullscreen view"
287
+ >${this.fullscreenBranding}</button>
288
+ `;
289
+ }
290
+ /** End Fullscreen Shortcut */
291
+
292
+ /**
293
+ * Open side menu
294
+ * @param {string} menuId
295
+ * @param {('open'|'close'|'toggle')} action
296
+ */
297
+ updateSideMenu(menuId = '', action = 'open') {
298
+ if (!menuId) {
299
+ return;
300
+ }
301
+ const event = new CustomEvent(
302
+ events.updateSideMenu, {
303
+ detail: { menuId, action },
304
+ },
305
+ );
306
+ this.dispatchEvent(event);
307
+ }
308
+
309
+ /**
310
+ * Sets order of menu and emits custom event when done
311
+ */
312
+ updateMenuContents() {
313
+ const {
314
+ search, downloads, visualAdjustments, share, bookmarks, volumes, chapters
315
+ } = this.menuProviders;
316
+ const availableMenus = [volumes, chapters, search, bookmarks, visualAdjustments, share].filter((menu) => !!menu);
317
+
318
+ if (this.shouldShowDownloadsMenu()) {
319
+ downloads?.update(this.downloadableTypes);
320
+ availableMenus.splice(-2, 0, downloads);
321
+ }
322
+
323
+ const event = new CustomEvent(
324
+ events.menuUpdated, {
325
+ detail: availableMenus,
326
+ },
327
+ );
328
+ this.dispatchEvent(event);
329
+ }
330
+
331
+ /**
332
+ * Confirms if we should show the downloads menu
333
+ * @returns {bool}
334
+ */
335
+ shouldShowDownloadsMenu() {
336
+ if (!this.downloadableTypes.length) { return false; }
337
+ if (this.bookIsRestricted === false) { return true; }
338
+ if (this.isAdmin) { return true; }
339
+ const { user_loan_record = {} } = this.lendingStatus;
340
+ const hasNoLoanRecord = Array.isArray(user_loan_record); /* (bc PHP assoc. arrays) */
341
+
342
+ if (hasNoLoanRecord) { return false; }
343
+
344
+ const hasValidLoan = user_loan_record.type && (user_loan_record.type !== 'SESSION_LOAN');
345
+ return hasValidLoan;
346
+ }
347
+
348
+ /**
349
+ * Adds a provider object to the menuShortcuts array property if it isn't
350
+ * already added. menuShortcuts are then sorted by shortcutOrder and
351
+ * a menuShortcutsUpdated event is emitted.
352
+ *
353
+ * @param {string} menuId - a string matching the id property of a provider
354
+ */
355
+ addMenuShortcut(menuId) {
356
+ if (this.menuShortcuts.find((m) => m.id === menuId)) {
357
+ // menu is already there
358
+ return;
359
+ }
360
+
361
+ if (!this.menuProviders[menuId]) {
362
+ // no provider for this menu
363
+ return;
364
+ }
365
+
366
+ this.menuShortcuts.push(this.menuProviders[menuId]);
367
+ this.sortMenuShortcuts();
368
+ this.emitMenuShortcutsUpdated();
369
+ }
370
+
371
+ /**
372
+ * Removes a provider object from the menuShortcuts array and emits a
373
+ * menuShortcutsUpdated event.
374
+ *
375
+ * @param {string} menuId - a string matching the id property of a provider
376
+ */
377
+ removeMenuShortcut(menuId) {
378
+ this.menuShortcuts = this.menuShortcuts.filter((m) => m.id !== menuId);
379
+ this.emitMenuShortcutsUpdated();
380
+ }
381
+
382
+ /**
383
+ * Sorts the menuShortcuts property by comparing each provider's id to
384
+ * the id in each iteration over the shortcutOrder array.
385
+ */
386
+ sortMenuShortcuts() {
387
+ this.menuShortcuts = this.shortcutOrder.reduce((shortcuts, id) => {
388
+ const menu = this.menuShortcuts.find((m) => m.id === id);
389
+ if (menu) { shortcuts.push(menu); }
390
+ return shortcuts;
391
+ }, []);
392
+ }
393
+
394
+ emitMenuShortcutsUpdated() {
395
+ const event = new CustomEvent('menuShortcutsUpdated', {
396
+ detail: this.menuShortcuts,
397
+ });
398
+ this.dispatchEvent(event);
399
+ }
400
+
401
+ emitLoadingStatusUpdate(loaded) {
402
+ const event = new CustomEvent('loadingStateUpdated', {
403
+ detail: { loaded },
404
+ });
405
+ this.dispatchEvent(event);
406
+ }
407
+
408
+ /**
409
+ * Core bookreader event handler registry
410
+ *
411
+ * NOTE: we are trying to keep bookreader's instance in scope
412
+ * Please update Book Navigator's instance reference of it to keep it current
413
+ */
414
+ bindEventListeners() {
415
+ window.addEventListener('BookReader:PostInit', (e) => {
416
+ this.bookreader = e.detail.props;
417
+ this.bookreader.shell = this;
418
+ this.bookReaderLoaded = true;
419
+ this.bookReaderCannotLoad = false;
420
+ this.emitLoadingStatusUpdate(true);
421
+ this.loadSharedObserver();
422
+ setTimeout(() => {
423
+ this.bookreader.resize();
424
+ }, 0);
425
+ });
426
+ window.addEventListener('BookReader:fullscreenToggled', (event) => {
427
+ const { detail: { props: brInstance = null } } = event;
428
+ if (brInstance) {
429
+ this.bookreader = brInstance;
430
+ }
431
+ this.manageFullScreenBehavior();
432
+ }, { passive: true });
433
+ window.addEventListener('BookReader:ToggleSearchMenu', (event) => {
434
+ this.dispatchEvent(new CustomEvent(events.updateSideMenu, {
435
+ detail: { menuId: 'search', action: 'toggle' },
436
+ }));
437
+ });
438
+ window.addEventListener('LendingFlow:PostInit', ({ detail }) => {
439
+ const {
440
+ downloadTypesAvailable, lendingStatus, isAdmin, previewType,
441
+ } = detail;
442
+ this.lendingInitialized = true;
443
+ this.downloadableTypes = downloadTypesAvailable;
444
+ this.lendingStatus = lendingStatus;
445
+ this.isAdmin = isAdmin;
446
+ this.bookReaderCannotLoad = previewType === 'singlePagePreview';
447
+ this.emitLoadingStatusUpdate(true);
448
+ });
449
+ window.addEventListener('BRJSIA:PostInit', ({ detail }) => {
450
+ const { isRestricted, downloadURLs } = detail;
451
+ this.bookReaderLoaded = true;
452
+ this.downloadableTypes = downloadURLs;
453
+ this.bookIsRestricted = isRestricted;
454
+ });
455
+ window.addEventListener('contextmenu', (e) => this.manageContextMenuVisibility(e), { capture: true });
456
+ }
457
+
458
+ /** Display an element's context menu */
459
+ manageContextMenuVisibility(e) {
460
+ window.archive_analytics?.send_event(
461
+ 'BookReader',
462
+ `contextmenu-${this.bookIsRestricted ? 'restricted' : 'unrestricted'}`,
463
+ e.target?.classList?.value
464
+ );
465
+ if (!this.bookIsRestricted) {
466
+ return;
467
+ }
468
+
469
+ const imagePane = e.target.classList.value.match(/BRscreen|BRpageimage/g);
470
+ if (!imagePane) {
471
+ return;
472
+ }
473
+
474
+ e.preventDefault();
475
+ return false;
476
+ }
477
+
478
+ loadSharedObserver() {
479
+ this.sharedObserverHandler = { handleResize: this.handleResize.bind(this) };
480
+ this.sharedObserver?.addObserver({
481
+ target: this.mainBRContainer,
482
+ handler: this.sharedObserverHandler
483
+ });
484
+ }
485
+
486
+ /**
487
+ * Uses resize observer to fire BookReader's `resize` functionality
488
+ * We do not want to trigger resize IF:
489
+ * - book animation is happening
490
+ * - book is in fullscreen (fullscreen is handled separately)
491
+ *
492
+ * @param { target: HTMLElement, contentRect: DOMRectReadOnly } entry
493
+ */
494
+ handleResize({ contentRect, target }) {
495
+ const startBrWidth = this.brWidth;
496
+ const startBrHeight = this.brHeight;
497
+ const { animating } = this.bookreader;
498
+
499
+ if (target === this.mainBRContainer) {
500
+ this.brWidth = contentRect.width;
501
+ this.brHeight = contentRect.height;
502
+ }
503
+
504
+ if (!startBrWidth && this.brWidth) {
505
+ // loading up, let's update side menus
506
+ this.initializeBookSubmenus();
507
+ }
508
+
509
+ const widthChange = startBrWidth !== this.brWidth;
510
+ const heightChange = startBrHeight !== this.brHeight;
511
+
512
+ if (!animating && (widthChange || heightChange)) {
513
+ this.bookreader?.resize();
514
+ }
515
+ }
516
+
517
+ /**
518
+ * Manages Fullscreen behavior
519
+ * This makes sure that controls are _always_ in view
520
+ * We need this to accommodate LOAN BAR during fullscreen
521
+ */
522
+ manageFullScreenBehavior() {
523
+ this.emitFullScreenState();
524
+
525
+ if (!this.bookreader.options.enableFSLogoShortcut) {
526
+ return;
527
+ }
528
+
529
+ const isFullScreen = this.bookreader.isFullscreen();
530
+ if (isFullScreen) {
531
+ this.addFullscreenShortcut();
532
+ } else {
533
+ this.deleteFullscreenShortcut();
534
+ }
535
+ }
536
+
537
+ /**
538
+ * Relays fullscreen toggle events
539
+ */
540
+ emitFullScreenState() {
541
+ const isFullScreen = this.bookreader.isFullscreen();
542
+ const event = new CustomEvent('ViewportInFullScreen', {
543
+ detail: { isFullScreen },
544
+ });
545
+ this.dispatchEvent(event);
546
+ }
547
+
548
+ get itemImage() {
549
+ const identifier = this.itemMD?.metadata.identifier;
550
+ const url = `https://${this.baseHost}/services/img/${identifier}`;
551
+ return html`<img class="cover-img" src=${url} alt="cover image for ${identifier}">`;
552
+ }
553
+
554
+ get placeholder() {
555
+ return html`<div class="placeholder">${this.itemImage}</div>`;
556
+ }
557
+
558
+ render() {
559
+ return html`<div id="book-navigator__root">
560
+ ${this.bookReaderCannotLoad ? this.placeholder : nothing}
561
+ ${!this.bookReaderCannotLoad ? html`<slot name="main"></slot>` : nothing}
562
+ </div>
563
+ `;
564
+ }
565
+
566
+ static get styles() {
567
+ return css`
568
+ :host,
569
+ #book-navigator__root,
570
+ slot,
571
+ slot > * {
572
+ display: block;
573
+ height: inherit;
574
+ width: inherit;
575
+ }
576
+ .placeholder {
577
+ display: flex;
578
+ align-items: center;
579
+ justify-content: center;
580
+ flex-direction: column;
581
+ margin: 5%;
582
+ }
583
+ .cover-img {
584
+ max-height: 300px;
585
+ }
586
+ `;
587
+ }
588
+ }
589
+
590
+ customElements.define('book-navigator', BookNavigator);
@@ -1,4 +1,4 @@
1
- import { LitElement, html, css } from 'lit-element';
1
+ import { LitElement, html, css } from 'lit';
2
2
 
3
3
  export default class BookmarkButton extends LitElement {
4
4
  static get styles() {
@@ -12,7 +12,7 @@ export default class BookmarkButton extends LitElement {
12
12
  height: 4rem;
13
13
  width: 4rem;
14
14
  background: transparent;
15
- cursor: url('/images/bookreader/bookmark-add.png'), pointer;
15
+ cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24' viewBox='0 0 16 24' width='16'%3E%3Cg fill='%23333' fill-rule='evenodd'%3E%3Cpath d='m15 0c.5522847 0 1 .44771525 1 1v23l-8-5.4545455-8 5.4545455v-23c0-.55228475.44771525-1 1-1zm-2 2h-10c-.51283584 0-.93550716.38604019-.99327227.88337887l-.00672773.11662113v18l6-4.3181818 6 4.3181818v-18c0-.51283584-.3860402-.93550716-.8833789-.99327227z'/%3E%3Cpath d='m8.75 6v2.25h2.25v1.5h-2.25v2.25h-1.5v-2.25h-2.25v-1.5h2.25v-2.25z' fill-rule='nonzero'/%3E%3C/g%3E%3C/svg%3E"), pointer;
16
16
  position: relative;
17
17
  }
18
18
  button > * {
@@ -40,6 +40,7 @@ export default class BookmarkButton extends LitElement {
40
40
  constructor() {
41
41
  super();
42
42
  this.state = 'hollow';
43
+ this.side = undefined;
43
44
  }
44
45
 
45
46
  handleClick(e) {
@@ -1,6 +1,5 @@
1
- import { nothing } from 'lit-html';
2
- import { repeat } from 'lit-html/directives/repeat.js';
3
- import { css, html, LitElement } from 'lit-element';
1
+ import { repeat } from 'lit/directives/repeat.js';
2
+ import { css, html, LitElement, nothing } from 'lit';
4
3
  import bookmarkColorsCSS from '../assets/bookmark-colors.js';
5
4
  import buttonCSS from '../assets/button-base.js';
6
5
 
@@ -208,7 +207,7 @@ export class IABookmarkEdit extends LitElement {
208
207
  grid-gap: 0 1rem;
209
208
  justify-items: stretch;
210
209
  }
211
- `
210
+ `;
212
211
  return [buttonCSS, bookmarkColorsCSS, bookmarkEditCSS];
213
212
  }
214
213
  }
@@ -1,6 +1,5 @@
1
- import { nothing } from 'lit-html';
2
- import { repeat } from 'lit-html/directives/repeat.js';
3
- import { css, html, LitElement } from 'lit-element';
1
+ import { repeat } from 'lit/directives/repeat.js';
2
+ import { css, html, LitElement, nothing } from 'lit';
4
3
  import './bookmark-edit.js';
5
4
  import '@internetarchive/icon-edit-pencil/icon-edit-pencil.js';
6
5
  import bookmarkColorsCSS from '../assets/bookmark-colors.js';
@@ -1,20 +1,15 @@
1
- import { LitElement, html, css } from 'lit-element';
1
+ import { LitElement, html } from 'lit';
2
2
  import buttonStyles from '../assets/button-base.js';
3
3
 
4
4
  class BookmarksLogin extends LitElement {
5
5
  static get properties() {
6
6
  return {
7
7
  url: { type: String }
8
- }
8
+ };
9
9
  }
10
10
 
11
11
  static get styles() {
12
- const mainCss = css`
13
- a {
14
- text-decoration: none;
15
- }
16
- `;
17
- return [buttonStyles, mainCss];
12
+ return buttonStyles;
18
13
  }
19
14
 
20
15
  constructor() {