@internetarchive/bookreader 5.0.0-5 → 5.0.0-50-a1

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 (260) hide show
  1. package/.eslintrc.js +17 -15
  2. package/.github/workflows/node.js.yml +77 -6
  3. package/.github/workflows/npm-publish.yml +6 -20
  4. package/.testcaferc.js +10 -0
  5. package/BookReader/BookReader.css +131 -339
  6. package/BookReader/BookReader.js +1 -1
  7. package/BookReader/BookReader.js.LICENSE.txt +24 -0
  8. package/BookReader/BookReader.js.map +1 -1
  9. package/BookReader/ia-bookreader-bundle.js +1493 -0
  10. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +17 -0
  11. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  12. package/BookReader/icons/close-circle-dark.svg +1 -0
  13. package/BookReader/icons/magnify-minus.svg +1 -1
  14. package/BookReader/icons/magnify-plus.svg +1 -1
  15. package/BookReader/icons/pause.svg +1 -1
  16. package/BookReader/icons/playback-speed.svg +1 -1
  17. package/BookReader/icons/read-aloud.svg +1 -1
  18. package/BookReader/icons/voice.svg +1 -0
  19. package/BookReader/images/BRicons.svg +2 -2
  20. package/BookReader/images/books_graphic.svg +1 -1
  21. package/BookReader/images/icon_book.svg +1 -1
  22. package/BookReader/images/icon_gear.svg +1 -1
  23. package/BookReader/images/icon_info.svg +1 -1
  24. package/BookReader/images/icon_playback-rate.svg +1 -1
  25. package/BookReader/images/icon_search_button.svg +1 -1
  26. package/BookReader/images/icon_share.svg +1 -1
  27. package/BookReader/images/icon_speaker.svg +1 -1
  28. package/BookReader/images/icon_speaker_open.svg +1 -1
  29. package/BookReader/images/marker_chap-off.svg +1 -1
  30. package/BookReader/images/marker_chap-on.svg +1 -1
  31. package/BookReader/images/marker_srch-on.svg +1 -1
  32. package/BookReader/jquery-3.js +2 -0
  33. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  34. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  35. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  36. package/BookReader/plugins/plugin.autoplay.js +1 -1
  37. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  38. package/BookReader/plugins/plugin.chapters.js +1 -1
  39. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  40. package/BookReader/plugins/plugin.iframe.js +1 -1
  41. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  42. package/BookReader/plugins/plugin.mobile_nav.js +1 -1
  43. package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
  44. package/BookReader/plugins/plugin.resume.js +1 -1
  45. package/BookReader/plugins/plugin.resume.js.map +1 -1
  46. package/BookReader/plugins/plugin.search.js +1 -1
  47. package/BookReader/plugins/plugin.search.js.map +1 -1
  48. package/BookReader/plugins/plugin.text_selection.js +1 -1
  49. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  50. package/BookReader/plugins/plugin.tts.js +1 -1
  51. package/BookReader/plugins/plugin.tts.js.map +1 -1
  52. package/BookReader/plugins/plugin.url.js +1 -1
  53. package/BookReader/plugins/plugin.url.js.map +1 -1
  54. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
  55. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  56. package/BookReader/webcomponents-bundle.js +3 -0
  57. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  58. package/BookReader/webcomponents-bundle.js.map +1 -0
  59. package/BookReaderDemo/BookReaderDemo.css +14 -1
  60. package/BookReaderDemo/IADemoBr.js +148 -0
  61. package/BookReaderDemo/demo-advanced.html +2 -2
  62. package/BookReaderDemo/demo-autoplay.html +2 -1
  63. package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
  64. package/BookReaderDemo/demo-fullscreen-mobile.html +2 -1
  65. package/BookReaderDemo/demo-fullscreen.html +2 -1
  66. package/BookReaderDemo/demo-iiif.html +2 -1
  67. package/BookReaderDemo/demo-internetarchive.html +84 -17
  68. package/BookReaderDemo/demo-multiple.html +2 -1
  69. package/BookReaderDemo/demo-preview-pages.html +2 -1
  70. package/BookReaderDemo/demo-simple.html +2 -1
  71. package/BookReaderDemo/demo-vendor-fullscreen.html +2 -1
  72. package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
  73. package/BookReaderDemo/immersion-1up.html +2 -1
  74. package/BookReaderDemo/immersion-mode.html +2 -1
  75. package/BookReaderDemo/toggle_controls.html +2 -1
  76. package/BookReaderDemo/view_mode.html +2 -1
  77. package/BookReaderDemo/viewmode-cycle.html +2 -3
  78. package/CHANGELOG.md +202 -0
  79. package/README.md +14 -1
  80. package/babel.config.js +18 -0
  81. package/codecov.yml +6 -0
  82. package/index.html +3 -0
  83. package/jsconfig.json +19 -0
  84. package/package.json +66 -56
  85. package/renovate.json +52 -0
  86. package/scripts/preversion.js +4 -1
  87. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  88. package/src/BookNavigator/assets/button-base.js +9 -2
  89. package/src/BookNavigator/assets/ia-logo.js +17 -0
  90. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  91. package/src/BookNavigator/assets/icon_close.js +1 -1
  92. package/src/BookNavigator/assets/icon_sort_asc.js +5 -0
  93. package/src/BookNavigator/assets/icon_sort_desc.js +5 -0
  94. package/src/BookNavigator/assets/icon_sort_neutral.js +5 -0
  95. package/src/BookNavigator/assets/icon_volumes.js +11 -0
  96. package/src/BookNavigator/book-navigator.js +583 -0
  97. package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
  98. package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
  99. package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
  100. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
  101. package/src/BookNavigator/bookmarks/bookmarks-provider.js +21 -8
  102. package/src/BookNavigator/bookmarks/ia-bookmarks.js +102 -66
  103. package/src/BookNavigator/delete-modal-actions.js +1 -1
  104. package/src/BookNavigator/downloads/downloads-provider.js +36 -21
  105. package/src/BookNavigator/downloads/downloads.js +41 -25
  106. package/src/BookNavigator/search/a-search-result.js +18 -13
  107. package/src/BookNavigator/search/search-provider.js +80 -28
  108. package/src/BookNavigator/search/search-results.js +10 -18
  109. package/src/BookNavigator/sharing.js +27 -0
  110. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -10
  111. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +3 -3
  112. package/src/BookNavigator/volumes/volumes-provider.js +114 -0
  113. package/src/BookNavigator/volumes/volumes.js +188 -0
  114. package/src/BookReader/BookModel.js +0 -29
  115. package/src/BookReader/DebugConsole.js +3 -3
  116. package/src/BookReader/DragScrollable.js +233 -0
  117. package/src/BookReader/Mode1Up.js +51 -351
  118. package/src/BookReader/Mode1UpLit.js +441 -0
  119. package/src/BookReader/Mode2Up.js +120 -105
  120. package/src/BookReader/ModeSmoothZoom.js +179 -0
  121. package/src/BookReader/ModeThumb.js +17 -11
  122. package/src/BookReader/Navbar/Navbar.js +10 -36
  123. package/src/BookReader/PageContainer.js +69 -6
  124. package/src/BookReader/ReduceSet.js +1 -1
  125. package/src/BookReader/Toolbar/Toolbar.js +10 -37
  126. package/src/BookReader/options.js +10 -0
  127. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  128. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  129. package/src/BookReader/utils.js +92 -13
  130. package/src/BookReader.js +431 -620
  131. package/src/assets/icons/close-circle-dark.svg +1 -0
  132. package/src/assets/icons/magnify-minus.svg +3 -7
  133. package/src/assets/icons/magnify-plus.svg +3 -7
  134. package/src/assets/icons/voice.svg +1 -0
  135. package/src/css/BookReader.scss +0 -12
  136. package/src/css/_BRComponent.scss +1 -1
  137. package/src/css/_BRmain.scss +19 -24
  138. package/src/css/_BRnav.scss +4 -26
  139. package/src/css/_BRpages.scss +35 -0
  140. package/src/css/_BRsearch.scss +25 -216
  141. package/src/css/_TextSelection.scss +14 -17
  142. package/src/css/_colorbox.scss +2 -2
  143. package/src/css/_controls.scss +17 -5
  144. package/src/css/_icons.scss +6 -0
  145. package/src/ia-bookreader/ia-bookreader.js +224 -0
  146. package/src/plugins/plugin.autoplay.js +4 -4
  147. package/src/plugins/plugin.chapters.js +28 -35
  148. package/src/plugins/plugin.mobile_nav.js +11 -10
  149. package/src/plugins/plugin.resume.js +3 -3
  150. package/src/plugins/plugin.text_selection.js +26 -39
  151. package/src/plugins/plugin.vendor-fullscreen.js +4 -4
  152. package/src/plugins/search/plugin.search.js +174 -116
  153. package/src/plugins/search/view.js +63 -179
  154. package/src/plugins/tts/AbstractTTSEngine.js +46 -37
  155. package/src/plugins/tts/FestivalTTSEngine.js +13 -14
  156. package/src/plugins/tts/PageChunk.js +15 -21
  157. package/src/plugins/tts/PageChunkIterator.js +8 -12
  158. package/src/plugins/tts/WebTTSEngine.js +66 -69
  159. package/src/plugins/tts/plugin.tts.js +92 -109
  160. package/src/plugins/tts/utils.js +0 -9
  161. package/src/plugins/url/UrlPlugin.js +184 -0
  162. package/src/plugins/{plugin.url.js → url/plugin.url.js} +28 -6
  163. package/src/util/manifestGenerator.js +0 -0
  164. package/tests/e2e/README.md +37 -0
  165. package/tests/e2e/autoplay.test.js +2 -2
  166. package/tests/e2e/base.test.js +7 -7
  167. package/tests/e2e/helpers/base.js +9 -3
  168. package/tests/e2e/helpers/debug.js +1 -1
  169. package/tests/e2e/helpers/desktopSearch.js +14 -13
  170. package/tests/e2e/helpers/mobileSearch.js +3 -3
  171. package/tests/e2e/helpers/params.js +17 -0
  172. package/tests/e2e/models/Navigation.js +13 -4
  173. package/tests/e2e/rightToLeft.test.js +4 -5
  174. package/tests/e2e/viewmode.test.js +38 -33
  175. package/tests/jest/BookNavigator/book-navigator.test.js +634 -0
  176. package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
  177. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
  178. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
  179. package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
  180. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
  181. package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
  182. package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
  183. package/tests/{karma/BookNavigator → jest/BookNavigator/search}/search-results.test.js +102 -58
  184. package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
  185. package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
  186. package/tests/jest/BookNavigator/volumes/volumes-provider.test.js +184 -0
  187. package/tests/jest/BookNavigator/volumes/volumes.test.js +97 -0
  188. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +34 -14
  189. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +176 -0
  190. package/tests/{BookReader → jest/BookReader}/DebugConsole.test.js +1 -1
  191. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  192. package/tests/jest/BookReader/Mode1UpLit.test.js +92 -0
  193. package/tests/{BookReader → jest/BookReader}/Mode2Up.test.js +36 -15
  194. package/tests/jest/BookReader/ModeSmoothZoom.test.js +149 -0
  195. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  196. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +7 -7
  197. package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +88 -6
  198. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  199. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
  200. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  201. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  202. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  203. package/tests/jest/BookReader/utils.test.js +186 -0
  204. package/tests/jest/BookReader.keyboard.test.js +190 -0
  205. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
  206. package/tests/{BookReader.test.js → jest/BookReader.test.js} +18 -37
  207. package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
  208. package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +4 -4
  209. package/tests/{plugins → jest/plugins}/plugin.chapters.test.js +10 -11
  210. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
  211. package/tests/{plugins → jest/plugins}/plugin.mobile_nav.test.js +5 -5
  212. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
  213. package/tests/{plugins → jest/plugins}/plugin.text_selection.test.js +39 -47
  214. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  215. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +63 -47
  216. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +35 -6
  217. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +9 -9
  218. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  219. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  220. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  221. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +1 -1
  222. package/tests/{plugins → jest/plugins}/tts/utils.test.js +3 -28
  223. package/tests/jest/plugins/url/UrlPlugin.test.js +190 -0
  224. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +33 -14
  225. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  226. package/tests/{util → jest/util}/docCookies.test.js +1 -1
  227. package/tests/{util → jest/util}/strings.test.js +1 -1
  228. package/tests/{utils.js → jest/utils.js} +38 -0
  229. package/webpack.config.js +11 -5
  230. package/.babelrc +0 -12
  231. package/.dependabot/config.yml +0 -6
  232. package/.testcaferc.json +0 -5
  233. package/BookReader/bookreader-component-bundle.js +0 -1450
  234. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  235. package/BookReader/bookreader-component-bundle.js.map +0 -1
  236. package/BookReader/jquery-1.10.1.js +0 -2
  237. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  238. package/BookReader/plugins/plugin.menu_toggle.js +0 -2
  239. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  240. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  241. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  242. package/karma.conf.js +0 -23
  243. package/src/BookNavigator/BookModel.js +0 -14
  244. package/src/BookNavigator/BookNavigator.js +0 -438
  245. package/src/BookNavigator/assets/book-loader.js +0 -27
  246. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  247. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  248. package/src/ItemNavigator/ItemNavigator.js +0 -372
  249. package/src/ItemNavigator/providers/sharing.js +0 -29
  250. package/src/Layers/sharing/sharing-provider.js +0 -22
  251. package/src/dragscrollable-br.js +0 -261
  252. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  253. package/src/plugins/plugin.bookmarks.js +0 -50
  254. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  255. package/tests/BookReader/Mode1Up.test.js +0 -164
  256. package/tests/BookReader/utils.test.js +0 -109
  257. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  258. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  259. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  260. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
@@ -0,0 +1,11 @@
1
+ import { html } from 'lit';
2
+
3
+ export default html`
4
+ <svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" aria-labelledby="volumesTitleID volumesDescID">
5
+ <title id="volumesTitleID">Volumes icon</title>
6
+ <desc id="volumesDescID">Three books stacked on each other</desc>
7
+ <g fill="#ffffff">
8
+ <path fill="#ffffff" d="m9.83536396 0h10.07241114c.1725502.47117517.3378411.76385809.4958725.87804878.1295523.11419069.3199719.1998337.5712586.25692905.2512868.05709534.4704647.08564301.6575337.08564301h.2806036v15.24362526h-4.3355343v3.8106985h-4.44275v3.7250554h-12.01318261c-.27306495 0-.50313194-.085643-.69020098-.256929-.18706903-.1712861-.30936193-.3425721-.36687867-.5138581l-.06449694-.2785477v-14.2159091c0-.32815965.08627512-.5922949.25882537-.79240577.17255024-.20011086.34510049-.32150776.51765073-.36419068l.25882537-.0640244h3.36472977v-2.54767184c0-.31374722.08627513-.57067627.25882537-.77078714.17255025-.20011086.34510049-.32150776.51765074-.36419068l.25882536-.06402439h3.36472978v-2.56929047c0-.32815964.08627512-.5922949.25882537-.79240576.17255024-.20011087.34510049-.31430156.51765073-.34257207zm10.78355264 15.6294346v-13.53076498c-.2730649-.08536585-.4456152-.16380266-.5176507-.23531042-.1725502-.1424612-.2730649-.27078714-.3015441-.38497783v13.36031043h-9.87808272c0 .0144124-.02149898.0144124-.06449694 0-.04299795-.0144124-.08962561.006929-.13988296.0640244-.05025735.0570953-.07538603.1427383-.07538603.256929s.02149898.210643.06449694.289357c.04299795.078714.08599591.1322062.12899387.1604767l.06449693.0216187h10.71905571zm-10.2449613-2.4412417h7.98003v-11.60421286h-7.98003zm1.6827837-9.41990022h4.6153002c.1725502 0 .3199718.05349224.4422647.16047672s.1834393.23891353.1834393.39578714c0 .15687362-.0611464.28519956-.1834393.38497783s-.2697145.1496674-.4422647.1496674h-4.6153002c-.1725503 0-.3199719-.04988913-.4422647-.1496674-.1222929-.09977827-.1834394-.22810421-.1834394-.38497783 0-.15687361.0611465-.28880266.1834394-.39578714.1222928-.10698448.2697144-.16047672.4422647-.16047672zm-6.08197737 13.50997782h7.72120467v-.8131929h-3.79610541c-.27306495 0-.49950224-.085643-.67931188-.256929-.17980964-.1712861-.29847284-.3425721-.35598958-.5138581l-.06449694-.2785477v-10.02023282h-2.82530086zm6.77217827-11.36890243h3.2139578c.1295522 0 .240956.05709534.3342113.17128603.0932554.11419069.139883.24972284.139883.40659645 0 .15687362-.0466276.28880267-.139883.39578714-.0932553.10698448-.2046591.16047672-.3342113.16047672h-3.2139578c-.1295523 0-.2373264-.05349224-.3233223-.16047672-.0859959-.10698447-.1289938-.23891352-.1289938-.39578714 0-.15687361.0429979-.29240576.1289938-.40659645s.19377-.17128603.3233223-.17128603zm-11.15043132 15.11557653h7.69942646v-.7491685h-3.79610539c-.25854616 0-.48135376-.0892462-.66842279-.2677384-.18706904-.1784922-.30936193-.3605876-.36687868-.546286l-.06449694-.2569291v-10.04101994h-2.80352266zm14.62237682-4.5606985h-.8191949v2.1410754h-9.89986085s-.04299796.0285477-.12899387.085643c-.08599592.0570954-.12201369.1427384-.10805331.2569291 0 .1141907.01786928.210643.05360784.289357.03573856.0787139.07538603.125.1189424.138858l.06449694.0432373h10.71905575v-2.9542683zm-4.3991936 3.8106985h-.8191949v2.077051h-9.8563045c0 .0144124-.02149898.0144124-.06449694 0-.04299795-.0144125-.08962561.0105321-.13988296.0748337-.05025735.0643015-.07538603.1607538-.07538603.289357 0 .1141906.02149898.2070399.06449694.2785476.04299795.0715078.08599591.1141907.12899387.1280488l.06449693.0216186h10.69811519v-2.8686252z" />
9
+ </g>
10
+ </svg>
11
+ `;
@@ -0,0 +1,583 @@
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 VolumesProvider from './volumes/volumes-provider.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
+ 'search',
73
+ 'bookmarks'
74
+ ];
75
+ }
76
+
77
+ disconnectedCallback() {
78
+ this.sharedObserver.removeObserver({
79
+ target: this.mainBRContainer,
80
+ handler: this.sharedObserverHandler
81
+ });
82
+ }
83
+
84
+ firstUpdated() {
85
+ this.bindEventListeners();
86
+ this.emitPostInit();
87
+ this.loaded = true;
88
+ }
89
+
90
+ updated(changed) {
91
+ if (!this.bookreader || !this.itemMD || !this.bookReaderLoaded) {
92
+ return;
93
+ }
94
+
95
+ const reload = changed.has('loaded') && this.loaded;
96
+ if (reload
97
+ || changed.has('itemMD')
98
+ || changed.has('bookreader')
99
+ || changed.has('signedIn')
100
+ || changed.has('isAdmin')
101
+ || changed.has('modal')) {
102
+ this.initializeBookSubmenus();
103
+ }
104
+
105
+ if (changed.has('sharedObserver') && this.bookreader) {
106
+ this.loadSharedObserver();
107
+ this.initializeBookSubmenus();
108
+ }
109
+
110
+ if (changed.has('downloadableTypes')) {
111
+ this.initializeBookSubmenus();
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Global event emitter for when Book Navigator loads
117
+ */
118
+ emitPostInit() {
119
+ // emit global event when book nav has loaded with current bookreader selector
120
+ this.dispatchEvent(new CustomEvent(`BrBookNav:${events.PostInit}`, {
121
+ detail: { brSelector: this.bookreader?.el },
122
+ bubbles: true,
123
+ composed: true,
124
+ }));
125
+ }
126
+
127
+ /**
128
+ * @typedef {{
129
+ * baseHost: string,
130
+ * modal: ModalManager,
131
+ * sharedObserver: SharedResizeObserver,
132
+ * bookreader: BookReader,
133
+ * item: Item,
134
+ * signedIn: boolean,
135
+ * isAdmin: boolean,
136
+ * onProviderChange: (BookReader, object) => void,
137
+ * }} baseProviderConfig
138
+ *
139
+ * @return {baseProviderConfig}
140
+ */
141
+ get baseProviderConfig() {
142
+ return {
143
+ baseHost: this.baseHost,
144
+ modal: this.modal,
145
+ sharedObserver: this.sharedObserver,
146
+ bookreader: this.bookreader,
147
+ item: this.itemMD,
148
+ signedIn: this.signedIn,
149
+ isAdmin: this.isAdmin,
150
+ onProviderChange: () => {}
151
+ };
152
+ }
153
+
154
+ get isWideEnoughToOpenMenu() {
155
+ return this.brWidth >= 640;
156
+ }
157
+ /**
158
+ * Instantiates books submenus & their update callbacks
159
+ *
160
+ * NOTE: we are doing our best to scope bookreader's instance.
161
+ * If your submenu provider uses a bookreader instance to read, manually
162
+ * manipulate BookReader, please update the navigator's instance of it
163
+ * to keep it in sync.
164
+ */
165
+ initializeBookSubmenus() {
166
+ const providers = {
167
+ downloads: new DownloadProvider(this.baseProviderConfig),
168
+ share: new SharingProvider(this.baseProviderConfig),
169
+ visualAdjustments: new VisualAdjustmentProvider({
170
+ ...this.baseProviderConfig,
171
+ /** Update menu contents */
172
+ onProviderChange: () => {
173
+ this.updateMenuContents();
174
+ },
175
+ }),
176
+ };
177
+
178
+ if (this.bookreader.options.enableSearch) {
179
+ providers.search = new SearchProvider({
180
+ ...this.baseProviderConfig,
181
+ /**
182
+ * Search specific menu updates
183
+ * @param {BookReader} brInstance
184
+ * @param {{ searchCanceled: boolean }} searchUpdates
185
+ */
186
+ onProviderChange: (brInstance = null, searchUpdates = {}) => {
187
+ if (brInstance) {
188
+ /* refresh br instance reference */
189
+ this.bookreader = brInstance;
190
+ }
191
+
192
+ this.updateMenuContents();
193
+
194
+ if (searchUpdates.openMenu === false) {
195
+ return;
196
+ }
197
+
198
+ if (this.isWideEnoughToOpenMenu && !searchUpdates?.searchCanceled) {
199
+ /* open side search menu */
200
+ setTimeout(() => {
201
+ this.updateSideMenu('search', 'open');
202
+ }, 0);
203
+ }
204
+ },
205
+ });
206
+ }
207
+
208
+ if (this.bookreader.options.enableBookmarks) {
209
+ providers.bookmarks = new BookmarksProvider({
210
+ ...this.baseProviderConfig,
211
+ onProviderChange: (bookmarks) => {
212
+ const method = Object.keys(bookmarks).length ? 'add' : 'remove';
213
+ this[`${method}MenuShortcut`]('bookmarks');
214
+ this.updateMenuContents();
215
+ }
216
+ });
217
+ }
218
+
219
+ // add shortcut for volumes if multipleBooksList exists
220
+ if (this.bookreader.options.enableMultipleBooks) {
221
+ providers.volumes = new VolumesProvider({
222
+ ...this.baseProviderConfig,
223
+ onProviderChange: (brInstance = null, volumesUpdates = {}) => {
224
+ if (brInstance) {
225
+ /* refresh br instance reference */
226
+ this.bookreader = brInstance;
227
+ }
228
+ this.updateMenuContents();
229
+ if (this.isWideEnoughToOpenMenu) {
230
+ /* open side search menu */
231
+ setTimeout(() => {
232
+ this.updateSideMenu('volumes', 'open');
233
+ });
234
+ }
235
+ }
236
+ });
237
+ }
238
+
239
+ this.menuProviders = providers;
240
+ this.addMenuShortcut('search');
241
+ this.addMenuShortcut('volumes');
242
+ this.updateMenuContents();
243
+ }
244
+
245
+ /** gets element that houses the bookreader in light dom */
246
+ get mainBRContainer() {
247
+ return document.querySelector(this.bookreader?.el);
248
+ }
249
+
250
+ /** Fullscreen Shortcut */
251
+ addFullscreenShortcut() {
252
+ const closeFS = {
253
+ icon: this.fullscreenShortcut,
254
+ id: 'fullscreen',
255
+ };
256
+ this.menuShortcuts.push(closeFS);
257
+ this.sortMenuShortcuts();
258
+ this.emitMenuShortcutsUpdated();
259
+ }
260
+
261
+ deleteFullscreenShortcut() {
262
+ const updatedShortcuts = this.menuShortcuts.filter(({ id }) => {
263
+ return id !== 'fullscreen';
264
+ });
265
+ this.menuShortcuts = updatedShortcuts;
266
+ this.sortMenuShortcuts();
267
+ this.emitMenuShortcutsUpdated();
268
+ }
269
+
270
+ closeFullscreen() {
271
+ this.bookreader.exitFullScreen();
272
+ }
273
+
274
+ get fullscreenShortcut() {
275
+ return html`
276
+ <button
277
+ @click=${() => this.closeFullscreen()}
278
+ title="Exit fullscreen view"
279
+ >${this.fullscreenBranding}</button>
280
+ `;
281
+ }
282
+ /** End Fullscreen Shortcut */
283
+
284
+ /**
285
+ * Open side menu
286
+ * @param {string} menuId
287
+ * @param {('open'|'close'|'toggle')} action
288
+ */
289
+ updateSideMenu(menuId = '', action = 'open') {
290
+ if (!menuId) {
291
+ return;
292
+ }
293
+ const event = new CustomEvent(
294
+ events.updateSideMenu, {
295
+ detail: { menuId, action },
296
+ },
297
+ );
298
+ this.dispatchEvent(event);
299
+ }
300
+
301
+ /**
302
+ * Sets order of menu and emits custom event when done
303
+ */
304
+ updateMenuContents() {
305
+ const {
306
+ search, downloads, visualAdjustments, share, bookmarks, volumes
307
+ } = this.menuProviders;
308
+ const availableMenus = [volumes, search, bookmarks, visualAdjustments, share].filter((menu) => !!menu);
309
+
310
+ if (this.shouldShowDownloadsMenu()) {
311
+ downloads?.update(this.downloadableTypes);
312
+ availableMenus.splice(1, 0, downloads);
313
+ }
314
+
315
+ const event = new CustomEvent(
316
+ events.menuUpdated, {
317
+ detail: availableMenus,
318
+ },
319
+ );
320
+ this.dispatchEvent(event);
321
+ }
322
+
323
+ /**
324
+ * Confirms if we should show the downloads menu
325
+ * @returns {bool}
326
+ */
327
+ shouldShowDownloadsMenu() {
328
+ if (this.bookIsRestricted === false) { return true; }
329
+ if (this.isAdmin) { return true; }
330
+ const { user_loan_record = {} } = this.lendingStatus;
331
+ const hasNoLoanRecord = Array.isArray(user_loan_record); /* (bc PHP assoc. arrays) */
332
+
333
+ if (hasNoLoanRecord) { return false; }
334
+
335
+ const hasValidLoan = user_loan_record.type && (user_loan_record.type !== 'SESSION_LOAN');
336
+ return hasValidLoan;
337
+ }
338
+
339
+ /**
340
+ * Adds a provider object to the menuShortcuts array property if it isn't
341
+ * already added. menuShortcuts are then sorted by shortcutOrder and
342
+ * a menuShortcutsUpdated event is emitted.
343
+ *
344
+ * @param {string} menuId - a string matching the id property of a provider
345
+ */
346
+ addMenuShortcut(menuId) {
347
+ if (this.menuShortcuts.find((m) => m.id === menuId)) {
348
+ // menu is already there
349
+ return;
350
+ }
351
+
352
+ if (!this.menuProviders[menuId]) {
353
+ // no provider for this menu
354
+ return;
355
+ }
356
+
357
+ this.menuShortcuts.push(this.menuProviders[menuId]);
358
+
359
+ this.sortMenuShortcuts();
360
+ this.emitMenuShortcutsUpdated();
361
+ }
362
+
363
+ /**
364
+ * Removes a provider object from the menuShortcuts array and emits a
365
+ * menuShortcutsUpdated event.
366
+ *
367
+ * @param {string} menuId - a string matching the id property of a provider
368
+ */
369
+ removeMenuShortcut(menuId) {
370
+ this.menuShortcuts = this.menuShortcuts.filter((m) => m.id !== menuId);
371
+ this.emitMenuShortcutsUpdated();
372
+ }
373
+
374
+ /**
375
+ * Sorts the menuShortcuts property by comparing each provider's id to
376
+ * the id in each iteration over the shortcutOrder array.
377
+ */
378
+ sortMenuShortcuts() {
379
+ this.menuShortcuts = this.shortcutOrder.reduce((shortcuts, id) => {
380
+ const menu = this.menuShortcuts.find((m) => m.id === id);
381
+ if (menu) { shortcuts.push(menu); }
382
+ return shortcuts;
383
+ }, []);
384
+ }
385
+
386
+ emitMenuShortcutsUpdated() {
387
+ const event = new CustomEvent('menuShortcutsUpdated', {
388
+ detail: this.menuShortcuts,
389
+ });
390
+ this.dispatchEvent(event);
391
+ }
392
+
393
+ emitLoadingStatusUpdate(loaded) {
394
+ const event = new CustomEvent('loadingStateUpdated', {
395
+ detail: { loaded },
396
+ });
397
+ this.dispatchEvent(event);
398
+ }
399
+
400
+ /**
401
+ * Core bookreader event handler registry
402
+ *
403
+ * NOTE: we are trying to keep bookreader's instance in scope
404
+ * Please update Book Navigator's instance reference of it to keep it current
405
+ */
406
+ bindEventListeners() {
407
+ window.addEventListener('BookReader:PostInit', (e) => {
408
+ this.bookreader = e.detail.props;
409
+ this.bookReaderLoaded = true;
410
+ this.bookReaderCannotLoad = false;
411
+ this.emitLoadingStatusUpdate(true);
412
+ this.loadSharedObserver();
413
+ setTimeout(() => {
414
+ this.bookreader.resize();
415
+ }, 0);
416
+ });
417
+ window.addEventListener('BookReader:fullscreenToggled', (event) => {
418
+ const { detail: { props: brInstance = null } } = event;
419
+ if (brInstance) {
420
+ this.bookreader = brInstance;
421
+ }
422
+ this.manageFullScreenBehavior();
423
+ }, { passive: true });
424
+ window.addEventListener('BookReader:ToggleSearchMenu', (event) => {
425
+ this.dispatchEvent(new CustomEvent(events.updateSideMenu, {
426
+ detail: { menuId: 'search', action: 'toggle' },
427
+ }));
428
+ });
429
+ window.addEventListener('LendingFlow:PostInit', ({ detail }) => {
430
+ const {
431
+ downloadTypesAvailable, lendingStatus, isAdmin, previewType,
432
+ } = detail;
433
+ this.lendingInitialized = true;
434
+ this.downloadableTypes = downloadTypesAvailable;
435
+ this.lendingStatus = lendingStatus;
436
+ this.isAdmin = isAdmin;
437
+ this.bookReaderCannotLoad = previewType === 'singlePagePreview';
438
+ this.emitLoadingStatusUpdate(true);
439
+ });
440
+ window.addEventListener('BRJSIA:PostInit', ({ detail }) => {
441
+ const { isRestricted, downloadURLs } = detail;
442
+ this.bookReaderLoaded = true;
443
+ this.downloadableTypes = downloadURLs;
444
+ this.bookIsRestricted = isRestricted;
445
+ });
446
+ window.addEventListener('contextmenu', (e) => this.manageContextMenuVisibility(e), { capture: true });
447
+ }
448
+
449
+ /** Display an element's context menu */
450
+ manageContextMenuVisibility(e) {
451
+ if (window.archive_analytics) {
452
+ window.archive_analytics?.send_event(
453
+ 'BookReader',
454
+ `contextmenu-${this.bookIsRestricted ? 'restricted' : 'unrestricted'}`,
455
+ e.target?.classList?.value
456
+ );
457
+ }
458
+ if (!this.bookIsRestricted) {
459
+ return;
460
+ }
461
+
462
+ const imagePane = e.target.classList.value.match(/BRscreen|BRpageimage/g);
463
+ if (!imagePane) {
464
+ return;
465
+ }
466
+
467
+ e.preventDefault();
468
+ return false;
469
+ }
470
+
471
+ loadSharedObserver() {
472
+ this.sharedObserverHandler = { handleResize: this.handleResize.bind(this) };
473
+ this.sharedObserver?.addObserver({
474
+ target: this.mainBRContainer,
475
+ handler: this.sharedObserverHandler
476
+ });
477
+ }
478
+
479
+ /**
480
+ * Uses resize observer to fire BookReader's `resize` functionality
481
+ * We do not want to trigger resize IF:
482
+ * - book animation is happening
483
+ * - book is in fullscreen (fullscreen is handled separately)
484
+ *
485
+ * @param { target: HTMLElement, contentRect: DOMRectReadOnly } entry
486
+ */
487
+ handleResize({ contentRect, target }) {
488
+ const startBrWidth = this.brWidth;
489
+ const startBrHeight = this.brHeight;
490
+ const { animating } = this.bookreader;
491
+
492
+ if (target === this.mainBRContainer) {
493
+ this.brWidth = contentRect.width;
494
+ this.brHeight = contentRect.height;
495
+ }
496
+
497
+ if (!startBrWidth && this.brWidth) {
498
+ // loading up, let's update side menus
499
+ this.initializeBookSubmenus();
500
+ }
501
+
502
+ const widthChange = startBrWidth !== this.brWidth;
503
+ const heightChange = startBrHeight !== this.brHeight;
504
+
505
+ if (!animating && (widthChange || heightChange)) {
506
+ this.bookreader?.resize();
507
+ }
508
+ }
509
+
510
+ /**
511
+ * Manages Fullscreen behavior
512
+ * This makes sure that controls are _always_ in view
513
+ * We need this to accommodate LOAN BAR during fullscreen
514
+ */
515
+ manageFullScreenBehavior() {
516
+ this.emitFullScreenState();
517
+
518
+ if (!this.bookreader.options.enableFSLogoShortcut) {
519
+ return;
520
+ }
521
+
522
+ const isFullScreen = this.bookreader.isFullscreen();
523
+ if (isFullScreen) {
524
+ this.addFullscreenShortcut();
525
+ } else {
526
+ this.deleteFullscreenShortcut();
527
+ }
528
+ }
529
+
530
+ /**
531
+ * Relays fullscreen toggle events
532
+ */
533
+ emitFullScreenState() {
534
+ const isFullScreen = this.bookreader.isFullscreen();
535
+ const event = new CustomEvent('ViewportInFullScreen', {
536
+ detail: { isFullScreen },
537
+ });
538
+ this.dispatchEvent(event);
539
+ }
540
+
541
+ get itemImage() {
542
+ const identifier = this.itemMD?.metadata.identifier;
543
+ const url = `https://${this.baseHost}/services/img/${identifier}`;
544
+ return html`<img class="cover-img" src=${url} alt="cover image for ${identifier}">`;
545
+ }
546
+
547
+ get placeholder() {
548
+ return html`<div class="placeholder">${this.itemImage}</div>`;
549
+ }
550
+
551
+ render() {
552
+ return html`<div id="book-navigator__root">
553
+ ${this.bookReaderCannotLoad ? this.placeholder : nothing}
554
+ ${!this.bookReaderCannotLoad ? html`<slot name="main"></slot>` : nothing}
555
+ </div>
556
+ `;
557
+ }
558
+
559
+ static get styles() {
560
+ return css`
561
+ :host,
562
+ #book-navigator__root,
563
+ slot,
564
+ slot > * {
565
+ display: block;
566
+ height: inherit;
567
+ width: inherit;
568
+ }
569
+ .placeholder {
570
+ display: flex;
571
+ align-items: center;
572
+ justify-content: center;
573
+ flex-direction: column;
574
+ margin: 5%;
575
+ }
576
+ .cover-img {
577
+ max-height: 300px;
578
+ }
579
+ `;
580
+ }
581
+ }
582
+
583
+ 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() {