@internetarchive/bookreader 5.0.0-5-multiple-files → 5.0.0-50

Sign up to get free protection for your applications and to get access to all the features.
Files changed (289) 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 +2 -21564
  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/1up.svg +1 -12
  13. package/BookReader/icons/2up.svg +1 -15
  14. package/BookReader/icons/advance.svg +3 -26
  15. package/BookReader/icons/chevron-right.svg +1 -1
  16. package/BookReader/icons/close-circle-dark.svg +1 -0
  17. package/BookReader/icons/close-circle.svg +1 -1
  18. package/BookReader/icons/fullscreen.svg +1 -17
  19. package/BookReader/icons/fullscreen_exit.svg +1 -17
  20. package/BookReader/icons/hamburger.svg +1 -15
  21. package/BookReader/icons/left-arrow.svg +1 -12
  22. package/BookReader/icons/magnify-minus.svg +1 -16
  23. package/BookReader/icons/magnify-plus.svg +1 -17
  24. package/BookReader/icons/magnify.svg +1 -15
  25. package/BookReader/icons/pause.svg +1 -23
  26. package/BookReader/icons/play.svg +1 -22
  27. package/BookReader/icons/playback-speed.svg +1 -34
  28. package/BookReader/icons/read-aloud.svg +1 -22
  29. package/BookReader/icons/review.svg +3 -22
  30. package/BookReader/icons/thumbnails.svg +1 -17
  31. package/BookReader/icons/voice.svg +1 -0
  32. package/BookReader/icons/volume-full.svg +1 -22
  33. package/BookReader/images/BRicons.svg +5 -94
  34. package/BookReader/images/books_graphic.svg +1 -177
  35. package/BookReader/images/icon_book.svg +1 -12
  36. package/BookReader/images/icon_bookmark.svg +1 -12
  37. package/BookReader/images/icon_gear.svg +1 -14
  38. package/BookReader/images/icon_hamburger.svg +1 -20
  39. package/BookReader/images/icon_home.svg +1 -21
  40. package/BookReader/images/icon_info.svg +1 -11
  41. package/BookReader/images/icon_one_page.svg +1 -8
  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 -15
  45. package/BookReader/images/icon_search_button.svg +1 -8
  46. package/BookReader/images/icon_share.svg +1 -9
  47. package/BookReader/images/icon_skip-ahead.svg +1 -6
  48. package/BookReader/images/icon_skip-back.svg +2 -13
  49. package/BookReader/images/icon_speaker.svg +1 -18
  50. package/BookReader/images/icon_speaker_open.svg +1 -10
  51. package/BookReader/images/icon_thumbnails.svg +1 -12
  52. package/BookReader/images/icon_toc.svg +1 -5
  53. package/BookReader/images/icon_two_pages.svg +1 -9
  54. package/BookReader/images/marker_chap-off.svg +1 -11
  55. package/BookReader/images/marker_chap-on.svg +1 -11
  56. package/BookReader/images/marker_srch-on.svg +1 -11
  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 -172
  60. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  61. package/BookReader/plugins/plugin.autoplay.js +1 -165
  62. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  63. package/BookReader/plugins/plugin.chapters.js +1 -304
  64. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  65. package/BookReader/plugins/plugin.iframe.js +1 -74
  66. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  67. package/BookReader/plugins/plugin.mobile_nav.js +1 -334
  68. package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
  69. package/BookReader/plugins/plugin.resume.js +1 -368
  70. package/BookReader/plugins/plugin.resume.js.map +1 -1
  71. package/BookReader/plugins/plugin.search.js +1 -1420
  72. package/BookReader/plugins/plugin.search.js.map +1 -1
  73. package/BookReader/plugins/plugin.text_selection.js +1 -1080
  74. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  75. package/BookReader/plugins/plugin.tts.js +2 -9193
  76. package/BookReader/plugins/plugin.tts.js.map +1 -1
  77. package/BookReader/plugins/plugin.url.js +1 -269
  78. package/BookReader/plugins/plugin.url.js.map +1 -1
  79. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -379
  80. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  81. package/BookReader/webcomponents-bundle.js +3 -0
  82. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  83. package/BookReader/webcomponents-bundle.js.map +1 -0
  84. package/BookReaderDemo/BookReaderDemo.css +14 -1
  85. package/BookReaderDemo/IADemoBr.js +148 -0
  86. package/BookReaderDemo/demo-advanced.html +2 -2
  87. package/BookReaderDemo/demo-autoplay.html +2 -1
  88. package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
  89. package/BookReaderDemo/demo-fullscreen-mobile.html +2 -1
  90. package/BookReaderDemo/demo-fullscreen.html +2 -1
  91. package/BookReaderDemo/demo-iiif.html +2 -1
  92. package/BookReaderDemo/demo-internetarchive.html +84 -17
  93. package/BookReaderDemo/demo-multiple.html +2 -1
  94. package/BookReaderDemo/demo-preview-pages.html +2 -1
  95. package/BookReaderDemo/demo-simple.html +2 -1
  96. package/BookReaderDemo/demo-vendor-fullscreen.html +2 -1
  97. package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
  98. package/BookReaderDemo/immersion-1up.html +2 -1
  99. package/BookReaderDemo/immersion-mode.html +2 -1
  100. package/BookReaderDemo/toggle_controls.html +2 -1
  101. package/BookReaderDemo/view_mode.html +2 -1
  102. package/BookReaderDemo/viewmode-cycle.html +2 -3
  103. package/CHANGELOG.md +205 -0
  104. package/README.md +14 -1
  105. package/babel.config.js +18 -0
  106. package/codecov.yml +6 -0
  107. package/index.html +3 -0
  108. package/jsconfig.json +19 -0
  109. package/package.json +66 -56
  110. package/renovate.json +52 -0
  111. package/scripts/preversion.js +4 -1
  112. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  113. package/src/BookNavigator/assets/button-base.js +9 -2
  114. package/src/BookNavigator/assets/ia-logo.js +17 -0
  115. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  116. package/src/BookNavigator/assets/icon_close.js +1 -1
  117. package/src/BookNavigator/assets/icon_sort_asc.js +5 -0
  118. package/src/BookNavigator/assets/{icon_sort_ascending.js → icon_sort_desc.js} +2 -2
  119. package/src/BookNavigator/assets/icon_sort_neutral.js +5 -0
  120. package/src/BookNavigator/assets/icon_volumes.js +11 -0
  121. package/src/BookNavigator/book-navigator.js +583 -0
  122. package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
  123. package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
  124. package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
  125. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
  126. package/src/BookNavigator/bookmarks/bookmarks-provider.js +21 -8
  127. package/src/BookNavigator/bookmarks/ia-bookmarks.js +102 -66
  128. package/src/BookNavigator/delete-modal-actions.js +1 -1
  129. package/src/BookNavigator/downloads/downloads-provider.js +36 -21
  130. package/src/BookNavigator/downloads/downloads.js +41 -25
  131. package/src/BookNavigator/search/a-search-result.js +15 -13
  132. package/src/BookNavigator/search/search-provider.js +80 -28
  133. package/src/BookNavigator/search/search-results.js +10 -18
  134. package/src/BookNavigator/sharing.js +27 -0
  135. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -10
  136. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +3 -3
  137. package/src/BookNavigator/volumes/volumes-provider.js +93 -63
  138. package/src/BookNavigator/volumes/volumes.js +40 -46
  139. package/src/BookReader/BookModel.js +0 -29
  140. package/src/BookReader/DebugConsole.js +3 -3
  141. package/src/BookReader/DragScrollable.js +233 -0
  142. package/src/BookReader/Mode1Up.js +51 -351
  143. package/src/BookReader/Mode1UpLit.js +441 -0
  144. package/src/BookReader/Mode2Up.js +120 -105
  145. package/src/BookReader/ModeSmoothZoom.js +179 -0
  146. package/src/BookReader/ModeThumb.js +17 -11
  147. package/src/BookReader/Navbar/Navbar.js +10 -36
  148. package/src/BookReader/PageContainer.js +69 -6
  149. package/src/BookReader/ReduceSet.js +1 -1
  150. package/src/BookReader/Toolbar/Toolbar.js +10 -37
  151. package/src/BookReader/options.js +10 -0
  152. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  153. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  154. package/src/BookReader/utils.js +92 -13
  155. package/src/BookReader.js +431 -620
  156. package/src/assets/icons/close-circle-dark.svg +1 -0
  157. package/src/assets/icons/magnify-minus.svg +3 -7
  158. package/src/assets/icons/magnify-plus.svg +3 -7
  159. package/src/assets/icons/voice.svg +1 -0
  160. package/src/css/BookReader.scss +0 -12
  161. package/src/css/_BRComponent.scss +1 -1
  162. package/src/css/_BRmain.scss +19 -24
  163. package/src/css/_BRnav.scss +4 -26
  164. package/src/css/_BRpages.scss +35 -0
  165. package/src/css/_BRsearch.scss +25 -216
  166. package/src/css/_TextSelection.scss +14 -17
  167. package/src/css/_colorbox.scss +2 -2
  168. package/src/css/_controls.scss +17 -5
  169. package/src/css/_icons.scss +6 -0
  170. package/src/ia-bookreader/ia-bookreader.js +224 -0
  171. package/src/plugins/plugin.autoplay.js +4 -4
  172. package/src/plugins/plugin.chapters.js +28 -35
  173. package/src/plugins/plugin.mobile_nav.js +11 -10
  174. package/src/plugins/plugin.resume.js +3 -3
  175. package/src/plugins/plugin.text_selection.js +26 -39
  176. package/src/plugins/plugin.vendor-fullscreen.js +4 -4
  177. package/src/plugins/search/plugin.search.js +174 -116
  178. package/src/plugins/search/view.js +63 -179
  179. package/src/plugins/tts/AbstractTTSEngine.js +46 -37
  180. package/src/plugins/tts/FestivalTTSEngine.js +13 -14
  181. package/src/plugins/tts/PageChunk.js +15 -21
  182. package/src/plugins/tts/PageChunkIterator.js +8 -12
  183. package/src/plugins/tts/WebTTSEngine.js +66 -69
  184. package/src/plugins/tts/plugin.tts.js +92 -109
  185. package/src/plugins/tts/utils.js +0 -9
  186. package/src/plugins/url/UrlPlugin.js +184 -0
  187. package/src/plugins/{plugin.url.js → url/plugin.url.js} +28 -6
  188. package/src/util/manifestGenerator.js +0 -0
  189. package/tests/e2e/README.md +37 -0
  190. package/tests/e2e/autoplay.test.js +2 -2
  191. package/tests/e2e/base.test.js +7 -7
  192. package/tests/e2e/helpers/base.js +8 -3
  193. package/tests/e2e/helpers/debug.js +1 -1
  194. package/tests/e2e/helpers/desktopSearch.js +14 -13
  195. package/tests/e2e/helpers/mobileSearch.js +3 -3
  196. package/tests/e2e/helpers/params.js +17 -0
  197. package/tests/e2e/models/Navigation.js +13 -4
  198. package/tests/e2e/rightToLeft.test.js +4 -5
  199. package/tests/e2e/viewmode.test.js +38 -33
  200. package/tests/jest/BookNavigator/book-navigator.test.js +634 -0
  201. package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
  202. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
  203. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
  204. package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
  205. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
  206. package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
  207. package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
  208. package/tests/{karma/BookNavigator → jest/BookNavigator/search}/search-results.test.js +102 -58
  209. package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
  210. package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
  211. package/tests/jest/BookNavigator/volumes/volumes-provider.test.js +184 -0
  212. package/tests/jest/BookNavigator/volumes/volumes.test.js +97 -0
  213. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +34 -14
  214. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +176 -0
  215. package/tests/{BookReader → jest/BookReader}/DebugConsole.test.js +1 -1
  216. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  217. package/tests/jest/BookReader/Mode1UpLit.test.js +92 -0
  218. package/tests/{BookReader → jest/BookReader}/Mode2Up.test.js +36 -15
  219. package/tests/jest/BookReader/ModeSmoothZoom.test.js +149 -0
  220. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  221. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +7 -7
  222. package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +88 -6
  223. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  224. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
  225. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  226. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  227. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  228. package/tests/jest/BookReader/utils.test.js +186 -0
  229. package/tests/jest/BookReader.keyboard.test.js +190 -0
  230. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
  231. package/tests/{BookReader.test.js → jest/BookReader.test.js} +18 -37
  232. package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
  233. package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +4 -4
  234. package/tests/{plugins → jest/plugins}/plugin.chapters.test.js +10 -11
  235. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
  236. package/tests/{plugins → jest/plugins}/plugin.mobile_nav.test.js +5 -5
  237. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
  238. package/tests/{plugins → jest/plugins}/plugin.text_selection.test.js +39 -47
  239. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  240. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +63 -47
  241. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +35 -6
  242. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +9 -9
  243. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  244. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  245. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  246. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +1 -1
  247. package/tests/{plugins → jest/plugins}/tts/utils.test.js +3 -28
  248. package/tests/jest/plugins/url/UrlPlugin.test.js +190 -0
  249. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +33 -14
  250. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  251. package/tests/{util → jest/util}/docCookies.test.js +1 -1
  252. package/tests/{util → jest/util}/strings.test.js +1 -1
  253. package/tests/{utils.js → jest/utils.js} +38 -0
  254. package/webpack.config.js +11 -5
  255. package/.babelrc +0 -12
  256. package/.dependabot/config.yml +0 -6
  257. package/.testcaferc.json +0 -5
  258. package/BookReader/bookreader-component-bundle.js +0 -14275
  259. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  260. package/BookReader/bookreader-component-bundle.js.map +0 -1
  261. package/BookReader/icons/sort-ascending.svg +0 -1
  262. package/BookReader/icons/sort-descending.svg +0 -1
  263. package/BookReader/jquery-1.10.1.js +0 -108
  264. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  265. package/BookReader/plugins/plugin.menu_toggle.js +0 -369
  266. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  267. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  268. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  269. package/karma.conf.js +0 -23
  270. package/src/BookNavigator/BookModel.js +0 -14
  271. package/src/BookNavigator/BookNavigator.js +0 -448
  272. package/src/BookNavigator/assets/book-loader.js +0 -27
  273. package/src/BookNavigator/assets/icon_sort_descending.js +0 -5
  274. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  275. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  276. package/src/ItemNavigator/ItemNavigator.js +0 -373
  277. package/src/ItemNavigator/providers/sharing.js +0 -29
  278. package/src/assets/icons/sort-ascending.svg +0 -1
  279. package/src/assets/icons/sort-descending.svg +0 -1
  280. package/src/dragscrollable-br.js +0 -261
  281. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  282. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  283. package/tests/BookReader/Mode1Up.test.js +0 -164
  284. package/tests/BookReader/utils.test.js +0 -109
  285. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  286. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  287. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  288. package/tests/karma/BookNavigator/volumes.test.js +0 -101
  289. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
@@ -1,4 +1,4 @@
1
- import { html } from 'lit-element';
1
+ import { html } from 'lit';
2
2
  import '../delete-modal-actions.js';
3
3
  import './bookmark-button.js';
4
4
  import './ia-bookmarks.js';
@@ -10,17 +10,32 @@ import { IAIconBookmark } from '@internetarchive/icon-bookmark';
10
10
  customElements.define('icon-bookmark', IAIconBookmark);
11
11
 
12
12
  export default class BookmarksProvider {
13
- constructor(options, bookreader) {
14
- const boundOptions = Object.assign(this, options, {loginClicked: this.bookmarksLoginClicked});
13
+ constructor(options) {
14
+ const {
15
+ baseHost,
16
+ signedIn,
17
+ bookreader,
18
+ modal,
19
+ onProviderChange,
20
+ } = options;
21
+
22
+ const referrerStr = `referer=${encodeURIComponent(location.href)}`;
23
+ const loginUrl = `https://${baseHost}/account/login?${referrerStr}`;
24
+
15
25
  this.component = document.createElement('ia-bookmarks');
16
26
  this.component.bookreader = bookreader;
17
- this.component.options = boundOptions;
18
-
27
+ this.component.displayMode = signedIn ? 'bookmarks' : 'login';
28
+ this.component.modal = modal;
29
+ this.component.loginOptions = {
30
+ loginClicked: this.bookmarksLoginClicked,
31
+ loginUrl
32
+ };
19
33
  this.bindEvents();
20
34
 
21
35
  this.icon = html`<icon-bookmark state="hollow" style="--iconWidth: 16px; --iconHeight: 24px;"></icon-bookmark>`;
22
36
  this.label = 'Bookmarks';
23
37
  this.id = 'bookmarks';
38
+ this.onProviderChange = onProviderChange;
24
39
  this.component.setup();
25
40
  this.updateMenu(this.component.bookmarks.length);
26
41
  }
@@ -31,14 +46,12 @@ export default class BookmarksProvider {
31
46
 
32
47
  bindEvents() {
33
48
  this.component.addEventListener('bookmarksChanged', this.bookmarksChanged.bind(this));
34
- this.component.addEventListener('showItemNavigatorModal', this.showItemNavigatorModal);
35
- this.component.addEventListener('closeItemNavigatorModal', this.closeItemNavigatorModal);
36
49
  }
37
50
 
38
51
  bookmarksChanged({ detail }) {
39
52
  const bookmarksLength = Object.keys(detail.bookmarks).length;
40
53
  this.updateMenu(bookmarksLength);
41
- this.onBookmarksChanged(detail.bookmarks);
54
+ this.onProviderChange(detail.bookmarks, detail.showSidePanel);
42
55
  }
43
56
 
44
57
  bookmarksLoginClicked() {
@@ -1,5 +1,6 @@
1
- import { render, nothing } from 'lit-html';
2
- import { LitElement, html, css } from 'lit-element';
1
+ import { LitElement, html, css, render } from 'lit';
2
+ // eslint-disable-next-line no-unused-vars
3
+ import { ModalConfig, ModalManager } from '@internetarchive/modal-manager';
3
4
  import buttonStyles from '../assets/button-base.js';
4
5
  import './bookmarks-loginCTA.js';
5
6
 
@@ -57,9 +58,11 @@ class IABookmarks extends LitElement {
57
58
  activeBookmarkID: { type: String },
58
59
  bookmarks: { type: Array },
59
60
  bookreader: { type: Object },
60
- options: { type: Object },
61
61
  displayMode: { type: String },
62
62
  editedBookmark: { type: Object },
63
+ deleteModalConfig: { type: Object},
64
+ modal: { attribute: false },
65
+ loginOptions: { type: Object, attribute: false }
63
66
  };
64
67
  }
65
68
 
@@ -92,7 +95,12 @@ class IABookmarks extends LitElement {
92
95
  this.bookmarks = [];
93
96
  this.bookreader = {};
94
97
  this.editedBookmark = {};
95
- this.options = {};
98
+ /** @type {ModalManager} */
99
+ this.modal = undefined;
100
+ this.loginOptions = {
101
+ loginClicked: () => {},
102
+ loginUrl: '',
103
+ };
96
104
  /**
97
105
  * Toggles display to either bookmarks or login cta
98
106
  * @param {('bookmarks'|'login')} displayMode
@@ -113,21 +121,45 @@ class IABookmarks extends LitElement {
113
121
  // eslint-disable-next-line
114
122
  this.defaultColor = this.bookmarkColors[0];
115
123
  this.api = api;
124
+ this.deleteModalConfig = new ModalConfig({
125
+ title: 'Delete Bookmark',
126
+ headline: 'This bookmark contains a note. Deleting it will permanently delete the note. Are you sure?',
127
+ headerColor: '#194880',
128
+ });
116
129
  }
117
130
 
118
- updated() {
131
+ updated(changed) {
132
+ if (changed.has('displayMode')) {
133
+ this.updateDisplay();
134
+ }
135
+
119
136
  this.emitBookmarksChanged();
120
137
  }
121
138
 
122
139
  setup() {
123
140
  this.api.identifier = this.bookreader.bookId;
124
- this.fetchBookmarks()
125
- .then(() => this.initializeBookmarks())
126
- .catch((err) => this.displayMode = 'login');
141
+ if (this.displayMode === 'login') {
142
+ return;
143
+ }
144
+ this.fetchUserBookmarks();
145
+ this.setBREventListeners();
127
146
  }
128
147
 
129
- initializeBookmarks() {
130
- this.displayMode = 'bookmarks';
148
+ updateDisplay() {
149
+ if (this.displayMode === 'bookmarks') {
150
+ this.fetchUserBookmarks();
151
+ }
152
+ }
153
+
154
+ async fetchUserBookmarks() {
155
+ if (!this.api.identifier) {
156
+ return;
157
+ }
158
+ await this.fetchBookmarks();
159
+ this.initializeBookmarks();
160
+ }
161
+
162
+ setBREventListeners() {
131
163
  ['3PageViewSelected'].forEach((event) => {
132
164
  window.addEventListener(`BookReader:${event}`, (e) => {
133
165
  setTimeout(() => {
@@ -147,12 +179,12 @@ class IABookmarks extends LitElement {
147
179
  });
148
180
  ['zoomOut', 'zoomIn', 'resize'].forEach((event) => {
149
181
  window.addEventListener(`BookReader:${event}`, () => {
150
- if (this.bookreader.mode === this.bookreader.constModeThumb) {
151
- this.renderBookmarkButtons();
152
- }
182
+ this.renderBookmarkButtons();
153
183
  });
154
184
  });
185
+ }
155
186
 
187
+ initializeBookmarks() {
156
188
  this.renderBookmarkButtons();
157
189
  this.markActiveBookmark(true);
158
190
  this.emitBookmarksChanged();
@@ -181,8 +213,8 @@ class IABookmarks extends LitElement {
181
213
  color: this.getBookmarkColor(color) ? color : this.defaultColor.id,
182
214
  };
183
215
 
184
- const page = IABookmarks.formatPage(this.bookreader.getPageNum(leafNum));
185
- const thumbnail = this.bookreader.getPageURI(`${leafNum}`.replace(/\D/g, ''), 32); // Request thumbnail 1/32 the size of original image
216
+ const page = IABookmarks.formatPage(this.bookreader.book.getPageNum(leafNum));
217
+ const thumbnail = this.bookreader.book.getPageURI(`${leafNum}`.replace(/\D/g, ''), 32); // Request thumbnail 1/32 the size of original image
186
218
  const bookmark = {
187
219
  ...nomalizedParams,
188
220
  id: leafNum,
@@ -194,27 +226,35 @@ class IABookmarks extends LitElement {
194
226
  return bookmark;
195
227
  }
196
228
 
197
- fetchBookmarks() {
198
- return this.api.getAll().then((res) => res.json()).then(({
229
+ async fetchBookmarks() {
230
+ const resText = await this.api.getAll().then(r=> r.text());
231
+ let parsedResponse;
232
+ try {
233
+ parsedResponse = JSON.parse(resText);
234
+ } catch (e) {
235
+ parsedResponse = {error : e.message};
236
+ }
237
+
238
+ const {
199
239
  success,
200
240
  error = 'Something happened while fetching bookmarks.',
201
241
  value: bkmrks = [],
202
- }) => {
203
- if (!success) {
204
- throw new Error(`Failed to load bookmarks: ${error}`);
205
- }
242
+ } = parsedResponse;
206
243
 
207
- const bookmarks = {};
208
- Object.keys(bkmrks).forEach((leafNum) => {
209
- const bookmark = bkmrks[leafNum];
210
- const formattedLeafNum = parseInt(leafNum, 10);
211
- const formattedBookmark = this.formatBookmark({ ...bookmark, leafNum: formattedLeafNum });
212
- bookmarks[leafNum] = formattedBookmark;
213
- });
244
+ if (!success) {
245
+ console?.warn('Error fetching bookmarks', error);
246
+ }
214
247
 
215
- this.bookmarks = bookmarks;
216
- return bookmarks;
248
+ const bookmarks = {};
249
+ Object.keys(bkmrks).forEach((leafNum) => {
250
+ const bookmark = bkmrks[leafNum];
251
+ const formattedLeafNum = parseInt(leafNum, 10);
252
+ const formattedBookmark = this.formatBookmark({ ...bookmark, leafNum: formattedLeafNum });
253
+ bookmarks[leafNum] = formattedBookmark;
217
254
  });
255
+
256
+ this.bookmarks = bookmarks;
257
+ return bookmarks;
218
258
  }
219
259
 
220
260
  emitBookmarksChanged() {
@@ -250,12 +290,14 @@ class IABookmarks extends LitElement {
250
290
 
251
291
  pages.forEach((pageEl) => {
252
292
  const existingButton = pageEl.querySelector('.bookmark-button');
253
- if (existingButton) { existingButton.remove(); }
293
+ if (existingButton) {
294
+ existingButton.remove();
295
+ }
254
296
  const pageID = +pageEl.classList.value.match(/pagediv\d+/)[0].replace(/\D/g, '');
255
297
  const pageBookmark = this.getBookmark(pageID);
256
298
  const bookmarkState = pageBookmark ? 'filled' : 'hollow';
257
299
  // eslint-disable-next-line
258
- const pageData = this.bookreader._models.book.getPage(pageID);
300
+ const pageData = this.bookreader.book.getPage(pageID);
259
301
  const { isViewable } = pageData;
260
302
 
261
303
  if (!isViewable) { return; }
@@ -375,7 +417,7 @@ class IABookmarks extends LitElement {
375
417
 
376
418
  bookmarkSelected({ detail }) {
377
419
  const { leafNum } = detail.bookmark;
378
- this.bookreader.jumpToPage(`${this.bookreader.getPageNum(`${leafNum}`.replace(/\D/g, ''))}`);
420
+ this.bookreader.jumpToPage(`${this.bookreader.book.getPageNum(`${leafNum}`.replace(/\D/g, ''))}`);
379
421
  this.activeBookmarkID = leafNum;
380
422
  }
381
423
 
@@ -390,33 +432,26 @@ class IABookmarks extends LitElement {
390
432
  confirmDeletion(pageID) {
391
433
  const existingBookmark = this.getBookmark(pageID);
392
434
  if (existingBookmark.note) {
393
- this.emitShowModal(pageID);
435
+ this.displayDeletionModal(pageID);
394
436
  return;
395
437
  }
396
438
  this.deleteBookmark({ detail: { id: `${pageID}` } });
397
439
  }
398
440
 
399
- emitShowModal(pageID) {
400
- this.dispatchEvent(new CustomEvent('showItemNavigatorModal', {
401
- bubbles: true,
402
- composed: true,
403
- detail: {
404
- customModalContent: html`
405
- <delete-modal-actions
406
- .deleteAction=${() => this.deleteBookmark({ detail: { id: `${pageID}` } })}
407
- .cancelAction=${() => this.emitCloseModal()}
408
- .pageID=${pageID}
409
- ></delete-modal-actions>
410
- `,
411
- },
412
- }));
413
- }
441
+ displayDeletionModal(pageID) {
442
+ const customModalContent = html`
443
+ <delete-modal-actions
444
+ .deleteAction=${() => this.deleteBookmark({ detail: { id: `${pageID}` } })}
445
+ .cancelAction=${() => this.modal.closeModal()}
446
+ .pageID=${pageID}
447
+ ></delete-modal-actions>
448
+ `;
414
449
 
415
- emitCloseModal() {
416
- this.dispatchEvent(new CustomEvent('closeItemNavigatorModal', {
417
- bubbles: true,
418
- composed: true,
419
- }));
450
+
451
+ this.modal.showModal({
452
+ config: this.deleteModalConfig,
453
+ customModalContent,
454
+ });
420
455
  }
421
456
 
422
457
  deleteBookmark({ detail }) {
@@ -427,18 +462,10 @@ class IABookmarks extends LitElement {
427
462
 
428
463
  this.api.delete(detail.id);
429
464
  this.editedBookmark = {};
430
- this.emitCloseModal();
465
+ this.modal.closeModal();
431
466
  this.renderBookmarkButtons();
432
467
  }
433
468
 
434
- /**
435
- * call `loginClicked` callback
436
- */
437
- loginClick() {
438
- const { loginClicked = () => {} } = this.options;
439
- loginClicked();
440
- }
441
-
442
469
  /**
443
470
  * Tells us if we should allow user to add bookmark via menu panel
444
471
  * returns { Boolean }
@@ -460,6 +487,7 @@ class IABookmarks extends LitElement {
460
487
  return html`
461
488
  <button
462
489
  class="ia-button primary"
490
+ tabindex="-1"
463
491
  ?disabled=${this.shouldEnableAddBookmarkButton}
464
492
  @click=${this.addBookmark}>
465
493
  Add bookmark
@@ -483,15 +511,23 @@ class IABookmarks extends LitElement {
483
511
  `;
484
512
  }
485
513
 
514
+ get bookmarkHelperMessage() {
515
+ return html`<p>Please use 1up or 2up view modes to add bookmark.</p>`;
516
+ }
517
+
486
518
  render() {
487
- const { loginUrl } = this.options;
488
519
  const bookmarks = html`
489
520
  ${this.bookmarksList}
490
- ${this.allowAddingBookmark ? this.addBookmarkButton : nothing}
521
+ ${this.allowAddingBookmark ? this.addBookmarkButton : this.bookmarkHelperMessage}
491
522
  `;
492
523
  return html`
493
524
  <section class="bookmarks">
494
- ${this.displayMode === 'login' ? html`<bookmarks-login @click=${this.loginClick} .url=${loginUrl}></bookmarks-login>` : bookmarks}
525
+ ${ this.displayMode === 'login'
526
+ ? html`<bookmarks-login
527
+ @click=${() => this.loginOptions.loginClicked()}
528
+ .url=${this.loginOptions.loginUrl}></bookmarks-login>`
529
+ : bookmarks
530
+ }
495
531
  </section>
496
532
  `;
497
533
  }
@@ -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 DeleteModalActions extends LitElement {
4
4
  static get styles() {
@@ -1,42 +1,56 @@
1
- import { html } from 'lit-element';
1
+ import { html } from 'lit';
2
+ import '@internetarchive/icon-dl/icon-dl';
3
+ import './downloads';
2
4
 
3
- /* register subpanel */
4
- import { IABookDownloads } from './downloads';
5
- customElements.define('ia-book-downloads', IABookDownloads);
6
-
7
- let downloads = [];
8
5
  const menuBase = {
9
6
  pdf: {
10
7
  type: 'Encrypted Adobe PDF',
11
8
  url: '#',
12
9
  note: 'PDF files contain high quality images of pages.',
13
10
  },
11
+ lcppdf: {
12
+ type: 'Get LCP PDF',
13
+ url: '#',
14
+ note: 'PDF files contain high quality images of pages.',
15
+ },
16
+ lcpepub: {
17
+ type: 'Get LCP ePub',
18
+ url: '#',
19
+ note: 'ePub files are smaller in size, but may contain errors.',
20
+ },
14
21
  epub: {
15
22
  type: 'Encrypted Adobe ePub',
16
23
  url: '#',
17
24
  note: 'ePub files are smaller in size, but may contain errors.',
18
- }
25
+ },
26
+ };
27
+
28
+ const publicMenuBase = {
29
+ pdf: "PDF",
30
+ epub: "ePub",
31
+ lcppdf: "LCP PDF",
32
+ lcpepub: "LCP ePub",
19
33
  };
20
34
 
21
- export default class {
22
- constructor() {
23
- this.icon = html`<ia-icon icon="download" style="width: var(--iconWidth); height: var(--iconHeight);"></ia-icon>`;
35
+ export default class DownloadsProvider {
36
+
37
+ constructor({ bookreader }) {
38
+ this.icon = html`<ia-icon-dl style="width: var(--iconWidth); height: var(--iconHeight);"></ia-icon-dl>`;
24
39
  this.label = 'Downloadable files';
25
40
  this.menuDetails = '';
41
+ this.downloads = [];
26
42
  this.id = 'downloads';
27
43
  this.component = '';
28
-
29
- this.computeAvailableTypes = this.computeAvailableTypes.bind(this);
30
- this.update = this.update.bind(this);
44
+ this.isBookProtected = bookreader?.options?.isProtected || false;
31
45
  }
32
46
 
33
-
34
47
  update(downloadTypes) {
35
48
  this.computeAvailableTypes(downloadTypes);
36
49
  this.component = this.menu;
50
+ this.component.isBookProtected = this.isBookProtected;
37
51
 
38
- const ending = downloads.length === 1 ? '' : 's';
39
- this.menuDetails = `(${downloads.length} format${ending})`;
52
+ const ending = this.downloads.length === 1 ? '' : 's';
53
+ this.menuDetails = `(${this.downloads.length} format${ending})`;
40
54
  }
41
55
 
42
56
  /**
@@ -45,22 +59,23 @@ export default class {
45
59
  * @param availableTypes
46
60
  */
47
61
  computeAvailableTypes(availableTypes = []) {
48
- const menuData = availableTypes.reduce((found, incoming = [], index) => {
62
+ const menuData = availableTypes.reduce((found, incoming = []) => {
49
63
  const [ type = '', link = '' ] = incoming;
50
64
  const formattedType = type.toLowerCase();
51
65
  const downloadOption = menuBase[formattedType] || null;
66
+
52
67
  if (downloadOption) {
53
- const menuInfo = Object.assign({}, downloadOption, { url: link });
68
+ const menuButtonText = this.isBookProtected ? menuBase[formattedType].type : publicMenuBase[formattedType];
69
+ const menuInfo = Object.assign({}, downloadOption, { url: link, type: menuButtonText});
54
70
  found.push(menuInfo);
55
71
  }
56
72
  return found;
57
73
  }, []);
58
74
 
59
- downloads = menuData;
75
+ this.downloads = menuData;
60
76
  }
61
77
 
62
-
63
78
  get menu () {
64
- return html`<ia-book-downloads .downloads=${downloads}></ia-book-downloads>`;
79
+ return html`<ia-book-downloads .downloads=${this.downloads}></ia-book-downloads>`;
65
80
  }
66
81
  }
@@ -1,11 +1,12 @@
1
- import { css, html, LitElement } from 'lit-element';
2
- import { nothing } from 'lit-html';
1
+ import { css, html, LitElement, nothing } from 'lit';
2
+ import buttonStyles from '../assets/button-base.js';
3
3
  export class IABookDownloads extends LitElement {
4
4
  static get properties() {
5
5
  return {
6
6
  downloads: { type: Array },
7
7
  expiration: { type: Number },
8
8
  renderHeader: { type: Boolean },
9
+ isBookProtected: { type: Boolean },
9
10
  };
10
11
  }
11
12
 
@@ -14,6 +15,7 @@ export class IABookDownloads extends LitElement {
14
15
  this.downloads = [];
15
16
  this.expiration = 0;
16
17
  this.renderHeader = false;
18
+ this.isBookProtected = false;
17
19
  }
18
20
 
19
21
  get formatsCount() {
@@ -31,13 +33,23 @@ export class IABookDownloads extends LitElement {
31
33
  return this.downloads.map(option => (
32
34
  html`
33
35
  <li>
34
- <a class="button" href="${option.url}">Get ${option.type}</a>
36
+ <a class="ia-button link primary" href="${option.url}">Get ${option.type}</a>
35
37
  ${option.note ? html`<p>${option.note}</p>` : html``}
36
38
  </li>
37
39
  `
38
40
  ));
39
41
  }
40
42
 
43
+ /**
44
+ * checks if downloads list contains an LCP option
45
+ * @return {boolean}
46
+ */
47
+ get hasLCPOption() {
48
+ const regex = /^(LCP)/g;
49
+ const lcpAvailable = this.downloads.some(option => option.type?.match(regex));
50
+ return lcpAvailable;
51
+ }
52
+
41
53
  get header() {
42
54
  if (!this.renderHeader) {
43
55
  return nothing;
@@ -50,18 +62,38 @@ export class IABookDownloads extends LitElement {
50
62
  `;
51
63
  }
52
64
 
65
+ get accessProtectedBook() {
66
+ return html`
67
+ <p>To access downloaded books, you need Adobe-compliant software on your device. The Internet Archive will administer this loan, but Adobe may also collect some information.</p>
68
+ <a class="ia-button external primary" href="https://www.adobe.com/solutions/ebook/digital-editions/download.html" rel="noopener noreferrer" target="_blank">Install Adobe Digital Editions</a>
69
+ `;
70
+ }
71
+
72
+ get installSimplyEAldikoThoriumMsg() {
73
+ return html`
74
+ <p>For LCP downloads, make sure you have SimplyE or Aldiko Next installed on mobile or Thorium on desktop.</p>
75
+ <ul>
76
+ <li><a href="https://librarysimplified.org/simplye/" rel="noopener noreferrer nofollow" target="_blank">Install SimplyE</a></li>
77
+ <li><a href="https://www.demarque.com/en-aldiko" rel="noopener noreferrer nofollow" target="_blank">Install Aldiko</a></li>
78
+ <li><a href="https://www.edrlab.org/software/thorium-reader/" rel="noopener noreferrer nofollow" target="_blank">Install Thorium</a></li>
79
+ </ul>
80
+ `;
81
+ }
82
+
53
83
  render() {
54
84
  return html`
55
85
  ${this.header}
56
86
  ${this.loanExpiryMessage}
57
87
  <ul>${this.renderDownloadOptions()}</ul>
58
- <p>To access downloaded books, you need Adobe-compliant software on your device. The Internet Archive will administer this loan, but Adobe may also collect some information.</p>
59
- <a class="button external" href="https://www.adobe.com/solutions/ebook/digital-editions/download.html" rel="noopener noreferrer" target="_blank">Install Adobe Digital Editions</a>
88
+ ${this.hasLCPOption
89
+ ? this.installSimplyEAldikoThoriumMsg
90
+ : (this.isBookProtected ? this.accessProtectedBook : nothing)
91
+ }
60
92
  `;
61
93
  }
62
94
 
63
95
  static get styles() {
64
- return css`
96
+ const mainCss = css`
65
97
  :host {
66
98
  display: block;
67
99
  height: 100%;
@@ -79,24 +111,6 @@ export class IABookDownloads extends LitElement {
79
111
  justify-self: end;
80
112
  }
81
113
 
82
- .button {
83
- color: var(--primaryTextColor);
84
- background: var(--primaryCTAFill);
85
- border: 1px solid var(--primaryCTABorder);
86
- display: inline-block;
87
- padding: .6rem 1rem;
88
- font-size: 1.4rem;
89
- text-decoration: none;
90
- text-shadow: 1px 1px #484848;
91
- border-radius: 4px;
92
- }
93
-
94
- .button.external {
95
- background: var(--secondaryCTAFill, transparent);
96
- border: 1px solid var(--secondaryCTABorder, #999);
97
- text-shadow: none;
98
- }
99
-
100
114
  header {
101
115
  display: flex;
102
116
  align-items: center;
@@ -109,7 +123,6 @@ export class IABookDownloads extends LitElement {
109
123
  font-weight: bold;
110
124
  font-style: italic;
111
125
  }
112
-
113
126
  header div {
114
127
  display: flex;
115
128
  align-items: baseline;
@@ -142,5 +155,8 @@ export class IABookDownloads extends LitElement {
142
155
  line-height: 140%;
143
156
  }
144
157
  `;
158
+
159
+ return [buttonStyles, mainCss];
145
160
  }
146
161
  }
162
+ customElements.define('ia-book-downloads', IABookDownloads);
@@ -1,6 +1,7 @@
1
- import { nothing } from 'lit-html';
2
- import { html, LitElement } from 'lit-element';
3
- import { unsafeHTML } from 'lit-html/directives/unsafe-html';
1
+ import { escapeHTML } from '../../BookReader/utils.js';
2
+ import { html, LitElement, nothing } from 'lit';
3
+ import { unsafeHTML } from 'lit/directives/unsafe-html.js';
4
+ /** @typedef {import('@/src/plugins/search/plugin.search.js').SearchInsideMatch} SearchInsideMatch */
4
5
 
5
6
  export class BookSearchResult extends LitElement {
6
7
  static get properties() {
@@ -12,17 +13,21 @@ export class BookSearchResult extends LitElement {
12
13
  constructor() {
13
14
  super();
14
15
 
15
- this.matchRegex = new RegExp('{{{(.+?)}}}', 'g');
16
+ this.matchRegex = new RegExp('{{{([^]+?)}}}', 'g'); // [^] matches any character, including line breaks
16
17
  }
17
18
 
18
19
  createRenderRoot() {
19
20
  return this;
20
21
  }
21
22
 
23
+ /**
24
+ * Converts the search hit to a `<p>` template containing the full search result with all of
25
+ * its `{{{triple-brace-delimited}}}` matches replaced by `<mark>HTML mark tags</mark>`.
26
+ */
22
27
  highlightedHit(hit) {
23
- return html`
24
- <p>${unsafeHTML(hit.replace(this.matchRegex, '<mark>$1</mark>'))}</p>
25
- `;
28
+ return html`<p>
29
+ ${unsafeHTML(escapeHTML(hit).replace(this.matchRegex, '<mark>$1</mark>'))}
30
+ </p>`;
26
31
  }
27
32
 
28
33
  resultSelected() {
@@ -36,17 +41,14 @@ export class BookSearchResult extends LitElement {
36
41
  }
37
42
 
38
43
  render() {
39
- const { match } = this;
40
- const { par = [] } = match;
41
- const [resultDetails = {}] = par;
42
- const pageNumber = Number.isInteger(resultDetails.page)
43
- ? html`<p class="page-num">Page -${resultDetails.page}-</p>` : nothing;
44
+ /** @type {SearchInsideMatch} */
45
+ const match = this.match;
44
46
  const coverImage = html`<img src="${match.cover}" />`;
45
47
  return html`
46
48
  <li @click=${this.resultSelected}>
47
49
  ${match.cover ? coverImage : nothing}
48
50
  <h4>${match.title || nothing}</h4>
49
- ${pageNumber}
51
+ <p class="page-num">Page ${match.displayPageNumber}</p>
50
52
  ${this.highlightedHit(match.text)}
51
53
  </li>
52
54
  `;