@internetarchive/bookreader 5.0.0-26 → 5.0.0-29

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 (236) hide show
  1. package/.husky/_/husky.sh +30 -0
  2. package/BookReader/BookReader.css +1 -1
  3. package/BookReader/BookReader.js +1 -1
  4. package/BookReader/BookReader.js.map +1 -1
  5. package/BookReader/bookreader-component-bundle.js +570 -542
  6. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +23 -0
  7. package/BookReader/bookreader-component-bundle.js.map +1 -1
  8. package/BookReader/plugins/plugin.search.js +1 -1
  9. package/BookReader/plugins/plugin.search.js.map +1 -1
  10. package/BookReader/plugins/plugin.tts.js.map +1 -1
  11. package/BookReader/plugins/plugin.url.js +1 -1
  12. package/BookReader/plugins/plugin.url.js.map +1 -1
  13. package/BookReaderDemo/BookReaderDemo.css +14 -1
  14. package/BookReaderDemo/IADemoBr.js +104 -0
  15. package/BookReaderDemo/demo-internetarchive.html +65 -98
  16. package/CHANGELOG.md +10 -0
  17. package/package.json +9 -6
  18. package/src/BookNavigator/assets/ia-logo.js +17 -0
  19. package/src/BookNavigator/book-navigator.js +521 -0
  20. package/src/BookNavigator/bookmarks/bookmark-button.js +2 -1
  21. package/src/BookNavigator/bookmarks/bookmarks-provider.js +20 -8
  22. package/src/BookNavigator/bookmarks/ia-bookmarks.js +84 -51
  23. package/src/BookNavigator/downloads/downloads-provider.js +5 -9
  24. package/src/BookNavigator/downloads/downloads.js +1 -0
  25. package/src/BookNavigator/search/search-provider.js +15 -8
  26. package/src/BookNavigator/sharing.js +27 -0
  27. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +9 -8
  28. package/src/BookNavigator/volumes/volumes-provider.js +44 -13
  29. package/src/BookNavigator/volumes/volumes.js +14 -3
  30. package/src/BookReader/options.js +6 -0
  31. package/src/BookReader.js +20 -8
  32. package/src/BookReaderComponent/BookReaderComponent.js +53 -32
  33. package/src/css/_BRComponent.scss +1 -1
  34. package/src/plugins/search/plugin.search.js +10 -9
  35. package/src/plugins/tts/FestivalTTSEngine.js +1 -1
  36. package/src/plugins/url/UrlPlugin.js +184 -0
  37. package/src/plugins/url/plugin.url.js +220 -0
  38. package/{src → stat}/BookNavigator/BookModel.js +0 -0
  39. package/{src → stat}/BookNavigator/BookNavigator.js +109 -102
  40. package/stat/BookNavigator/assets/bookmark-colors.js +15 -0
  41. package/stat/BookNavigator/assets/button-base.js +61 -0
  42. package/stat/BookNavigator/assets/ia-logo.js +17 -0
  43. package/stat/BookNavigator/assets/icon_checkmark.js +6 -0
  44. package/stat/BookNavigator/assets/icon_close.js +3 -0
  45. package/stat/BookNavigator/assets/icon_sort_asc.js +5 -0
  46. package/stat/BookNavigator/assets/icon_sort_desc.js +5 -0
  47. package/stat/BookNavigator/assets/icon_sort_neutral.js +5 -0
  48. package/stat/BookNavigator/assets/icon_volumes.js +11 -0
  49. package/stat/BookNavigator/bookmarks/bookmark-button.js +64 -0
  50. package/stat/BookNavigator/bookmarks/bookmark-edit.js +215 -0
  51. package/stat/BookNavigator/bookmarks/bookmarks-list.js +285 -0
  52. package/stat/BookNavigator/bookmarks/bookmarks-loginCTA.js +28 -0
  53. package/stat/BookNavigator/bookmarks/bookmarks-provider.js +56 -0
  54. package/stat/BookNavigator/bookmarks/ia-bookmarks.js +523 -0
  55. package/{src → stat}/BookNavigator/br-fullscreen-mgr.js +1 -2
  56. package/stat/BookNavigator/delete-modal-actions.js +49 -0
  57. package/stat/BookNavigator/downloads/downloads-provider.js +72 -0
  58. package/stat/BookNavigator/downloads/downloads.js +139 -0
  59. package/stat/BookNavigator/provider-config.js +0 -0
  60. package/stat/BookNavigator/search/a-search-result.js +55 -0
  61. package/stat/BookNavigator/search/search-provider.js +180 -0
  62. package/stat/BookNavigator/search/search-results.js +360 -0
  63. package/{src/ItemNavigator/providers → stat/BookNavigator}/sharing.js +3 -5
  64. package/stat/BookNavigator/visual-adjustments/visual-adjustments-provider.js +94 -0
  65. package/stat/BookNavigator/visual-adjustments/visual-adjustments.js +280 -0
  66. package/stat/BookNavigator/volumes/volumes-provider.js +83 -0
  67. package/stat/BookNavigator/volumes/volumes.js +178 -0
  68. package/stat/BookReader/BookModel.js +518 -0
  69. package/stat/BookReader/DebugConsole.js +54 -0
  70. package/stat/BookReader/DragScrollable.js +233 -0
  71. package/stat/BookReader/ImageCache.js +116 -0
  72. package/stat/BookReader/Mode1Up.js +102 -0
  73. package/stat/BookReader/Mode1UpLit.js +434 -0
  74. package/stat/BookReader/Mode2Up.js +1372 -0
  75. package/stat/BookReader/ModeSmoothZoom.js +177 -0
  76. package/stat/BookReader/ModeThumb.js +344 -0
  77. package/stat/BookReader/Navbar/Navbar.js +310 -0
  78. package/stat/BookReader/PageContainer.js +120 -0
  79. package/stat/BookReader/ReduceSet.js +26 -0
  80. package/stat/BookReader/Toolbar/Toolbar.js +384 -0
  81. package/stat/BookReader/events.js +20 -0
  82. package/stat/BookReader/options.js +324 -0
  83. package/stat/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  84. package/stat/BookReader/utils/classes.js +36 -0
  85. package/stat/BookReader/utils.js +240 -0
  86. package/stat/BookReader.js +2550 -0
  87. package/stat/BookReaderComponent/BookReaderComponent.js +117 -0
  88. package/stat/assets/icons/1up.svg +12 -0
  89. package/stat/assets/icons/2up.svg +15 -0
  90. package/stat/assets/icons/advance.svg +26 -0
  91. package/stat/assets/icons/chevron-right.svg +1 -0
  92. package/stat/assets/icons/close-circle-dark.svg +1 -0
  93. package/stat/assets/icons/close-circle.svg +1 -0
  94. package/stat/assets/icons/fullscreen.svg +17 -0
  95. package/stat/assets/icons/fullscreen_exit.svg +17 -0
  96. package/stat/assets/icons/hamburger.svg +15 -0
  97. package/stat/assets/icons/left-arrow.svg +12 -0
  98. package/stat/assets/icons/magnify-minus.svg +16 -0
  99. package/stat/assets/icons/magnify-plus.svg +17 -0
  100. package/stat/assets/icons/magnify.svg +15 -0
  101. package/stat/assets/icons/pause.svg +23 -0
  102. package/stat/assets/icons/play.svg +22 -0
  103. package/stat/assets/icons/playback-speed.svg +34 -0
  104. package/stat/assets/icons/read-aloud.svg +22 -0
  105. package/stat/assets/icons/review.svg +22 -0
  106. package/stat/assets/icons/thumbnails.svg +17 -0
  107. package/stat/assets/icons/voice.svg +1 -0
  108. package/stat/assets/icons/volume-full.svg +22 -0
  109. package/stat/assets/images/BRicons.png +0 -0
  110. package/stat/assets/images/BRicons.svg +94 -0
  111. package/stat/assets/images/BRicons_ia.png +0 -0
  112. package/stat/assets/images/back_pages.png +0 -0
  113. package/stat/assets/images/book_bottom_icon.png +0 -0
  114. package/stat/assets/images/book_down_icon.png +0 -0
  115. package/stat/assets/images/book_left_icon.png +0 -0
  116. package/stat/assets/images/book_leftmost_icon.png +0 -0
  117. package/stat/assets/images/book_right_icon.png +0 -0
  118. package/stat/assets/images/book_rightmost_icon.png +0 -0
  119. package/stat/assets/images/book_top_icon.png +0 -0
  120. package/stat/assets/images/book_up_icon.png +0 -0
  121. package/stat/assets/images/books_graphic.svg +177 -0
  122. package/stat/assets/images/booksplit.png +0 -0
  123. package/stat/assets/images/control_pause_icon.png +0 -0
  124. package/stat/assets/images/control_play_icon.png +0 -0
  125. package/stat/assets/images/embed_icon.png +0 -0
  126. package/stat/assets/images/icon-home-ia.png +0 -0
  127. package/stat/assets/images/icon_OL-logo-xs.png +0 -0
  128. package/stat/assets/images/icon_alert-xs.png +0 -0
  129. package/stat/assets/images/icon_book.svg +12 -0
  130. package/stat/assets/images/icon_bookmark.svg +12 -0
  131. package/stat/assets/images/icon_close-pop.png +0 -0
  132. package/stat/assets/images/icon_download.png +0 -0
  133. package/stat/assets/images/icon_gear.svg +14 -0
  134. package/stat/assets/images/icon_hamburger.svg +20 -0
  135. package/stat/assets/images/icon_home.png +0 -0
  136. package/stat/assets/images/icon_home.svg +21 -0
  137. package/stat/assets/images/icon_home_ia.png +0 -0
  138. package/stat/assets/images/icon_indicator.png +0 -0
  139. package/stat/assets/images/icon_info.svg +11 -0
  140. package/stat/assets/images/icon_one_page.svg +8 -0
  141. package/stat/assets/images/icon_pause.svg +1 -0
  142. package/stat/assets/images/icon_play.svg +1 -0
  143. package/stat/assets/images/icon_playback-rate.svg +15 -0
  144. package/stat/assets/images/icon_return.png +0 -0
  145. package/stat/assets/images/icon_search_button.svg +8 -0
  146. package/stat/assets/images/icon_share.svg +9 -0
  147. package/stat/assets/images/icon_skip-ahead.svg +6 -0
  148. package/stat/assets/images/icon_skip-back.svg +13 -0
  149. package/stat/assets/images/icon_speaker.svg +18 -0
  150. package/stat/assets/images/icon_speaker_open.svg +10 -0
  151. package/stat/assets/images/icon_thumbnails.svg +12 -0
  152. package/stat/assets/images/icon_toc.svg +5 -0
  153. package/stat/assets/images/icon_two_pages.svg +9 -0
  154. package/stat/assets/images/icon_zoomer.png +0 -0
  155. package/stat/assets/images/loading.gif +0 -0
  156. package/stat/assets/images/logo_icon.png +0 -0
  157. package/stat/assets/images/marker_chap-off.png +0 -0
  158. package/stat/assets/images/marker_chap-off.svg +11 -0
  159. package/stat/assets/images/marker_chap-off_ia.png +0 -0
  160. package/stat/assets/images/marker_chap-on.png +0 -0
  161. package/stat/assets/images/marker_chap-on.svg +11 -0
  162. package/stat/assets/images/marker_srch-on.svg +11 -0
  163. package/stat/assets/images/marker_srchchap-off.png +0 -0
  164. package/stat/assets/images/marker_srchchap-on.png +0 -0
  165. package/stat/assets/images/nav_control-dn.png +0 -0
  166. package/stat/assets/images/nav_control-dn_ia.png +0 -0
  167. package/stat/assets/images/nav_control-up.png +0 -0
  168. package/stat/assets/images/nav_control-up_ia.png +0 -0
  169. package/stat/assets/images/nav_control.png +0 -0
  170. package/stat/assets/images/one_page_mode_icon.png +0 -0
  171. package/stat/assets/images/paper-badge.png +0 -0
  172. package/stat/assets/images/print_icon.png +0 -0
  173. package/stat/assets/images/progressbar.gif +0 -0
  174. package/stat/assets/images/right_edges.png +0 -0
  175. package/stat/assets/images/slider.png +0 -0
  176. package/stat/assets/images/slider_ia.png +0 -0
  177. package/stat/assets/images/thumbnail_mode_icon.png +0 -0
  178. package/stat/assets/images/transparent.png +0 -0
  179. package/stat/assets/images/two_page_mode_icon.png +0 -0
  180. package/stat/assets/images/zoom_in_icon.png +0 -0
  181. package/stat/assets/images/zoom_out_icon.png +0 -0
  182. package/stat/css/BookReader.scss +89 -0
  183. package/stat/css/_BRBookmarks.scss +29 -0
  184. package/stat/css/_BRComponent.scss +13 -0
  185. package/stat/css/_BRfloat.scss +197 -0
  186. package/stat/css/_BRicon.scss +48 -0
  187. package/stat/css/_BRmain.scss +251 -0
  188. package/stat/css/_BRnav.scss +359 -0
  189. package/stat/css/_BRpages.scss +139 -0
  190. package/stat/css/_BRsearch.scss +226 -0
  191. package/stat/css/_BRtoolbar.scss +84 -0
  192. package/stat/css/_BRvendor.scss +5 -0
  193. package/stat/css/_MobileNav.scss +194 -0
  194. package/stat/css/_TextSelection.scss +32 -0
  195. package/stat/css/_colorbox.scss +52 -0
  196. package/stat/css/_controls.scss +253 -0
  197. package/stat/css/_icons.scss +121 -0
  198. package/stat/jquery-wrapper.js +4 -0
  199. package/stat/plugins/plugin.archive_analytics.js +86 -0
  200. package/stat/plugins/plugin.autoplay.js +129 -0
  201. package/stat/plugins/plugin.chapters.js +248 -0
  202. package/stat/plugins/plugin.iframe.js +48 -0
  203. package/stat/plugins/plugin.mobile_nav.js +288 -0
  204. package/stat/plugins/plugin.resume.js +68 -0
  205. package/stat/plugins/plugin.text_selection.js +291 -0
  206. package/{src → stat}/plugins/plugin.url.js +0 -0
  207. package/stat/plugins/plugin.vendor-fullscreen.js +247 -0
  208. package/stat/plugins/search/plugin.search.js +439 -0
  209. package/stat/plugins/search/view.js +439 -0
  210. package/stat/plugins/tts/AbstractTTSEngine.js +249 -0
  211. package/stat/plugins/tts/FestivalTTSEngine.js +169 -0
  212. package/stat/plugins/tts/PageChunk.js +107 -0
  213. package/stat/plugins/tts/PageChunkIterator.js +163 -0
  214. package/stat/plugins/tts/WebTTSEngine.js +357 -0
  215. package/stat/plugins/tts/plugin.tts.js +357 -0
  216. package/stat/plugins/tts/tooltip_dict.js +15 -0
  217. package/stat/plugins/tts/utils.js +91 -0
  218. package/stat/util/browserSniffing.js +30 -0
  219. package/stat/util/debouncer.js +26 -0
  220. package/stat/util/docCookies.js +67 -0
  221. package/stat/util/strings.js +34 -0
  222. package/tests/e2e/viewmode.test.js +30 -30
  223. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +64 -52
  224. package/tests/jest/BookReader.test.js +1 -1
  225. package/tests/jest/plugins/url/UrlPlugin.test.js +175 -0
  226. package/tests/jest/plugins/{plugin.url.test.js → url/plugin.url.test.js} +3 -2
  227. package/tests/karma/BookNavigator/book-navigator.test.js +413 -108
  228. package/tests/karma/BookNavigator/bookmarks/bookmark-button.test.js +44 -0
  229. package/tests/karma/BookNavigator/downloads/downloads-provider.test.js +6 -3
  230. package/tests/karma/BookNavigator/search/search-provider.test.js +106 -6
  231. package/tests/karma/BookNavigator/search/search-results.test.js +0 -2
  232. package/tests/karma/BookNavigator/sharing/sharing-provider.test.js +29 -20
  233. package/tests/karma/BookNavigator/volumes/volumes-provider.test.js +46 -22
  234. package/webpack.config.js +1 -1
  235. package/src/BookNavigator/assets/book-loader.js +0 -27
  236. package/src/ItemNavigator/ItemNavigator.js +0 -377
@@ -1,5 +1,7 @@
1
- import { render, nothing } from 'lit-html';
1
+ import { render } from 'lit-html';
2
2
  import { LitElement, html, css } from 'lit-element';
3
+ // eslint-disable-next-line no-unused-vars
4
+ import { ModalConfig, ModalManager } from '@internetarchive/modal-manager';
3
5
  import buttonStyles from '../assets/button-base.js';
4
6
  import './bookmarks-loginCTA.js';
5
7
 
@@ -57,9 +59,11 @@ class IABookmarks extends LitElement {
57
59
  activeBookmarkID: { type: String },
58
60
  bookmarks: { type: Array },
59
61
  bookreader: { type: Object },
60
- options: { type: Object },
61
62
  displayMode: { type: String },
62
63
  editedBookmark: { type: Object },
64
+ deleteModalConfig: { type: Object},
65
+ modal: { attribute: false },
66
+ loginOptions: { type: Object, attribute: false }
63
67
  };
64
68
  }
65
69
 
@@ -92,7 +96,12 @@ class IABookmarks extends LitElement {
92
96
  this.bookmarks = [];
93
97
  this.bookreader = {};
94
98
  this.editedBookmark = {};
95
- this.options = {};
99
+ /** @type {ModalManager} */
100
+ this.modal = undefined;
101
+ this.loginOptions = {
102
+ loginClicked: () => {},
103
+ loginUrl: '',
104
+ };
96
105
  /**
97
106
  * Toggles display to either bookmarks or login cta
98
107
  * @param {('bookmarks'|'login')} displayMode
@@ -113,9 +122,18 @@ class IABookmarks extends LitElement {
113
122
  // eslint-disable-next-line
114
123
  this.defaultColor = this.bookmarkColors[0];
115
124
  this.api = api;
125
+ this.deleteModalConfig = new ModalConfig({
126
+ title: 'Delete Bookmark',
127
+ headline: 'This bookmark contains a note. Deleting it will permanently delete the note. Are you sure?',
128
+ headerColor: '#194880',
129
+ });
116
130
  }
117
131
 
118
- updated() {
132
+ updated(changed) {
133
+ if (changed.has('displayMode')) {
134
+ this.updateDisplay();
135
+ }
136
+
119
137
  this.emitBookmarksChanged();
120
138
  }
121
139
 
@@ -124,13 +142,24 @@ class IABookmarks extends LitElement {
124
142
  if (this.displayMode === 'login') {
125
143
  return;
126
144
  }
145
+ this.setBREventListeners();
146
+ this.initializeBookmarks();
147
+ }
148
+
149
+ updateDisplay() {
150
+ if (this.displayMode === 'bookmarks') {
151
+ this.fetchUserBookmarks();
152
+ }
153
+ }
154
+
155
+ fetchUserBookmarks() {
127
156
  this.fetchBookmarks()
128
- .then(() => this.initializeBookmarks())
129
- .catch((err) => this.displayMode = 'login');
157
+ .then(() => {
158
+ this.initializeBookmarks();
159
+ });
130
160
  }
131
161
 
132
- initializeBookmarks() {
133
- this.displayMode = 'bookmarks';
162
+ setBREventListeners() {
134
163
  ['3PageViewSelected'].forEach((event) => {
135
164
  window.addEventListener(`BookReader:${event}`, (e) => {
136
165
  setTimeout(() => {
@@ -150,12 +179,12 @@ class IABookmarks extends LitElement {
150
179
  });
151
180
  ['zoomOut', 'zoomIn', 'resize'].forEach((event) => {
152
181
  window.addEventListener(`BookReader:${event}`, () => {
153
- if (this.bookreader.mode === this.bookreader.constModeThumb) {
154
- this.renderBookmarkButtons();
155
- }
182
+ this.renderBookmarkButtons();
156
183
  });
157
184
  });
185
+ }
158
186
 
187
+ initializeBookmarks() {
159
188
  this.renderBookmarkButtons();
160
189
  this.markActiveBookmark(true);
161
190
  this.emitBookmarksChanged();
@@ -198,13 +227,22 @@ class IABookmarks extends LitElement {
198
227
  }
199
228
 
200
229
  fetchBookmarks() {
201
- return this.api.getAll().then((res) => res.json()).then(({
202
- success,
203
- error = 'Something happened while fetching bookmarks.',
204
- value: bkmrks = [],
205
- }) => {
230
+ return this.api.getAll().then((res) => {
231
+ let response;
232
+ try {
233
+ response = JSON.parse(res);
234
+ } catch (e) {
235
+ response = { error: e.message };
236
+ }
237
+ return response;
238
+ }).then((response) => {
239
+ const {
240
+ success,
241
+ error = 'Something happened while fetching bookmarks.',
242
+ value: bkmrks = [],
243
+ } = response;
206
244
  if (!success) {
207
- throw new Error(`Failed to load bookmarks: ${error}`);
245
+ console?.warn('Error fetching bookmarks', error);
208
246
  }
209
247
 
210
248
  const bookmarks = {};
@@ -253,7 +291,9 @@ class IABookmarks extends LitElement {
253
291
 
254
292
  pages.forEach((pageEl) => {
255
293
  const existingButton = pageEl.querySelector('.bookmark-button');
256
- if (existingButton) { existingButton.remove(); }
294
+ if (existingButton) {
295
+ existingButton.remove();
296
+ }
257
297
  const pageID = +pageEl.classList.value.match(/pagediv\d+/)[0].replace(/\D/g, '');
258
298
  const pageBookmark = this.getBookmark(pageID);
259
299
  const bookmarkState = pageBookmark ? 'filled' : 'hollow';
@@ -393,33 +433,26 @@ class IABookmarks extends LitElement {
393
433
  confirmDeletion(pageID) {
394
434
  const existingBookmark = this.getBookmark(pageID);
395
435
  if (existingBookmark.note) {
396
- this.emitShowModal(pageID);
436
+ this.displayDeletionModal(pageID);
397
437
  return;
398
438
  }
399
439
  this.deleteBookmark({ detail: { id: `${pageID}` } });
400
440
  }
401
441
 
402
- emitShowModal(pageID) {
403
- this.dispatchEvent(new CustomEvent('showItemNavigatorModal', {
404
- bubbles: true,
405
- composed: true,
406
- detail: {
407
- customModalContent: html`
408
- <delete-modal-actions
409
- .deleteAction=${() => this.deleteBookmark({ detail: { id: `${pageID}` } })}
410
- .cancelAction=${() => this.emitCloseModal()}
411
- .pageID=${pageID}
412
- ></delete-modal-actions>
413
- `,
414
- },
415
- }));
416
- }
442
+ displayDeletionModal(pageID) {
443
+ const customModalContent = html`
444
+ <delete-modal-actions
445
+ .deleteAction=${() => this.deleteBookmark({ detail: { id: `${pageID}` } })}
446
+ .cancelAction=${() => this.modal.closeModal()}
447
+ .pageID=${pageID}
448
+ ></delete-modal-actions>
449
+ `;
417
450
 
418
- emitCloseModal() {
419
- this.dispatchEvent(new CustomEvent('closeItemNavigatorModal', {
420
- bubbles: true,
421
- composed: true,
422
- }));
451
+
452
+ this.modal.showModal({
453
+ config: this.deleteModalConfig,
454
+ customModalContent,
455
+ });
423
456
  }
424
457
 
425
458
  deleteBookmark({ detail }) {
@@ -430,18 +463,10 @@ class IABookmarks extends LitElement {
430
463
 
431
464
  this.api.delete(detail.id);
432
465
  this.editedBookmark = {};
433
- this.emitCloseModal();
466
+ this.modal.closeModal();
434
467
  this.renderBookmarkButtons();
435
468
  }
436
469
 
437
- /**
438
- * call `loginClicked` callback
439
- */
440
- loginClick() {
441
- const { loginClicked = () => {} } = this.options;
442
- loginClicked();
443
- }
444
-
445
470
  /**
446
471
  * Tells us if we should allow user to add bookmark via menu panel
447
472
  * returns { Boolean }
@@ -487,15 +512,23 @@ class IABookmarks extends LitElement {
487
512
  `;
488
513
  }
489
514
 
515
+ get bookmarkHelperMessage() {
516
+ return html`<p>Please use 1up or 2up view modes to add bookmark.</p>`;
517
+ }
518
+
490
519
  render() {
491
- const { loginUrl } = this.options;
492
520
  const bookmarks = html`
493
521
  ${this.bookmarksList}
494
- ${this.allowAddingBookmark ? this.addBookmarkButton : nothing}
522
+ ${this.allowAddingBookmark ? this.addBookmarkButton : this.bookmarkHelperMessage}
495
523
  `;
496
524
  return html`
497
525
  <section class="bookmarks">
498
- ${this.displayMode === 'login' ? html`<bookmarks-login @click=${this.loginClick} .url=${loginUrl}></bookmarks-login>` : bookmarks}
526
+ ${ this.displayMode === 'login'
527
+ ? html`<bookmarks-login
528
+ @click=${() => this.loginOptions.loginClicked()}
529
+ .url=${this.loginOptions.loginUrl}></bookmarks-login>`
530
+ : bookmarks
531
+ }
499
532
  </section>
500
533
  `;
501
534
  }
@@ -1,9 +1,6 @@
1
1
  import { html } from 'lit-element';
2
-
3
- /* register subpanel */
4
- import { IABookDownloads } from './downloads';
5
-
6
- customElements.define('ia-book-downloads', IABookDownloads);
2
+ import '@internetarchive/icon-dl/icon-dl';
3
+ import './downloads';
7
4
 
8
5
  const menuBase = {
9
6
  pdf: {
@@ -25,14 +22,14 @@ const publicMenuBase = {
25
22
 
26
23
  export default class DownloadsProvider {
27
24
 
28
- constructor(isBookProtected) {
29
- this.icon = html`<ia-icon icon="download" style="width: var(--iconWidth); height: var(--iconHeight);"></ia-icon>`;
25
+ constructor({ bookreader }) {
26
+ this.icon = html`<ia-icon-dl style="width: var(--iconWidth); height: var(--iconHeight);"></ia-icon-dl>`;
30
27
  this.label = 'Downloadable files';
31
28
  this.menuDetails = '';
32
29
  this.downloads = [];
33
30
  this.id = 'downloads';
34
31
  this.component = '';
35
- this.isBookProtected = isBookProtected;
32
+ this.isBookProtected = bookreader?.options?.isProtected || false;
36
33
 
37
34
  this.computeAvailableTypes = this.computeAvailableTypes.bind(this);
38
35
  this.update = this.update.bind(this);
@@ -72,5 +69,4 @@ export default class DownloadsProvider {
72
69
  get menu () {
73
70
  return html`<ia-book-downloads .downloads=${this.downloads}></ia-book-downloads>`;
74
71
  }
75
-
76
72
  }
@@ -136,3 +136,4 @@ export class IABookDownloads extends LitElement {
136
136
  return [buttonStyles, mainCss];
137
137
  }
138
138
  }
139
+ customElements.define('ia-book-downloads', IABookDownloads);
@@ -1,6 +1,6 @@
1
1
  import { html } from 'lit-element';
2
2
  import { nothing } from 'lit-html';
3
-
3
+ import '@internetarchive/icon-search/icon-search';
4
4
  import './search-results';
5
5
 
6
6
  let searchState = {
@@ -10,8 +10,11 @@ let searchState = {
10
10
  queryInProgress: false,
11
11
  errorMessage: '',
12
12
  };
13
- export default class {
14
- constructor(onSearchChange = () => {}, brInstance) {
13
+ export default class SearchProvider {
14
+ constructor({
15
+ onProviderChange,
16
+ bookreader
17
+ }) {
15
18
  /* search menu events */
16
19
  this.onBookSearchInitiated = this.onBookSearchInitiated.bind(this);
17
20
  /* bookreader search events */
@@ -29,9 +32,9 @@ export default class {
29
32
  this.advanceToPage = this.advanceToPage.bind(this);
30
33
  this.updateMenu = this.updateMenu.bind(this);
31
34
 
32
- this.onSearchChange = onSearchChange;
33
- this.bookreader = brInstance;
34
- this.icon = html`<ia-icon icon="search" style="width: var(--iconWidth); height: var(--iconHeight);"></ia-icon>`;
35
+ this.onProviderChange = onProviderChange;
36
+ this.bookreader = bookreader;
37
+ this.icon = html`<ia-icon-search style="width: var(--iconWidth); height: var(--iconHeight);"></ia-icon-search>`;
35
38
  this.label = 'Search inside';
36
39
  this.menuDetails = this.getMenuDetails();
37
40
  this.id = 'search';
@@ -75,7 +78,10 @@ export default class {
75
78
  }
76
79
 
77
80
  onSearchStarted(e) {
78
- const { term = '' } = e.detail.props;
81
+ const { term = '', instance } = e.detail.props;
82
+ if (instance) {
83
+ this.bookreader = instance;
84
+ }
79
85
  searchState.query = term;
80
86
  searchState.results = [];
81
87
  searchState.resultsCount = 0;
@@ -104,6 +110,7 @@ export default class {
104
110
  };
105
111
 
106
112
  const messageToShow = errorMessages[errorType] ?? errorMessages.default;
113
+ searchState.query = instance?.searchResults?.q || '';
107
114
  searchState.results = [];
108
115
  searchState.resultsCount = 0;
109
116
  searchState.queryInProgress = false;
@@ -148,7 +155,7 @@ export default class {
148
155
  updateMenu(searchUpdates = {}) {
149
156
  this.menuDetails = this.getMenuDetails();
150
157
  this.component = this.getComponent();
151
- this.onSearchChange(this.bookreader, searchUpdates);
158
+ this.onProviderChange(this.bookreader, searchUpdates);
152
159
  }
153
160
 
154
161
  getComponent() {
@@ -0,0 +1,27 @@
1
+ import { html } from 'lit-element';
2
+ import '@internetarchive/icon-share/icon-share';
3
+ import '@internetarchive/ia-sharing-options';
4
+
5
+ export default class SharingProvider {
6
+ constructor({
7
+ item,
8
+ baseHost,
9
+ bookreader
10
+ }) {
11
+ const { identifier, creator, title } = item?.metadata;
12
+ const creatorToUse = Array.isArray(creator) ? creator[0] : creator;
13
+ const subPrefix = bookreader.options.subPrefix || '';
14
+ const label = `Share this book`;
15
+ this.icon = html`<ia-icon-share style="width: var(--iconWidth); height: var(--iconHeight);"></ia-icon-share>`;
16
+ this.label = label;
17
+ this.id = 'share';
18
+ this.component = html`<ia-sharing-options
19
+ .identifier=${identifier}
20
+ .type=${`book`}
21
+ .creator=${creatorToUse}
22
+ .description=${title}
23
+ .baseHost=${baseHost}
24
+ .fileSubPrefix=${subPrefix}
25
+ ></ia-sharing-options>`;
26
+ }
27
+ }
@@ -1,5 +1,6 @@
1
1
  import { html } from 'lit-element';
2
- import './visual-adjustments.js';
2
+ import '@internetarchive/icon-visual-adjustment/icon-visual-adjustment';
3
+ import './visual-adjustments';
3
4
 
4
5
  const visualAdjustmentOptions = [{
5
6
  id: 'brightness',
@@ -27,11 +28,11 @@ const visualAdjustmentOptions = [{
27
28
  active: false,
28
29
  }];
29
30
 
30
- export default class {
31
+ export default class VisualAdjustmentsProvider {
31
32
  constructor(options) {
32
- const { onOptionChange = () => {}, bookContainerSelector, bookreader } = options;
33
- this.onOptionChange = onOptionChange;
34
- this.bookContainerSelector = bookContainerSelector;
33
+ const { onProviderChange, bookreader } = options;
34
+ this.onProviderChange = onProviderChange;
35
+ this.bookContainer = bookreader.refs.$brContainer;
35
36
  this.bookreader = bookreader;
36
37
 
37
38
  this.onAdjustmentChange = this.onAdjustmentChange.bind(this);
@@ -41,7 +42,7 @@ export default class {
41
42
  this.onZoomOut = this.onZoomOut.bind(this);
42
43
 
43
44
  this.activeCount = 0;
44
- this.icon = html`<ia-icon icon="visualAdjustment" style="width: var(--iconWidth); height: var(--iconHeight);"></ia-icon>`;
45
+ this.icon = html`<ia-icon-visual-adjustment style="width: var(--iconWidth); height: var(--iconHeight);"></ia-icon-visual-adjustment>`;
45
46
  this.label = 'Visual Adjustments';
46
47
  this.menuDetails = this.updateOptionsCount();
47
48
  this.id = 'adjustment';
@@ -76,7 +77,7 @@ export default class {
76
77
  return newValue ? [...values, newValue] : values;
77
78
  }, []).join(' ');
78
79
 
79
- document.querySelector(this.bookContainerSelector).style.setProperty('filter', filters);
80
+ this.bookContainer.css('filter', filters);
80
81
 
81
82
  this.optionUpdateComplete(event);
82
83
  }
@@ -84,7 +85,7 @@ export default class {
84
85
  optionUpdateComplete(event) {
85
86
  this.activeCount = event.detail.activeCount;
86
87
  this.updateOptionsCount(event);
87
- this.onOptionChange(event);
88
+ this.onProviderChange();
88
89
  }
89
90
 
90
91
  updateOptionsCount() {
@@ -7,16 +7,26 @@ import volumesIcon from '../assets/icon_volumes.js';
7
7
 
8
8
  import './volumes.js';
9
9
 
10
+ const sortType = {
11
+ title_asc: 'title_asc',
12
+ title_desc: 'title_desc',
13
+ default: 'default'
14
+ };
10
15
  export default class VolumesProvider {
11
-
12
- constructor(baseHost, bookreader, optionChange) {
13
- this.optionChange = optionChange;
16
+ /**
17
+ * @param {import('../../BookReader').default} bookreader
18
+ */
19
+ constructor({ baseHost, bookreader, onProviderChange }) {
20
+ this.onProviderChange = onProviderChange;
14
21
  this.component = document.createElement("viewable-files");
15
22
 
16
23
  const files = bookreader.options.multipleBooksList.by_subprefix;
17
24
  this.viewableFiles = Object.keys(files).map(item => files[item]);
18
25
  this.volumeCount = Object.keys(files).length;
19
26
 
27
+ /** @type {import('../../BookReader').default} */
28
+ this.bookreader = bookreader;
29
+
20
30
  this.component.subPrefix = bookreader.options.subPrefix || "";
21
31
  this.component.hostUrl = baseHost;
22
32
  this.component.viewableFiles = this.viewableFiles;
@@ -25,20 +35,30 @@ export default class VolumesProvider {
25
35
  this.label = `Viewable files (${this.volumeCount})`;
26
36
  this.icon = html`${volumesIcon}`;
27
37
 
28
- this.sortOrderBy = "orig_sort";
29
- this.sortVolumes("orig_sort");
38
+ this.sortOrderBy = sortType.default;
39
+
40
+ // get sort state from query param
41
+ if (this.bookreader.urlPlugin) {
42
+ this.bookreader.urlPlugin.pullFromAddressBar();
43
+
44
+ const urlSortValue = this.bookreader.urlPlugin.getUrlParam('sort');
45
+ if (urlSortValue === sortType.title_asc || urlSortValue === sortType.title_desc) {
46
+ this.sortOrderBy = urlSortValue;
47
+ }
48
+ }
49
+ this.sortVolumes(this.sortOrderBy);
30
50
  }
31
51
 
32
52
  get sortButton() {
33
53
  const sortIcons = {
34
- orig_sort: html`
54
+ default: html`
35
55
  <button class="sort-by neutral-icon" aria-label="Sort volumes in initial order" @click=${() => this.sortVolumes("title_asc")}>${sortNeutralIcon}</button>
36
56
  `,
37
57
  title_asc: html`
38
58
  <button class="sort-by asc-icon" aria-label="Sort volumes in ascending order" @click=${() => this.sortVolumes("title_desc")}>${sortAscIcon}</button>
39
59
  `,
40
60
  title_desc: html`
41
- <button class="sort-by desc-icon" aria-label="Sort volumes in descending order" @click=${() => this.sortVolumes("orig_sort")}>${sortDescIcon}</button>
61
+ <button class="sort-by desc-icon" aria-label="Sort volumes in descending order" @click=${() => this.sortVolumes("default")}>${sortDescIcon}</button>
42
62
  `,
43
63
  };
44
64
 
@@ -46,28 +66,39 @@ export default class VolumesProvider {
46
66
  }
47
67
 
48
68
  /**
49
- * @param {'orig_sort' | 'title_asc' | 'title_desc'} sortByType
69
+ * @param {'default' | 'title_asc' | 'title_desc'} sortByType
50
70
  */
51
71
  sortVolumes(sortByType) {
52
72
  let sortedFiles = [];
53
73
 
54
74
  const files = this.viewableFiles;
55
75
  sortedFiles = files.sort((a, b) => {
56
- if (sortByType === 'orig_sort') return a.orig_sort - b.orig_sort;
57
- else if (sortByType === 'title_asc') return a.title.localeCompare(b.title);
58
- else return b.title.localeCompare(a.title);
76
+ if (sortByType === sortType.title_asc) return a.title.localeCompare(b.title);
77
+ else if (sortByType === sortType.title_desc) return b.title.localeCompare(a.title);
78
+ else return a.orig_sort - b.orig_sort;
59
79
  });
60
80
 
61
81
  this.sortOrderBy = sortByType;
82
+ this.component.sortOrderBy = sortByType;
62
83
  this.component.viewableFiles = [...sortedFiles];
63
84
  this.actionButton = this.sortButton;
64
- this.optionChange(this.bookreader);
85
+
86
+ if (this.bookreader.urlPlugin) {
87
+ this.bookreader.urlPlugin.pullFromAddressBar();
88
+ if (this.sortOrderBy !== sortType.default) {
89
+ this.bookreader.urlPlugin.setUrlParam('sort', sortByType);
90
+ } else {
91
+ this.bookreader.urlPlugin.removeUrlParam('sort');
92
+ }
93
+ }
94
+
95
+ this.onProviderChange(this.bookreader);
65
96
 
66
97
  this.multipleFilesClicked(sortByType);
67
98
  }
68
99
 
69
100
  /**
70
- * @param {'orig_sort' | 'title_asc' | 'title_desc'} orderBy
101
+ * @param {'default' | 'title_asc' | 'title_desc'} orderBy
71
102
  */
72
103
  multipleFilesClicked(orderBy) {
73
104
  if (!window.archive_analytics) {
@@ -8,13 +8,15 @@ export class Volumes extends LitElement {
8
8
  subPrefix: { type: String },
9
9
  hostUrl: { type: String },
10
10
  viewableFiles: { type: Array },
11
+ sortOrderBy: { type: String },
11
12
  };
12
13
  }
13
14
 
14
15
  constructor() {
15
16
  super();
16
- this.subPrefix = '';
17
17
  this.hostUrl = '';
18
+ this.sortOrderBy = '';
19
+ this.subPrefix = '';
18
20
  this.viewableFiles = [];
19
21
  }
20
22
 
@@ -36,10 +38,14 @@ export class Volumes extends LitElement {
36
38
  }
37
39
 
38
40
  volumeItemWithImageTitle(item) {
41
+ const hrefUrl = this.sortOrderBy === 'default'
42
+ ? `${this.hostUrl}${item.url_path}`
43
+ : `${this.hostUrl}${item.url_path}?sort=${this.sortOrderBy}`;
44
+
39
45
  return html`
40
46
  <li class="content active">
41
47
  <div class="separator"></div>
42
- <a class="container" href="${this.hostUrl}${item.url_path}">
48
+ <a class="container" href="${hrefUrl}">
43
49
  <div class="image">
44
50
  <img src="${item.image}">
45
51
  </div>
@@ -54,11 +60,16 @@ export class Volumes extends LitElement {
54
60
 
55
61
  volumeItem(item) {
56
62
  const activeClass = this.subPrefix === item.file_subprefix ? ' active' : '';
63
+
64
+ const hrefUrl = this.sortOrderBy === 'default'
65
+ ? `${this.hostUrl}${item.url_path}`
66
+ : `${this.hostUrl}${item.url_path}?sort=${this.sortOrderBy}`;
67
+
57
68
  return html`
58
69
  <li>
59
70
  <div class="separator"></div>
60
71
  <div class="content${activeClass}">
61
- <a href="https://${this.hostUrl}${item.url_path}">
72
+ <a href="https://${hrefUrl}">
62
73
  <p class="item-title">${item.title}</p>
63
74
  </a>
64
75
  </div>
@@ -279,6 +279,12 @@ export const DEFAULT_OPTIONS = {
279
279
  */
280
280
  startFullscreen: false,
281
281
 
282
+ /**
283
+ * @type {Boolean}
284
+ * will show logo at fullscreen mode
285
+ */
286
+ enableFSLogoShortcut: false,
287
+
282
288
  /**
283
289
  * @type {Boolean}
284
290
  * On init, by default, we want to handle resizing bookreader