@internetarchive/bookreader 5.0.0-106 → 5.0.0-107
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.
- package/BookReader/BookReader.js +1 -1
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +54 -60
- package/BookReader/ia-bookreader-bundle.js.map +1 -1
- package/BookReader/plugins/plugin.chapters.js +1 -4
- package/BookReader/plugins/plugin.chapters.js.map +1 -1
- package/package.json +12 -10
- package/src/BookReader.js +1 -1
- package/src/css/icon_checkmark.js +9 -0
- package/src/css/sharedStyles.js +15 -0
- package/src/{BookNavigator → ia-bookreader}/downloads/downloads.js +1 -1
- package/src/ia-bookreader/ia-bookreader.js +513 -71
- package/src/{BookNavigator → ia-bookreader}/viewable-files.js +4 -1
- package/src/{BookNavigator → ia-bookreader}/visual-adjustments/visual-adjustments-provider.js +1 -2
- package/src/{BookNavigator → ia-bookreader}/visual-adjustments/visual-adjustments.js +4 -14
- package/src/{BookNavigator → plugins}/bookmarks/bookmark-button.js +1 -1
- package/src/{BookNavigator → plugins}/bookmarks/bookmark-edit.js +41 -28
- package/src/{BookNavigator → plugins}/bookmarks/bookmarks-list.js +46 -46
- package/src/{BookNavigator → plugins}/bookmarks/bookmarks-loginCTA.js +1 -1
- package/src/{BookNavigator → plugins}/bookmarks/bookmarks-provider.js +1 -1
- package/src/{BookNavigator → plugins}/bookmarks/ia-bookmarks.js +2 -2
- package/src/{BookNavigator → plugins}/search/search-results.js +14 -20
- package/src/util/lit.js +10 -0
- package/src/BookNavigator/assets/ia-logo.js +0 -17
- package/src/BookNavigator/assets/icon_checkmark.js +0 -6
- package/src/BookNavigator/assets/icon_close.js +0 -3
- package/src/BookNavigator/book-navigator.js +0 -620
- /package/src/{BookNavigator/assets → css}/button-base.js +0 -0
- /package/src/{BookNavigator → ia-bookreader}/downloads/downloads-provider.js +0 -0
- /package/src/{BookNavigator → ia-bookreader}/sharing.js +0 -0
- /package/src/{BookNavigator/assets → plugins/bookmarks}/bookmark-colors.js +0 -0
- /package/src/{BookNavigator → plugins/bookmarks}/delete-modal-actions.js +0 -0
- /package/src/{BookNavigator → plugins}/search/search-provider.js +0 -0
|
@@ -1,15 +1,26 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
/**
|
|
2
|
-
*
|
|
3
|
+
* Wrapping web component for Internet Archive's BookReader. Currently operates
|
|
4
|
+
* more as a shell ; requires BookReader to be instantiated independently in the
|
|
5
|
+
* main slot.
|
|
3
6
|
*/
|
|
4
7
|
|
|
5
8
|
import { LitElement, html, css } from 'lit';
|
|
6
9
|
|
|
7
10
|
import '@internetarchive/ia-item-navigator';
|
|
8
|
-
import '../BookNavigator/book-navigator.js';
|
|
9
|
-
// eslint-disable-next-line no-unused-vars
|
|
10
|
-
import { ModalManager } from '@internetarchive/modal-manager';
|
|
11
11
|
import '@internetarchive/modal-manager';
|
|
12
12
|
import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
|
|
13
|
+
import '@internetarchive/icon-ia-logo';
|
|
14
|
+
import SearchProvider from '../plugins/search/search-provider.js';
|
|
15
|
+
import DownloadProvider from './downloads/downloads-provider.js';
|
|
16
|
+
import VisualAdjustmentProvider from './visual-adjustments/visual-adjustments-provider.js';
|
|
17
|
+
import BookmarksProvider from '../plugins/bookmarks/bookmarks-provider.js';
|
|
18
|
+
import SharingProvider from './sharing.js';
|
|
19
|
+
import ViewableFilesProvider from './viewable-files.js';
|
|
20
|
+
import { sortBy } from '../BookReader/utils.js';
|
|
21
|
+
/** @typedef {import('@/src/BookReader.js').default} BookReader */
|
|
22
|
+
/** @typedef {import('@internetarchive/modal-manager').ModalManager} ModalManager */
|
|
23
|
+
|
|
13
24
|
|
|
14
25
|
export class IaBookReader extends LitElement {
|
|
15
26
|
static get properties() {
|
|
@@ -23,12 +34,28 @@ export class IaBookReader extends LitElement {
|
|
|
23
34
|
loaded: { type: Boolean },
|
|
24
35
|
menuShortcuts: { type: Array },
|
|
25
36
|
menuContents: { type: Array },
|
|
37
|
+
bookReaderLoaded: { type: Boolean },
|
|
38
|
+
bookreader: { type: Object },
|
|
39
|
+
bookIsRestricted: { type: Boolean },
|
|
40
|
+
downloadableTypes: { type: Array },
|
|
41
|
+
isAdmin: { type: Boolean },
|
|
42
|
+
lendingInitialized: { type: Boolean },
|
|
43
|
+
lendingStatus: { type: Object },
|
|
44
|
+
menuProviders: { type: Object },
|
|
45
|
+
fullscreenBranding: { type: Object },
|
|
26
46
|
};
|
|
27
47
|
}
|
|
28
48
|
|
|
49
|
+
/** @type {import('@internetarchive/ia-item-navigator').ItemNavigator} */
|
|
50
|
+
get itemNav() {
|
|
51
|
+
return this.shadowRoot.querySelector('iaux-item-navigator');
|
|
52
|
+
}
|
|
53
|
+
|
|
29
54
|
constructor() {
|
|
30
55
|
super();
|
|
56
|
+
/** The IA metadata item */
|
|
31
57
|
this.item = undefined;
|
|
58
|
+
/** @type {BookReader} */
|
|
32
59
|
this.bookreader = undefined;
|
|
33
60
|
this.baseHost = 'archive.org';
|
|
34
61
|
this.fullscreen = false;
|
|
@@ -38,12 +65,62 @@ export class IaBookReader extends LitElement {
|
|
|
38
65
|
/** @type {SharedResizeObserver} */
|
|
39
66
|
this.sharedObserver = undefined;
|
|
40
67
|
this.loaded = false;
|
|
68
|
+
/** @type {Array<{ id: string, icon: string | import('lit').TemplateResult }>} */
|
|
41
69
|
this.menuShortcuts = [];
|
|
42
70
|
this.menuContents = [];
|
|
43
71
|
this.openMenuName = '';
|
|
72
|
+
|
|
73
|
+
this.bookReaderCannotLoad = false;
|
|
74
|
+
this.bookReaderLoaded = false;
|
|
75
|
+
this.bookIsRestricted = false;
|
|
76
|
+
this.downloadableTypes = [];
|
|
77
|
+
this.isAdmin = false;
|
|
78
|
+
this.lendingInitialized = false;
|
|
79
|
+
this.lendingStatus = {};
|
|
80
|
+
this.menuProviders = {
|
|
81
|
+
/** @type {BookmarksProvider} */
|
|
82
|
+
bookmarks: null,
|
|
83
|
+
/** @type {SearchProvider} */
|
|
84
|
+
search: null,
|
|
85
|
+
/** @type {DownloadProvider} */
|
|
86
|
+
downloads: null,
|
|
87
|
+
/** @type {VisualAdjustmentProvider} */
|
|
88
|
+
visualAdjustments: null,
|
|
89
|
+
/** @type {SharingProvider} */
|
|
90
|
+
share: null,
|
|
91
|
+
/** @type {ViewableFilesProvider} */
|
|
92
|
+
volumes: null,
|
|
93
|
+
};
|
|
94
|
+
this.signedIn = false;
|
|
95
|
+
this.fullscreenBranding = html`<ia-icon-ia-logo aria-hidden="true"></ia-icon-ia-logo>`;
|
|
96
|
+
// Untracked properties
|
|
97
|
+
this._sharedObserverHandler = { handleResize: this.handleResize.bind(this) };
|
|
98
|
+
this._brWidth = 0;
|
|
99
|
+
this._brHeight = 0;
|
|
100
|
+
this.shortcutOrder = [
|
|
101
|
+
/**
|
|
102
|
+
* sets exit FS button (`this.fullscreenBranding`)
|
|
103
|
+
* when `br.options.enableFSLogoShortcut`
|
|
104
|
+
*/
|
|
105
|
+
'fullscreen',
|
|
106
|
+
'volumes',
|
|
107
|
+
'chapters',
|
|
108
|
+
'search',
|
|
109
|
+
'translate',
|
|
110
|
+
'bookmarks',
|
|
111
|
+
'downloads',
|
|
112
|
+
'visualAdjustments',
|
|
113
|
+
'share',
|
|
114
|
+
'experiments',
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
disconnectedCallback() {
|
|
119
|
+
super.disconnectedCallback();
|
|
120
|
+
this.unloadSharedObserver();
|
|
44
121
|
}
|
|
45
122
|
|
|
46
|
-
|
|
123
|
+
firstUpdated() {
|
|
47
124
|
if (!this.modal) {
|
|
48
125
|
this.setModalManager();
|
|
49
126
|
}
|
|
@@ -51,50 +128,242 @@ export class IaBookReader extends LitElement {
|
|
|
51
128
|
if (!this.sharedObserver) {
|
|
52
129
|
this.sharedObserver = new SharedResizeObserver();
|
|
53
130
|
}
|
|
131
|
+
|
|
132
|
+
this._bindEventListeners();
|
|
133
|
+
this.loaded = true;
|
|
54
134
|
}
|
|
55
135
|
|
|
56
|
-
|
|
57
|
-
|
|
136
|
+
/**
|
|
137
|
+
* @param {import('lit').PropertyValues} changed
|
|
138
|
+
*/
|
|
139
|
+
updated(changed) {
|
|
140
|
+
if (!this.bookreader || !this.item || !this.bookReaderLoaded) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const reload = changed.has('loaded') && this.loaded;
|
|
145
|
+
if (reload
|
|
146
|
+
|| changed.has('item')
|
|
147
|
+
|| changed.has('bookreader')
|
|
148
|
+
|| changed.has('signedIn')
|
|
149
|
+
|| changed.has('isAdmin')
|
|
150
|
+
|| changed.has('modal')) {
|
|
151
|
+
this.initializeBookSubmenus();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (changed.has('sharedObserver') && this.bookreader) {
|
|
155
|
+
this.loadSharedObserver();
|
|
156
|
+
this.initializeBookSubmenus();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (changed.has('downloadableTypes')) {
|
|
160
|
+
this.initializeBookSubmenus();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
loadSharedObserver() {
|
|
165
|
+
this.unloadSharedObserver();
|
|
166
|
+
this.sharedObserver?.addObserver({
|
|
167
|
+
target: this.mainBRContainer,
|
|
168
|
+
handler: this._sharedObserverHandler,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
unloadSharedObserver() {
|
|
173
|
+
this.sharedObserver?.removeObserver({
|
|
174
|
+
target: this.mainBRContainer,
|
|
175
|
+
handler: this._sharedObserverHandler,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Uses resize observer to fire BookReader's `resize` functionality
|
|
181
|
+
* We do not want to trigger resize IF:
|
|
182
|
+
* - book animation is happening
|
|
183
|
+
* - book is in fullscreen (fullscreen is handled separately)
|
|
184
|
+
*
|
|
185
|
+
* @param { target: HTMLElement, contentRect: DOMRectReadOnly } entry
|
|
186
|
+
*/
|
|
187
|
+
handleResize({ contentRect, target }) {
|
|
188
|
+
const startBrWidth = this._brWidth;
|
|
189
|
+
const startBrHeight = this._brHeight;
|
|
190
|
+
const { animating } = this.bookreader;
|
|
191
|
+
|
|
192
|
+
if (target === this.mainBRContainer) {
|
|
193
|
+
this._brWidth = contentRect.width;
|
|
194
|
+
this._brHeight = contentRect.height;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (!startBrWidth && this._brWidth) {
|
|
198
|
+
// loading up, let's update side menus
|
|
199
|
+
this.initializeBookSubmenus();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const widthChange = startBrWidth !== this._brWidth;
|
|
203
|
+
const heightChange = startBrHeight !== this._brHeight;
|
|
204
|
+
|
|
205
|
+
if (!animating && (widthChange || heightChange)) {
|
|
206
|
+
this.bookreader?.resize();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Manages Fullscreen behavior
|
|
212
|
+
* This makes sure that controls are _always_ in view
|
|
213
|
+
* We need this to accommodate LOAN BAR during fullscreen
|
|
214
|
+
*/
|
|
215
|
+
manageFullScreenBehavior() {
|
|
216
|
+
if (!this.bookreader.options.enableFSLogoShortcut) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
this.fullscreen = this.bookreader.isFullscreen();
|
|
221
|
+
this.dispatchEvent(new CustomEvent('fullscreenStateUpdated', { detail: { fullscreen: this.fullscreen }}));
|
|
222
|
+
if (this.fullscreen) {
|
|
223
|
+
this.addFullscreenShortcut();
|
|
224
|
+
} else {
|
|
225
|
+
this.deleteFullscreenShortcut();
|
|
226
|
+
}
|
|
58
227
|
}
|
|
59
228
|
|
|
60
229
|
/** Creates modal DOM & attaches to `<body>` */
|
|
61
230
|
setModalManager() {
|
|
231
|
+
/** @type {ModalManager} */
|
|
62
232
|
let modalManager = document.querySelector('modal-manager');
|
|
63
233
|
if (!modalManager) {
|
|
64
|
-
modalManager = document.createElement(
|
|
65
|
-
'modal-manager',
|
|
66
|
-
);
|
|
234
|
+
modalManager = /** @type {ModalManager} */(document.createElement('modal-manager'));
|
|
67
235
|
document.body.appendChild(modalManager);
|
|
68
236
|
}
|
|
69
237
|
|
|
70
238
|
this.modal = modalManager;
|
|
71
239
|
}
|
|
72
240
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
241
|
+
/**
|
|
242
|
+
* Instantiates books submenus & their update callbacks
|
|
243
|
+
*
|
|
244
|
+
* NOTE: we are doing our best to scope bookreader's instance.
|
|
245
|
+
* If your submenu provider uses a bookreader instance to read, manually
|
|
246
|
+
* manipulate BookReader, please update ia-bookreader's instance of it
|
|
247
|
+
* to keep it in sync.
|
|
248
|
+
*/
|
|
249
|
+
initializeBookSubmenus() {
|
|
250
|
+
const providers = {
|
|
251
|
+
visualAdjustments: new VisualAdjustmentProvider({
|
|
252
|
+
...this.baseProviderConfig,
|
|
253
|
+
/** Update menu contents */
|
|
254
|
+
onProviderChange: () => {
|
|
255
|
+
this.updateMenuContents();
|
|
256
|
+
},
|
|
257
|
+
}),
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
if (this.baseProviderConfig.item) {
|
|
261
|
+
// Share options currently rely on IA item metadata
|
|
262
|
+
providers.share = new SharingProvider(this.baseProviderConfig);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (this.shouldShowDownloadsMenu()) {
|
|
266
|
+
providers.downloads = new DownloadProvider(this.baseProviderConfig);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Note plugins will never be null-ish in runtime, but some of the unit tests
|
|
270
|
+
// stub BR with a nullish value there.
|
|
271
|
+
if (this.bookreader.options.plugins?.search?.enabled) {
|
|
272
|
+
providers.search = new SearchProvider({
|
|
273
|
+
...this.baseProviderConfig,
|
|
274
|
+
/**
|
|
275
|
+
* Search specific menu updates
|
|
276
|
+
* @param {BookReader} brInstance
|
|
277
|
+
* @param {Partial<{ searchCanceled: boolean, openMenu: boolean }>} searchUpdates
|
|
278
|
+
*/
|
|
279
|
+
onProviderChange: (brInstance = null, searchUpdates = {}) => {
|
|
280
|
+
if (brInstance) {
|
|
281
|
+
/** @type {BookReader} refresh br instance reference */
|
|
282
|
+
this.bookreader = brInstance;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
this.updateMenuContents();
|
|
286
|
+
|
|
287
|
+
if (searchUpdates.openMenu === false) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
78
290
|
|
|
291
|
+
if (this.isWideEnoughToOpenMenu && !searchUpdates?.searchCanceled) {
|
|
292
|
+
/* open side search menu */
|
|
293
|
+
setTimeout(() => {
|
|
294
|
+
this.updateSideMenu('search', 'open');
|
|
295
|
+
}, 0);
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (this.bookreader.options.enableBookmarks) {
|
|
302
|
+
providers.bookmarks = new BookmarksProvider({
|
|
303
|
+
...this.baseProviderConfig,
|
|
304
|
+
onProviderChange: (bookmarks) => {
|
|
305
|
+
const method = Object.keys(bookmarks).length ? 'add' : 'remove';
|
|
306
|
+
this[`${method}MenuShortcut`]('bookmarks');
|
|
307
|
+
this.updateMenuContents();
|
|
308
|
+
},
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// add shortcut for volumes if multipleBooksList exists
|
|
313
|
+
if (this.bookreader.options.enableMultipleBooks) {
|
|
314
|
+
providers.volumes = new ViewableFilesProvider({
|
|
315
|
+
...this.baseProviderConfig,
|
|
316
|
+
onProviderChange: (brInstance = null, volumesUpdates = {}) => {
|
|
317
|
+
if (brInstance) {
|
|
318
|
+
/* refresh br instance reference */
|
|
319
|
+
this.bookreader = brInstance;
|
|
320
|
+
}
|
|
321
|
+
this.updateMenuContents();
|
|
322
|
+
if (this.isWideEnoughToOpenMenu) {
|
|
323
|
+
/* open side search menu */
|
|
324
|
+
setTimeout(() => {
|
|
325
|
+
this.updateSideMenu('volumes', 'open');
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
Object.assign(this.menuProviders, providers);
|
|
333
|
+
this.addMenuShortcut('search');
|
|
334
|
+
this.addMenuShortcut('volumes');
|
|
335
|
+
this.updateMenuContents();
|
|
79
336
|
}
|
|
80
337
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
this.
|
|
84
|
-
this.dispatchEvent(new CustomEvent('loadingStateUpdated', { detail: { loaded }}));
|
|
338
|
+
/** gets element that houses the bookreader in light dom */
|
|
339
|
+
get mainBRContainer() {
|
|
340
|
+
return document.querySelector(this.bookreader?.el);
|
|
85
341
|
}
|
|
86
342
|
|
|
87
|
-
|
|
88
|
-
|
|
343
|
+
get baseProviderConfig() {
|
|
344
|
+
return {
|
|
345
|
+
baseHost: this.baseHost,
|
|
346
|
+
modal: this.modal,
|
|
347
|
+
sharedObserver: this.sharedObserver,
|
|
348
|
+
bookreader: this.bookreader,
|
|
349
|
+
item: this.item,
|
|
350
|
+
signedIn: this.signedIn,
|
|
351
|
+
isAdmin: this.isAdmin,
|
|
352
|
+
/** @type {function(BookReader, object): void} */
|
|
353
|
+
onProviderChange: () => {},
|
|
354
|
+
};
|
|
89
355
|
}
|
|
90
356
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
this.menuContents = updatedContents;
|
|
357
|
+
get isWideEnoughToOpenMenu() {
|
|
358
|
+
return this._brWidth >= 640;
|
|
94
359
|
}
|
|
95
360
|
|
|
96
|
-
|
|
97
|
-
|
|
361
|
+
/**
|
|
362
|
+
* Open side menu
|
|
363
|
+
* @param {string} menuId
|
|
364
|
+
* @param {('open'|'close'|'toggle')} action
|
|
365
|
+
*/
|
|
366
|
+
updateSideMenu(menuId = '', action = 'open') {
|
|
98
367
|
if (!menuId) {
|
|
99
368
|
return;
|
|
100
369
|
}
|
|
@@ -108,45 +377,207 @@ export class IaBookReader extends LitElement {
|
|
|
108
377
|
}
|
|
109
378
|
}
|
|
110
379
|
|
|
380
|
+
/** Fullscreen Shortcut */
|
|
381
|
+
addFullscreenShortcut() {
|
|
382
|
+
this.menuShortcuts.push({
|
|
383
|
+
icon: this.fullscreenShortcut,
|
|
384
|
+
id: 'fullscreen',
|
|
385
|
+
});
|
|
386
|
+
this._sortMenuShortcuts();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
deleteFullscreenShortcut() {
|
|
390
|
+
this.menuShortcuts = this.menuShortcuts
|
|
391
|
+
.filter(s => s.id !== 'fullscreen');
|
|
392
|
+
this._sortMenuShortcuts();
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
get fullscreenShortcut() {
|
|
396
|
+
return html`
|
|
397
|
+
<button
|
|
398
|
+
@click=${() => this.bookreader.exitFullScreen()}
|
|
399
|
+
title="Exit fullscreen view"
|
|
400
|
+
>${this.fullscreenBranding}</button>
|
|
401
|
+
`;
|
|
402
|
+
}
|
|
403
|
+
/** End Fullscreen Shortcut */
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Sets order of menu and emits custom event when done
|
|
407
|
+
*/
|
|
408
|
+
updateMenuContents() {
|
|
409
|
+
const availableMenus = sortBy(
|
|
410
|
+
Object.entries(this.menuProviders)
|
|
411
|
+
.filter(([id, menu]) => !!menu)
|
|
412
|
+
.filter(([id, menu]) => {
|
|
413
|
+
return id === 'downloads' ? this.shouldShowDownloadsMenu() : true;
|
|
414
|
+
}),
|
|
415
|
+
([id, menu]) => {
|
|
416
|
+
const index = this.shortcutOrder.indexOf(id);
|
|
417
|
+
return index === -1 ? this.shortcutOrder.length : index;
|
|
418
|
+
},
|
|
419
|
+
).map(([id, menu]) => menu);
|
|
420
|
+
|
|
421
|
+
if (this.shouldShowDownloadsMenu()) {
|
|
422
|
+
this.menuProviders.downloads?.update(this.downloadableTypes);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
this.menuContents = availableMenus;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Confirms if we should show the downloads menu
|
|
430
|
+
* @returns {boolean}
|
|
431
|
+
*/
|
|
432
|
+
shouldShowDownloadsMenu() {
|
|
433
|
+
if (!this.downloadableTypes.length) { return false; }
|
|
434
|
+
if (this.bookIsRestricted === false) { return true; }
|
|
435
|
+
if (this.isAdmin) { return true; }
|
|
436
|
+
const { user_loan_record = {} } = this.lendingStatus;
|
|
437
|
+
const hasNoLoanRecord = Array.isArray(user_loan_record); /* (bc PHP assoc. arrays) */
|
|
438
|
+
|
|
439
|
+
if (hasNoLoanRecord) { return false; }
|
|
440
|
+
|
|
441
|
+
const hasValidLoan = user_loan_record.type && (user_loan_record.type !== 'SESSION_LOAN');
|
|
442
|
+
return hasValidLoan;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Adds a provider object to the menuShortcuts array property if it isn't
|
|
447
|
+
* already added, then sorts menuShortcuts based on shortcutOrder.
|
|
448
|
+
*
|
|
449
|
+
* @param {string} menuId - a string matching the id property of a provider
|
|
450
|
+
*/
|
|
451
|
+
addMenuShortcut(menuId) {
|
|
452
|
+
if (this.menuShortcuts.find((m) => m.id === menuId)) {
|
|
453
|
+
// menu is already there
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (!this.menuProviders[menuId]) {
|
|
458
|
+
// no provider for this menu
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
this.menuShortcuts.push(this.menuProviders[menuId]);
|
|
463
|
+
this._sortMenuShortcuts();
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Sorts the menuShortcuts property by comparing each provider's id to
|
|
468
|
+
* the id in each iteration over the shortcutOrder array.
|
|
469
|
+
*/
|
|
470
|
+
_sortMenuShortcuts() {
|
|
471
|
+
this.menuShortcuts = sortBy(
|
|
472
|
+
this.menuShortcuts,
|
|
473
|
+
(shortcut) => {
|
|
474
|
+
const index = this.shortcutOrder.indexOf(shortcut.id);
|
|
475
|
+
return index === -1 ? this.shortcutOrder.length : index;
|
|
476
|
+
},
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Core bookreader event handler registry
|
|
482
|
+
*
|
|
483
|
+
* NOTE: we are trying to keep bookreader's instance in scope
|
|
484
|
+
* Please update ia-bookreader's instance reference of it to keep it current
|
|
485
|
+
*/
|
|
486
|
+
_bindEventListeners() {
|
|
487
|
+
window.addEventListener('BookReader:PostInit', /** @param {CustomEvent} e */ (e) => {
|
|
488
|
+
this.bookreader = e.detail.props;
|
|
489
|
+
this.bookreader.shell = this;
|
|
490
|
+
this.bookReaderLoaded = true;
|
|
491
|
+
this.bookReaderCannotLoad = false;
|
|
492
|
+
this.loaded = true;
|
|
493
|
+
this.loadSharedObserver();
|
|
494
|
+
setTimeout(() => this.bookreader.resize(), 0);
|
|
495
|
+
});
|
|
496
|
+
window.addEventListener('BookReader:fullscreenToggled', /** @param {CustomEvent} event */ (event) => {
|
|
497
|
+
const brInstance = event.detail.props;
|
|
498
|
+
if (brInstance) {
|
|
499
|
+
this.bookreader = brInstance;
|
|
500
|
+
}
|
|
501
|
+
this.manageFullScreenBehavior();
|
|
502
|
+
}, { passive: true });
|
|
503
|
+
window.addEventListener('BookReader:ToggleSearchMenu', /** @param {CustomEvent} event */ (event) => {
|
|
504
|
+
this.updateSideMenu('search', 'toggle');
|
|
505
|
+
});
|
|
506
|
+
window.addEventListener('LendingFlow:PostInit', /** @param {CustomEvent} detail */ ({ detail }) => {
|
|
507
|
+
const {
|
|
508
|
+
downloadTypesAvailable, lendingStatus, isAdmin, previewType,
|
|
509
|
+
} = detail;
|
|
510
|
+
this.lendingInitialized = true;
|
|
511
|
+
this.downloadableTypes = downloadTypesAvailable;
|
|
512
|
+
this.lendingStatus = lendingStatus;
|
|
513
|
+
this.isAdmin = isAdmin;
|
|
514
|
+
this.bookReaderCannotLoad = previewType === 'singlePagePreview';
|
|
515
|
+
this.loaded = true;
|
|
516
|
+
});
|
|
517
|
+
window.addEventListener('BRJSIA:PostInit', /** @param {CustomEvent} detail */ ({ detail }) => {
|
|
518
|
+
const { isRestricted, downloadURLs } = detail;
|
|
519
|
+
this.bookReaderLoaded = true;
|
|
520
|
+
this.downloadableTypes = downloadURLs;
|
|
521
|
+
this.bookIsRestricted = isRestricted;
|
|
522
|
+
});
|
|
523
|
+
window.addEventListener('contextmenu', (e) => this._manageContextMenuVisibility(e), { capture: true });
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* @param {PointerEvent} e
|
|
528
|
+
**/
|
|
529
|
+
_manageContextMenuVisibility(e) {
|
|
530
|
+
const target = /** @type {HTMLElement} */(e.target);
|
|
531
|
+
|
|
532
|
+
window['archive_analytics']?.send_event(
|
|
533
|
+
'BookReader',
|
|
534
|
+
`contextmenu-${this.bookIsRestricted ? 'restricted' : 'unrestricted'}`,
|
|
535
|
+
target?.classList?.value,
|
|
536
|
+
);
|
|
537
|
+
if (!this.bookIsRestricted) {
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
const imagePane = target.classList.value.match(/BRscreen|BRpageimage/g);
|
|
542
|
+
if (!imagePane) {
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
e.preventDefault();
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
get itemImage() {
|
|
551
|
+
const identifier = this.item?.metadata.identifier;
|
|
552
|
+
const url = `https://${this.baseHost}/services/img/${identifier}`;
|
|
553
|
+
return html`<img class="cover-img" src=${url} alt="cover image for ${identifier}">`;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
get placeholder() {
|
|
557
|
+
return html`<div class="placeholder">${this.itemImage}</div>`;
|
|
558
|
+
}
|
|
559
|
+
|
|
111
560
|
render() {
|
|
112
561
|
return html`
|
|
113
|
-
<
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
>
|
|
126
|
-
<
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
.baseHost=${this.baseHost}
|
|
133
|
-
.itemMD=${this.item}
|
|
134
|
-
?signedIn=${this.signedIn}
|
|
135
|
-
?sideMenuOpen=${this.menuOpened}
|
|
136
|
-
.sharedObserver=${this.sharedObserver}
|
|
137
|
-
@ViewportInFullScreen=${this.manageFullscreen}
|
|
138
|
-
@loadingStateUpdated=${this.loadingStateUpdated}
|
|
139
|
-
@updateSideMenu=${this.manageSideMenuEvents}
|
|
140
|
-
@menuUpdated=${this.setMenuContents}
|
|
141
|
-
@menuShortcutsUpdated=${this.setMenuShortcuts}
|
|
142
|
-
>
|
|
143
|
-
<div slot="main">
|
|
144
|
-
<slot name="main"></slot>
|
|
145
|
-
</div>
|
|
146
|
-
</book-navigator>
|
|
147
|
-
</div>
|
|
148
|
-
</iaux-item-navigator>
|
|
149
|
-
</div>
|
|
562
|
+
<iaux-item-navigator
|
|
563
|
+
?viewportInFullscreen=${this.fullscreen}
|
|
564
|
+
.basehost=${this.baseHost}
|
|
565
|
+
.item=${this.item}
|
|
566
|
+
.modal=${this.modal}
|
|
567
|
+
.loaded=${this.loaded}
|
|
568
|
+
.sharedObserver=${this.sharedObserver}
|
|
569
|
+
?signedIn=${this.signedIn}
|
|
570
|
+
.menuShortcuts=${this.menuShortcuts}
|
|
571
|
+
.menuContents=${this.menuContents}
|
|
572
|
+
.openMenu=${this.openMenuName}
|
|
573
|
+
>
|
|
574
|
+
<div slot="header">
|
|
575
|
+
<slot name="header"></slot>
|
|
576
|
+
</div>
|
|
577
|
+
<div slot="main">
|
|
578
|
+
${this.bookReaderCannotLoad ? this.placeholder : html`<slot name="main"></slot>`}
|
|
579
|
+
</div>
|
|
580
|
+
</iaux-item-navigator>
|
|
150
581
|
`;
|
|
151
582
|
}
|
|
152
583
|
|
|
@@ -176,12 +607,6 @@ export class IaBookReader extends LitElement {
|
|
|
176
607
|
min-height: unset;
|
|
177
608
|
}
|
|
178
609
|
|
|
179
|
-
.main-component {
|
|
180
|
-
height: 100%;
|
|
181
|
-
width: 100%;
|
|
182
|
-
min-height: inherit;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
610
|
div[slot="header"],
|
|
186
611
|
div[slot="main"] {
|
|
187
612
|
display: flex;
|
|
@@ -193,11 +618,28 @@ export class IaBookReader extends LitElement {
|
|
|
193
618
|
flex: 1;
|
|
194
619
|
}
|
|
195
620
|
|
|
621
|
+
slot,
|
|
622
|
+
slot > * {
|
|
623
|
+
display: block;
|
|
624
|
+
height: inherit;
|
|
625
|
+
width: inherit;
|
|
626
|
+
}
|
|
627
|
+
.placeholder {
|
|
628
|
+
display: flex;
|
|
629
|
+
align-items: center;
|
|
630
|
+
justify-content: center;
|
|
631
|
+
flex-direction: column;
|
|
632
|
+
margin: 5%;
|
|
633
|
+
}
|
|
634
|
+
.cover-img {
|
|
635
|
+
max-height: 300px;
|
|
636
|
+
}
|
|
637
|
+
|
|
196
638
|
iaux-item-navigator {
|
|
197
|
-
min-height: var(--br-height, inherit);
|
|
198
|
-
height: var(--br-height, inherit);
|
|
199
639
|
display: block;
|
|
200
640
|
width: 100%;
|
|
641
|
+
min-height: var(--br-height, inherit);
|
|
642
|
+
height: var(--br-height, 100%);
|
|
201
643
|
color: var(--primaryTextColor);
|
|
202
644
|
--menuButtonLabelDisplay: block;
|
|
203
645
|
--menuWidth: 320px;
|
|
@@ -13,7 +13,10 @@ const sortTypes = {
|
|
|
13
13
|
};
|
|
14
14
|
export default class ViewableFilesProvider {
|
|
15
15
|
/**
|
|
16
|
-
* @param {
|
|
16
|
+
* @param {object} options
|
|
17
|
+
* @param {import('../BookReader').default} options.bookreader
|
|
18
|
+
* @param {string} options.baseHost
|
|
19
|
+
* @param {function} options.onProviderChange
|
|
17
20
|
*/
|
|
18
21
|
constructor({ baseHost, bookreader, onProviderChange }) {
|
|
19
22
|
/** @type {import('../BookReader').default} */
|
package/src/{BookNavigator → ia-bookreader}/visual-adjustments/visual-adjustments-provider.js
RENAMED
|
@@ -29,8 +29,7 @@ const visualAdjustmentOptions = [{
|
|
|
29
29
|
}];
|
|
30
30
|
|
|
31
31
|
export default class VisualAdjustmentsProvider {
|
|
32
|
-
constructor(
|
|
33
|
-
const { onProviderChange, bookreader } = options;
|
|
32
|
+
constructor({ onProviderChange, bookreader }) {
|
|
34
33
|
this.onProviderChange = onProviderChange;
|
|
35
34
|
this.bookContainer = bookreader.refs.$brContainer;
|
|
36
35
|
this.bookreader = bookreader;
|