@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,17 +1,14 @@
1
1
  import { css, html, LitElement } from 'lit-element';
2
- import { nothing } from 'lit-html';
3
- import { ResizeObserver as roPolyfill } from '@juggle/resize-observer';
2
+ import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
4
3
  import SearchProvider from './search/search-provider.js';
5
4
  import DownloadProvider from './downloads/downloads-provider.js';
6
5
  import VisualAdjustmentProvider from './visual-adjustments/visual-adjustments-provider.js';
7
6
  import BookmarksProvider from './bookmarks/bookmarks-provider.js';
8
- import SharingProvider from '../ItemNavigator/providers/sharing.js';
7
+ import SharingProvider from './sharing.js';
9
8
  import VolumesProvider from './volumes/volumes-provider.js';
10
9
  import BRFullscreenMgr from './br-fullscreen-mgr.js';
11
10
  import { Book } from './BookModel.js';
12
- import bookLoader from './assets/book-loader.js';
13
-
14
- const ResizeObserver = window.ResizeObserver || roPolyfill;
11
+ import iaLogo from './assets/ia-logo.js';
15
12
 
16
13
  const events = {
17
14
  menuUpdated: 'menuUpdated',
@@ -35,6 +32,9 @@ export class BookNavigator extends LitElement {
35
32
  menuShortcuts: { type: Array },
36
33
  sideMenuOpen: { type: Boolean },
37
34
  signedIn: { type: Boolean },
35
+ sharedObserver: { type: Object },
36
+ fullscreenBranding: { type: Object },
37
+ addBranding: { type: Boolean },
38
38
  };
39
39
  }
40
40
 
@@ -54,12 +54,15 @@ export class BookNavigator extends LitElement {
54
54
  this.menuShortcuts = [];
55
55
  this.sideMenuOpen = false;
56
56
  this.signedIn = false;
57
-
57
+ this.modal = undefined;
58
+ this.sharedObserver = undefined;
59
+ this.fullscreenBranding = iaLogo;
60
+ this.addBranding = true;
58
61
  // Untracked properties
59
62
  this.fullscreenMgr = null;
60
- this.brResizeObserver = null;
63
+ this.sharedObserver = null;
61
64
  this.model = new Book();
62
- this.shortcutOrder = ['volumes', 'search', 'bookmarks'];
65
+ this.shortcutOrder = ['fullscreen', 'volumes', 'search', 'bookmarks'];
63
66
  }
64
67
 
65
68
  firstUpdated() {
@@ -72,13 +75,9 @@ export class BookNavigator extends LitElement {
72
75
  if (!this.bookreader) {
73
76
  return;
74
77
  }
75
- const isFirstSideMenuUpdate = changed.has('sideMenuOpen') && (changed.get('sideMenuOpen') === undefined);
76
- if (!isFirstSideMenuUpdate) {
77
- // realign image
78
- if (this.bookreader.animating) {
79
- return;
80
- }
81
- this.bookreader.resize();
78
+ if (changed.has('signedIn') || changed.has('isAdmin')) {
79
+ /** redraw book submenus to propagate property update */
80
+ this.initializeBookSubmenus();
82
81
  }
83
82
  }
84
83
 
@@ -104,6 +103,15 @@ export class BookNavigator extends LitElement {
104
103
  */
105
104
  initializeBookSubmenus() {
106
105
  const isBookProtected = this.bookreader.options.protected;
106
+
107
+ // const baseProviderConfig = {
108
+ // modal: this.modal,
109
+ // sharedObserver: this.sharedObserver,
110
+ // bookreader: this.bookreader,
111
+ // signedIn: this.signedIn,
112
+ // isAdmin: this.isAdmin,
113
+ // };
114
+
107
115
  this.menuProviders = {
108
116
  search: new SearchProvider(
109
117
  /**
@@ -138,7 +146,7 @@ export class BookNavigator extends LitElement {
138
146
  bookreader: this.bookreader,
139
147
  }),
140
148
  share: new SharingProvider(this.book.metadata, this.baseHost, this.itemType, this.bookreader.options.subPrefix),
141
- bookmarks: new BookmarksProvider(this.bookmarksOptions, this.bookreader),
149
+ bookmarks: new BookmarksProvider(this.bookmarksOptions),
142
150
  };
143
151
 
144
152
  // add shortcut for volumes if multipleBooksList exists
@@ -167,10 +175,17 @@ export class BookNavigator extends LitElement {
167
175
  const referrerStr = `referer=${encodeURIComponent(location.href)}`;
168
176
  return {
169
177
  loginUrl: `https://${this.baseHost}/account/login?${referrerStr}`,
178
+ signedIn: this.signedIn,
170
179
  displayMode: this.signedIn ? 'bookmarks' : 'login',
171
- showItemNavigatorModal: this.showItemNavigatorModal.bind(this),
172
- closeItemNavigatorModal: this.closeItemNavigatorModal.bind(this),
173
- onBookmarksChanged: (bookmarks) => {
180
+ isAdmin: this.isAdmin,
181
+ modal: this.modal,
182
+ sharedObserver: this.sharedObserver,
183
+ bookreader: this.bookreader,
184
+ onBookmarksChanged: (bookmarks, showSidePanel = false) => {
185
+ console.log('booknav on bkch', bookmarks, showSidePanel);
186
+ if (showSidePanel) {
187
+ this.updateSideMenu('bookmarks', 'open');
188
+ }
174
189
  const method = Object.keys(bookmarks).length ? 'add' : 'remove';
175
190
  this[`${method}MenuShortcut`]('bookmarks');
176
191
  this.updateMenuContents();
@@ -178,6 +193,42 @@ export class BookNavigator extends LitElement {
178
193
  };
179
194
  }
180
195
 
196
+ /** Fullscreen Shortcut */
197
+ addFullscreenShortcut() {
198
+ const closeFS = {
199
+ icon: this.fullscreenShortcut,
200
+ id: 'fullscreen',
201
+ };
202
+ this.menuShortcuts.push(closeFS);
203
+ this.sortMenuShortcuts();
204
+ this.emitMenuShortcutsUpdated();
205
+ }
206
+
207
+ deleteFullscreenShortcut() {
208
+ console.log('delete fullscreenshortcut', this.menuShortcuts);
209
+ const updatedShortcuts = this.menuShortcuts.filter(({ id }) => {
210
+ return id !== 'fullscreen';
211
+ });
212
+ console.log('updatedShortcuts', updatedShortcuts);
213
+ this.menuShortcuts = updatedShortcuts;
214
+ this.sortMenuShortcuts();
215
+ this.emitMenuShortcutsUpdated();
216
+ }
217
+
218
+ closeFullscreen() {
219
+ this.bookreader.exitFullScreen();
220
+ }
221
+
222
+ get fullscreenShortcut() {
223
+ return html`
224
+ <button
225
+ @click=${() => this.closeFullscreen()}
226
+ title="Exit fullscreen view"
227
+ >${this.fullscreenBranding}</button>
228
+ `;
229
+ }
230
+ /** End Fullscreen Shortcut */
231
+
181
232
  /**
182
233
  * Open side menu
183
234
  * @param {string} menuId
@@ -205,7 +256,7 @@ export class BookNavigator extends LitElement {
205
256
  const availableMenus = [volumes, search, bookmarks, visualAdjustments, share].filter((menu) => !!menu);
206
257
 
207
258
  if (this.shouldShowDownloadsMenu()) {
208
- downloads.update(this.downloadableTypes);
259
+ downloads?.update(this.downloadableTypes);
209
260
  availableMenus.splice(1, 0, downloads);
210
261
  }
211
262
 
@@ -278,6 +329,13 @@ export class BookNavigator extends LitElement {
278
329
  this.dispatchEvent(event);
279
330
  }
280
331
 
332
+ emitLoadingStatusUpdate(loaded) {
333
+ const event = new CustomEvent('loadingStateUpdated', {
334
+ detail: { loaded },
335
+ });
336
+ this.dispatchEvent(event);
337
+ }
338
+
281
339
  /**
282
340
  * Core bookreader event handler registry
283
341
  *
@@ -286,22 +344,28 @@ export class BookNavigator extends LitElement {
286
344
  */
287
345
  bindEventListeners() {
288
346
  window.addEventListener('BookReader:PostInit', (e) => {
347
+ console.log('BookReader:PostInit');
289
348
  this.bookreader = e.detail.props;
290
349
  this.bookReaderLoaded = true;
291
350
  this.bookReaderCannotLoad = false;
292
351
  this.fullscreenMgr = new BRFullscreenMgr(this.bookreader.el);
293
352
 
294
353
  this.initializeBookSubmenus();
295
- setTimeout(() => this.bookreader.resize(), 0);
296
- this.brResizeObserver = new ResizeObserver((elements) => this.reactToBrResize(elements));
297
- this.brResizeObserver.observe(this.mainBRContainer);
354
+ this.startResizeObserver();
355
+ this.emitLoadingStatusUpdate(true);
298
356
  });
299
357
  window.addEventListener('BookReader:fullscreenToggled', (event) => {
358
+ console.log('BookReader:fullscreenToggled');
300
359
  const { detail: { props: brInstance = null } } = event;
301
360
  if (brInstance) {
302
361
  this.bookreader = brInstance;
303
362
  }
304
363
  this.manageFullScreenBehavior(event);
364
+ if (this.bookreader.isFullscreenActive) {
365
+ this.addFullscreenShortcut();
366
+ } else {
367
+ this.deleteFullscreenShortcut();
368
+ }
305
369
  }, { passive: true });
306
370
  window.addEventListener('BookReader:ToggleSearchMenu', (event) => {
307
371
  this.dispatchEvent(new CustomEvent(events.updateSideMenu, {
@@ -309,6 +373,7 @@ export class BookNavigator extends LitElement {
309
373
  }));
310
374
  });
311
375
  window.addEventListener('LendingFlow:PostInit', ({ detail }) => {
376
+ console.log('LendingFlow:PostInit');
312
377
  const {
313
378
  downloadTypesAvailable, lendingStatus, isAdmin, previewType,
314
379
  } = detail;
@@ -319,6 +384,8 @@ export class BookNavigator extends LitElement {
319
384
  this.bookReaderCannotLoad = previewType === 'singlePagePreview';
320
385
  });
321
386
  window.addEventListener('BRJSIA:PostInit', ({ detail }) => {
387
+ console.log('BRJSIA:PostInit');
388
+
322
389
  const { isRestricted, downloadURLs } = detail;
323
390
  this.bookReaderLoaded = true;
324
391
  this.downloadableTypes = downloadURLs;
@@ -332,17 +399,16 @@ export class BookNavigator extends LitElement {
332
399
  * - book animation is happening
333
400
  * - book is in fullscreen (fullscreen is handled separately)
334
401
  *
335
- * @param { Object } entries - resize observer entries
402
+ * @param { target: HTMLElement, contentRect: DOMRectReadOnly } entry
336
403
  */
337
- reactToBrResize(entries = []) {
404
+ handleResize({ contentRect, target }) {
338
405
  const startBrWidth = this.brWidth;
339
406
  const { animating } = this.bookreader;
340
407
 
341
- entries.forEach(({ contentRect, target }) => {
342
- if (target === this.mainBRContainer) {
343
- this.brWidth = contentRect.width;
344
- }
345
- });
408
+ if (target === this.mainBRContainer) {
409
+ this.brWidth = contentRect.width;
410
+ }
411
+
346
412
  setTimeout(() => {
347
413
  if (startBrWidth && !animating) {
348
414
  this.bookreader.resize();
@@ -350,6 +416,17 @@ export class BookNavigator extends LitElement {
350
416
  }, 0);
351
417
  }
352
418
 
419
+ async startResizeObserver() {
420
+ if (!this.sharedObserver) {
421
+ this.sharedObserver = new SharedResizeObserver();
422
+ }
423
+
424
+ this.sharedObserver?.addObserver({
425
+ handler: this,
426
+ target: this.mainBRContainer,
427
+ });
428
+ }
429
+
353
430
  /**
354
431
  * Manages Fullscreen behavior
355
432
  * This makes sure that controls are _always_ in view
@@ -357,7 +434,6 @@ export class BookNavigator extends LitElement {
357
434
  */
358
435
  manageFullScreenBehavior() {
359
436
  this.emitFullScreenState();
360
-
361
437
  if (!this.bookreader.isFullscreen()) {
362
438
  this.fullscreenMgr.teardown();
363
439
  } else {
@@ -376,32 +452,6 @@ export class BookNavigator extends LitElement {
376
452
  this.dispatchEvent(event);
377
453
  }
378
454
 
379
- emitShowItemNavigatorModal(e) {
380
- this.dispatchEvent(new CustomEvent('showItemNavigatorModal', {
381
- detail: e.detail,
382
- }));
383
- }
384
-
385
- emitCloseItemNavigatorModal() {
386
- this.dispatchEvent(new CustomEvent('closeItemNavigatorModal'));
387
- }
388
-
389
- showItemNavigatorModal(e) {
390
- this.emitShowItemNavigatorModal(e);
391
- }
392
-
393
- closeItemNavigatorModal() {
394
- this.emitCloseItemNavigatorModal();
395
- }
396
-
397
- get loader() {
398
- const loader = html`
399
- <div class="book-loader">${bookLoader}<div>
400
- <h3>Loading viewer</h3>
401
- `;
402
- return !this.bookReaderLoaded ? loader : nothing;
403
- }
404
-
405
455
  get loadingClass() {
406
456
  return !this.bookReaderLoaded ? 'loading' : '';
407
457
  }
@@ -415,56 +465,13 @@ export class BookNavigator extends LitElement {
415
465
  const placeholder = this.bookReaderCannotLoad ? this.itemImage : this.loader;
416
466
  return html`<div id="book-navigator" class="${this.loadingClass}">
417
467
  ${placeholder}
418
- <slot name="bookreader"></slot>
468
+ <slot name="theater-main"></slot>
419
469
  </div>
420
470
  `;
421
471
  }
422
472
 
423
473
  static get styles() {
424
474
  return css`
425
- #book-navigator.loading {
426
- display: flex;
427
- align-items: center;
428
- justify-content: center;
429
- min-height: 30vh;
430
- }
431
-
432
- #book-navigator .book-loader {
433
- width: 30%;
434
- margin: auto;
435
- text-align: center;
436
- color: var(--primaryTextColor);
437
- }
438
-
439
- .book-loader {
440
- position: relative;
441
- }
442
-
443
- .book-loader svg {
444
- display: block;
445
- width: 60%;
446
- max-width: 100px;
447
- height: auto;
448
- margin: auto;
449
- }
450
-
451
- svg * {
452
- fill: var(--primaryTextColor);
453
- }
454
-
455
- svg .ring {
456
- animation: rotate 1.3s infinite linear;
457
- transform-origin: 50px 50px;
458
- transform-box: fill-box;
459
- display: block; // transform won't work on inline style
460
- }
461
-
462
- @keyframes rotate {
463
- 0% {
464
- transform: rotate(-360deg);
465
- }
466
- }
467
-
468
475
  .cover-img {
469
476
  max-height: 300px;
470
477
  }
@@ -0,0 +1,15 @@
1
+ import { css } from 'lit-element';
2
+
3
+ export default css`
4
+ .blue {
5
+ --iconFillColor: var(--blueBookmarkColor, #0023f5);
6
+ }
7
+
8
+ .red {
9
+ --iconFillColor: var(--redBookmarkColor, #eb3223);
10
+ }
11
+
12
+ .green {
13
+ --iconFillColor: var(--greenBookmarkColor, #75ef4c);
14
+ }
15
+ `;
@@ -0,0 +1,61 @@
1
+ import { css } from 'lit-element';
2
+
3
+ export default css`
4
+ .ia-button {
5
+ min-height: 3rem;
6
+ border: none;
7
+ outline: none;
8
+ cursor: pointer;
9
+ color: var(--primaryTextColor);
10
+ line-height: normal;
11
+ border-radius: .4rem;
12
+ text-align: center;
13
+ vertical-align: middle;
14
+ font-size: 1.4rem;
15
+ display: inline-block;
16
+ padding: .6rem 1.2rem;
17
+ border: 1px solid transparent;
18
+
19
+ white-space: nowrap;
20
+ -webkit-user-select: none;
21
+ -moz-user-select: none;
22
+ -ms-user-select: none;
23
+ -o-user-select: none;
24
+ user-select: none;
25
+ }
26
+
27
+ .ia-button.link,
28
+ .ia-button.external {
29
+ min-height: unset;
30
+ text-decoration: none;
31
+ }
32
+
33
+ .ia-button:disabled,
34
+ .ia-button.disabled {
35
+ cursor: not-allowed;
36
+ opacity: 0.5;
37
+ }
38
+
39
+ .ia-button.transparent {
40
+ background-color: transparent;
41
+ }
42
+
43
+ .ia-button.slim {
44
+ padding: 0;
45
+ }
46
+
47
+ .ia-button.primary {
48
+ background-color: var(--primaryCTAFill);
49
+ border-color: var(--primaryCTABorder);
50
+ }
51
+
52
+ .ia-button.cancel {
53
+ background-color: var(--primaryErrorCTAFill);
54
+ border-color: var(--primaryErrorCTABorder);
55
+ }
56
+
57
+ .ia-button.external {
58
+ background: var(--secondaryCTAFill);
59
+ border-color: var(--secondaryCTABorder);
60
+ }
61
+ `;
@@ -0,0 +1,17 @@
1
+ import { svg } from 'lit-element';
2
+
3
+ export default svg`
4
+ <svg class="ia-logo" width="27" height="30" viewBox="0 0 27 30" xmlns="http://www.w3.org/2000/svg" aria-labelledby="logoTitleID logoDescID">
5
+ <title id="logoTitleID">Internet Archive logo</title>
6
+ <desc id="logoDescID">A line drawing of the Internet Archive headquarters building façade.</desc>
7
+ <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
8
+ <mask id="mask-2" fill="white">
9
+ <path d="M26.6666667,28.6046512 L26.6666667,30 L0,30 L0.000283687943,28.6046512 L26.6666667,28.6046512 Z M25.6140351,26.5116279 L25.6140351,28.255814 L1.05263158,28.255814 L1.05263158,26.5116279 L25.6140351,26.5116279 Z M3.62469203,7.6744186 L3.91746909,7.82153285 L4.0639977,10.1739544 L4.21052632,13.9963932 L4.21052632,17.6725617 L4.0639977,22.255044 L4.03962296,25.3421929 L3.62469203,25.4651163 L2.16024641,25.4651163 L1.72094074,25.3421929 L1.55031755,22.255044 L1.40350877,17.6970339 L1.40350877,14.0211467 L1.55031755,10.1739544 L1.68423854,7.80887484 L1.98962322,7.6744186 L3.62469203,7.6744186 Z M24.6774869,7.6744186 L24.9706026,7.82153285 L25.1168803,10.1739544 L25.2631579,13.9963932 L25.2631579,17.6725617 L25.1168803,22.255044 L25.0927809,25.3421929 L24.6774869,25.4651163 L23.2130291,25.4651163 L22.7736357,25.3421929 L22.602418,22.255044 L22.4561404,17.6970339 L22.4561404,14.0211467 L22.602418,10.1739544 L22.7369262,7.80887484 L23.0420916,7.6744186 L24.6774869,7.6744186 Z M9.94042303,7.6744186 L10.2332293,7.82153285 L10.3797725,10.1739544 L10.5263158,13.9963932 L10.5263158,17.6725617 L10.3797725,22.255044 L10.3556756,25.3421929 L9.94042303,25.4651163 L8.47583122,25.4651163 L8.0362015,25.3421929 L7.86556129,22.255044 L7.71929825,17.6970339 L7.71929825,14.0211467 L7.86556129,10.1739544 L8.00005604,7.80887484 L8.30491081,7.6744186 L9.94042303,7.6744186 Z M18.0105985,7.6744186 L18.3034047,7.82153285 L18.449948,10.1739544 L18.5964912,13.9963932 L18.5964912,17.6725617 L18.449948,22.255044 L18.425851,25.3421929 L18.0105985,25.4651163 L16.5460067,25.4651163 L16.1066571,25.3421929 L15.9357367,22.255044 L15.7894737,17.6970339 L15.7894737,14.0211467 L15.9357367,10.1739544 L16.0702315,7.80887484 L16.3753664,7.6744186 L18.0105985,7.6744186 Z M25.6140351,4.53488372 L25.6140351,6.97674419 L1.05263158,6.97674419 L1.05263158,4.53488372 L25.6140351,4.53488372 Z M13.0806755,0 L25.9649123,2.93331338 L25.4484139,3.8372093 L0.771925248,3.8372093 L0,3.1041615 L13.0806755,0 Z" id="path-1"></path>
10
+ </mask>
11
+ <use fill="#FFFFFF" xlink:href="#path-1"></use>
12
+ <g mask="url(#mask-2)" fill="#FFFFFF">
13
+ <path d="M0,0 L26.6666667,0 L26.6666667,30 L0,30 L0,0 Z" id="swatch"></path>
14
+ </g>
15
+ </g>
16
+ </svg>
17
+ `;
@@ -0,0 +1,6 @@
1
+ import { css } from 'lit-element';
2
+
3
+ // Original SVG object for reference
4
+ // <svg height="10" viewBox="0 0 13 10" width="13" xmlns="http://www.w3.org/2000/svg"><path d="m4.33333333 10-4.33333333-4.16666667 1.73333333-1.66666666 2.6 2.5 6.93333337-6.66666667 1.7333333 1.66666667z" fill="#fff" fill-rule="evenodd"/></svg>
5
+
6
+ export default css`data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjEwIiB2aWV3Qm94PSIwIDAgMTMgMTAiIHdpZHRoPSIxMyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtNC4zMzMzMzMzMyAxMC00LjMzMzMzMzMzLTQuMTY2NjY2NjcgMS43MzMzMzMzMy0xLjY2NjY2NjY2IDIuNiAyLjUgNi45MzMzMzMzNy02LjY2NjY2NjY3IDEuNzMzMzMzMyAxLjY2NjY2NjY3eiIgZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIi8+PC9zdmc+`;
@@ -0,0 +1,3 @@
1
+ import { css } from 'lit-element';
2
+
3
+ export default css`data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNDAgNDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgYXJpYS1sYWJlbGxlZGJ5PSJjbG9zZVRpdGxlSUQgY2xvc2VEZXNjSUQiPjxwYXRoIGQ9Ik0yOS4xOTIgMTAuODA4YTEuNSAxLjUgMCAwMTAgMi4xMkwyMi4xMjIgMjBsNy4wNyA3LjA3MmExLjUgMS41IDAgMDEtMi4xMiAyLjEyMWwtNy4wNzMtNy4wNy03LjA3IDcuMDdhMS41IDEuNSAwIDAxLTIuMTIxLTIuMTJsNy4wNy03LjA3My03LjA3LTcuMDdhMS41IDEuNSAwIDAxMi4xMi0yLjEyMUwyMCAxNy44NzhsNy4wNzItNy4wN2ExLjUgMS41IDAgMDEyLjEyMSAweiIgY2xhc3M9ImZpbGwtY29sb3IiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==`;
@@ -0,0 +1,5 @@
1
+ import { html } from 'lit-html';
2
+
3
+ export default html`
4
+ <svg name="sort-asc" height="18" viewBox="0 0 18 18" width="18" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="m2.32514544 8.30769231.7756949-2.08468003h2.92824822l.75630252 2.08468003h1.01809955l-2.70523594-6.92307693h-1.01809955l-2.69553976 6.92307693zm3.41305753-2.86037492h-2.34647705l1.17323853-3.22883h.01939237z" fill="#fff" fill-rule="nonzero"/><path d="m7.1689722 16.6153846v-.7756949h-4.4117647l4.29541047-5.3716871v-.77569491h-5.06140918v.77569491h3.97543633l-4.30510666 5.3716871v.7756949z" fill="#fff" fill-rule="nonzero"/><path d="m10.3846154 11.0769231 2.7692308 5.5384615 2.7692307-5.5384615m-2.7692307 4.1538461v-13.15384612" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.661538" transform="matrix(1 0 0 -1 0 18.692308)"/></g></svg>
5
+ `;
@@ -0,0 +1,5 @@
1
+ import { html } from 'lit-html';
2
+
3
+ export default html`
4
+ <svg name="sort-desc" height="18" viewBox="0 0 18 18" width="18" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="m2.32514544 8.30769231.7756949-2.08468003h2.92824822l.75630252 2.08468003h1.01809955l-2.70523594-6.92307693h-1.01809955l-2.69553976 6.92307693zm3.41305753-2.86037492h-2.34647705l1.17323853-3.22883h.01939237z" fill="#fff" fill-rule="nonzero"/><path d="m7.1689722 16.6153846v-.7756949h-4.4117647l4.29541047-5.3716871v-.77569491h-5.06140918v.77569491h3.97543633l-4.30510666 5.3716871v.7756949z" fill="#fff" fill-rule="nonzero"/><path d="m10.3846154 11.0769231 2.7692308 5.5384615 2.7692307-5.5384615m-2.7692307 4.1538461v-13.15384612" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.661538"/></g></svg>
5
+ `;
@@ -0,0 +1,5 @@
1
+ import { html } from 'lit-html';
2
+
3
+ export default html`
4
+ <svg name="sort-neutral" height="18" viewBox="0 0 18 18" width="18" xmlns="http://www.w3.org/2000/svg"><g fill="#fff" fill-rule="evenodd"><path d="m2.32514544 8.30769231.7756949-2.08468003h2.92824822l.75630252 2.08468003h1.01809955l-2.70523594-6.92307693h-1.01809955l-2.69553976 6.92307693zm3.41305753-2.86037492h-2.34647705l1.17323853-3.22883h.01939237z" fill-rule="nonzero"/><path d="m7.1689722 16.6153846v-.7756949h-4.4117647l4.29541047-5.3716871v-.77569491h-5.06140918v.77569491h3.97543633l-4.30510666 5.3716871v.7756949z" fill-rule="nonzero"/><circle cx="13" cy="9" r="2"/></g></svg>
5
+ `;
@@ -0,0 +1,11 @@
1
+ import { html } from 'lit-html';
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,64 @@
1
+ import { LitElement, html, css } from 'lit-element';
2
+
3
+ export default class BookmarkButton extends LitElement {
4
+ static get styles() {
5
+ return css`
6
+ button {
7
+ -webkit-appearance: none;
8
+ appearance: none;
9
+ outline: 0;
10
+ border: none;
11
+ padding: 0;
12
+ height: 4rem;
13
+ width: 4rem;
14
+ background: transparent;
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
+ position: relative;
17
+ }
18
+ button > * {
19
+ display: block;
20
+ position: absolute;
21
+ top: 0.2rem;
22
+ }
23
+ button.left > * {
24
+ left: 0.2rem;
25
+ }
26
+
27
+ button.right > * {
28
+ right: 0.2rem;
29
+ }
30
+ `;
31
+ }
32
+
33
+ static get properties() {
34
+ return {
35
+ side: { type: String },
36
+ state: { type: String },
37
+ };
38
+ }
39
+
40
+ constructor() {
41
+ super();
42
+ this.state = 'hollow';
43
+ }
44
+
45
+ handleClick(e) {
46
+ e.preventDefault();
47
+ this.dispatchEvent(new CustomEvent('bookmarkButtonClicked'));
48
+ }
49
+
50
+ get title() {
51
+ return `${this.state === 'hollow' ? 'Add' : 'Remove'} bookmark`;
52
+ }
53
+
54
+ render() {
55
+ const position = this.side || 'right';
56
+ return html`
57
+ <button title=${this.title} @click=${this.handleClick} class=${position}>
58
+ <icon-bookmark state=${this.state}></icon-bookmark>
59
+ </button>
60
+ `;
61
+ }
62
+ }
63
+
64
+ customElements.define('bookmark-button', BookmarkButton);