@internetarchive/bookreader 5.0.0-4 → 5.0.0-40-a1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +17 -15
- package/.github/workflows/node.js.yml +75 -4
- package/.github/workflows/npm-publish.yml +2 -16
- package/.testcaferc.js +10 -0
- package/BookReader/BookReader.css +83 -323
- package/BookReader/BookReader.js +1 -1
- package/BookReader/BookReader.js.LICENSE.txt +24 -0
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +1623 -0
- package/BookReader/{bookreader-component-bundle.js.LICENSE.txt → ia-bookreader-bundle.js.LICENSE.txt} +14 -10
- package/BookReader/ia-bookreader-bundle.js.map +1 -0
- package/BookReader/icons/close-circle-dark.svg +1 -0
- package/BookReader/icons/magnify-minus.svg +1 -1
- package/BookReader/icons/magnify-plus.svg +1 -1
- package/BookReader/icons/voice.svg +1 -0
- package/BookReader/plugins/plugin.archive_analytics.js +1 -1
- package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
- package/BookReader/plugins/plugin.autoplay.js +1 -1
- package/BookReader/plugins/plugin.autoplay.js.map +1 -1
- package/BookReader/plugins/plugin.chapters.js +1 -1
- package/BookReader/plugins/plugin.chapters.js.map +1 -1
- package/BookReader/plugins/plugin.iframe.js +1 -1
- package/BookReader/plugins/plugin.iframe.js.map +1 -1
- package/BookReader/plugins/plugin.mobile_nav.js +1 -1
- package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
- package/BookReader/plugins/plugin.resume.js +1 -1
- package/BookReader/plugins/plugin.resume.js.map +1 -1
- package/BookReader/plugins/plugin.search.js +1 -1
- package/BookReader/plugins/plugin.search.js.map +1 -1
- package/BookReader/plugins/plugin.text_selection.js +1 -1
- package/BookReader/plugins/plugin.text_selection.js.map +1 -1
- package/BookReader/plugins/plugin.tts.js +1 -1
- package/BookReader/plugins/plugin.tts.js.map +1 -1
- package/BookReader/plugins/plugin.url.js +1 -1
- package/BookReader/plugins/plugin.url.js.map +1 -1
- package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
- package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
- package/BookReader/webcomponents-bundle.js +3 -0
- package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
- package/BookReader/webcomponents-bundle.js.map +1 -0
- package/BookReaderDemo/BookReaderDemo.css +14 -1
- package/BookReaderDemo/IADemoBr.js +120 -0
- package/BookReaderDemo/demo-advanced.html +1 -1
- package/BookReaderDemo/demo-autoplay.html +1 -0
- package/BookReaderDemo/demo-embed-iframe-src.html +1 -0
- package/BookReaderDemo/demo-fullscreen-mobile.html +1 -0
- package/BookReaderDemo/demo-fullscreen.html +1 -0
- package/BookReaderDemo/demo-iiif.html +1 -0
- package/BookReaderDemo/demo-internetarchive.html +74 -17
- package/BookReaderDemo/demo-multiple.html +1 -0
- package/BookReaderDemo/demo-preview-pages.html +1 -0
- package/BookReaderDemo/demo-simple.html +1 -0
- package/BookReaderDemo/demo-vendor-fullscreen.html +1 -0
- package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
- package/BookReaderDemo/immersion-1up.html +1 -0
- package/BookReaderDemo/immersion-mode.html +1 -0
- package/BookReaderDemo/toggle_controls.html +1 -0
- package/BookReaderDemo/view_mode.html +1 -0
- package/BookReaderDemo/viewmode-cycle.html +1 -2
- package/CHANGELOG.md +166 -0
- package/README.md +14 -1
- package/babel.config.js +18 -0
- package/codecov.yml +6 -0
- package/index.html +3 -0
- package/jsconfig.json +19 -0
- package/package.json +62 -47
- package/renovate.json +43 -0
- package/src/BookNavigator/assets/bookmark-colors.js +1 -1
- package/src/BookNavigator/assets/button-base.js +9 -2
- package/src/BookNavigator/assets/ia-logo.js +17 -0
- package/src/BookNavigator/assets/icon_checkmark.js +1 -1
- package/src/BookNavigator/assets/icon_close.js +1 -1
- package/src/BookNavigator/assets/icon_sort_asc.js +5 -0
- package/src/BookNavigator/assets/icon_sort_desc.js +5 -0
- package/src/BookNavigator/assets/icon_sort_neutral.js +5 -0
- package/src/BookNavigator/assets/icon_volumes.js +11 -0
- package/src/BookNavigator/book-navigator.js +556 -0
- package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
- package/src/BookNavigator/bookmarks/bookmark-edit.js +4 -4
- package/src/BookNavigator/bookmarks/bookmarks-list.js +3 -3
- package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
- package/src/BookNavigator/bookmarks/bookmarks-provider.js +23 -12
- package/src/BookNavigator/bookmarks/ia-bookmarks.js +98 -62
- package/src/BookNavigator/delete-modal-actions.js +1 -1
- package/src/BookNavigator/downloads/downloads-provider.js +23 -17
- package/src/BookNavigator/downloads/downloads.js +17 -25
- package/src/BookNavigator/search/a-search-result.js +3 -3
- package/src/BookNavigator/search/search-provider.js +57 -24
- package/src/BookNavigator/search/search-results.js +8 -20
- package/src/BookNavigator/sharing.js +27 -0
- package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -13
- package/src/BookNavigator/visual-adjustments/visual-adjustments.js +4 -3
- package/src/BookNavigator/volumes/volumes-provider.js +114 -0
- package/src/BookNavigator/volumes/volumes.js +188 -0
- package/src/BookReader/DebugConsole.js +3 -3
- package/src/BookReader/DragScrollable.js +233 -0
- package/src/BookReader/Mode1Up.js +51 -351
- package/src/BookReader/Mode1UpLit.js +441 -0
- package/src/BookReader/Mode2Up.js +104 -71
- package/src/BookReader/ModeSmoothZoom.js +179 -0
- package/src/BookReader/ModeThumb.js +16 -8
- package/src/BookReader/Navbar/Navbar.js +2 -31
- package/src/BookReader/PageContainer.js +57 -6
- package/src/BookReader/ReduceSet.js +1 -1
- package/src/BookReader/Toolbar/Toolbar.js +7 -7
- package/src/BookReader/options.js +10 -0
- package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
- package/src/BookReader/utils/ScrollClassAdder.js +31 -0
- package/src/BookReader/utils.js +68 -13
- package/src/BookReader.js +375 -289
- package/src/assets/icons/close-circle-dark.svg +1 -0
- package/src/assets/icons/magnify-minus.svg +3 -7
- package/src/assets/icons/magnify-plus.svg +3 -7
- package/src/assets/icons/voice.svg +1 -0
- package/src/css/BookReader.scss +0 -12
- package/src/css/_BRComponent.scss +1 -1
- package/src/css/_BRmain.scss +19 -24
- package/src/css/_BRnav.scss +4 -26
- package/src/css/_BRpages.scss +35 -0
- package/src/css/_BRsearch.scss +11 -215
- package/src/css/_TextSelection.scss +14 -17
- package/src/css/_colorbox.scss +2 -2
- package/src/css/_controls.scss +16 -3
- package/src/css/_icons.scss +6 -0
- package/src/ia-bookreader/ia-bookreader.js +224 -0
- package/src/plugins/plugin.chapters.js +26 -33
- package/src/plugins/plugin.mobile_nav.js +11 -10
- package/src/plugins/plugin.resume.js +3 -3
- package/src/plugins/plugin.text_selection.js +26 -39
- package/src/plugins/plugin.vendor-fullscreen.js +4 -4
- package/src/plugins/search/plugin.search.js +106 -107
- package/src/plugins/search/view.js +50 -163
- package/src/plugins/tts/AbstractTTSEngine.js +46 -37
- package/src/plugins/tts/FestivalTTSEngine.js +12 -13
- package/src/plugins/tts/PageChunk.js +15 -21
- package/src/plugins/tts/PageChunkIterator.js +8 -12
- package/src/plugins/tts/WebTTSEngine.js +64 -68
- package/src/plugins/tts/plugin.tts.js +79 -108
- package/src/plugins/url/UrlPlugin.js +184 -0
- package/src/plugins/{plugin.url.js → url/plugin.url.js} +28 -6
- package/tests/e2e/README.md +37 -0
- package/tests/e2e/autoplay.test.js +2 -2
- package/tests/e2e/base.test.js +7 -7
- package/tests/e2e/helpers/base.js +8 -3
- package/tests/e2e/helpers/debug.js +1 -1
- package/tests/e2e/helpers/desktopSearch.js +14 -13
- package/tests/e2e/helpers/mobileSearch.js +3 -3
- package/tests/e2e/helpers/params.js +17 -0
- package/tests/e2e/models/Navigation.js +12 -3
- package/tests/e2e/rightToLeft.test.js +4 -5
- package/tests/e2e/viewmode.test.js +38 -33
- package/tests/{BookReader → jest/BookReader}/BookModel.test.js +3 -3
- package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +176 -0
- package/tests/{BookReader → jest/BookReader}/DebugConsole.test.js +1 -1
- package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
- package/tests/jest/BookReader/Mode1UpLit.test.js +88 -0
- package/tests/{BookReader → jest/BookReader}/Mode2Up.test.js +5 -7
- package/tests/jest/BookReader/ModeSmoothZoom.test.js +149 -0
- package/tests/jest/BookReader/ModeThumb.test.js +71 -0
- package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +7 -7
- package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +79 -6
- package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
- package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
- package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
- package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
- package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
- package/tests/jest/BookReader/utils.test.js +136 -0
- package/tests/jest/BookReader.keyboard.test.js +190 -0
- package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
- package/tests/{BookReader.test.js → jest/BookReader.test.js} +20 -4
- package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.chapters.test.js +8 -8
- package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.mobile_nav.test.js +5 -5
- package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
- package/tests/{plugins → jest/plugins}/plugin.text_selection.test.js +39 -47
- package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
- package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +24 -25
- package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +6 -6
- package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +6 -6
- package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
- package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
- package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
- package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +1 -1
- package/tests/{plugins → jest/plugins}/tts/utils.test.js +3 -3
- package/tests/jest/plugins/url/UrlPlugin.test.js +190 -0
- package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +33 -14
- package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
- package/tests/{util → jest/util}/docCookies.test.js +1 -1
- package/tests/{util → jest/util}/strings.test.js +1 -1
- package/tests/{utils.js → jest/utils.js} +38 -0
- package/tests/karma/BookNavigator/book-navigator.test.js +501 -0
- package/tests/karma/BookNavigator/bookmarks/bookmark-button.test.js +44 -0
- package/tests/karma/BookNavigator/bookmarks/bookmark-edit.test.js +1 -3
- package/tests/karma/BookNavigator/bookmarks/bookmarks-list.test.js +3 -4
- package/tests/karma/BookNavigator/bookmarks/ia-bookmarks.test.js +57 -0
- package/tests/karma/BookNavigator/downloads/downloads-provider.test.js +67 -0
- package/tests/karma/BookNavigator/downloads/downloads.test.js +54 -0
- package/tests/karma/BookNavigator/search/search-provider.test.js +123 -0
- package/tests/karma/BookNavigator/{search-results.test.js → search/search-results.test.js} +1 -4
- package/tests/karma/BookNavigator/sharing/sharing-provider.test.js +49 -0
- package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -2
- package/tests/karma/BookNavigator/volumes/volumes-provider.test.js +184 -0
- package/tests/karma/BookNavigator/volumes/volumes.test.js +98 -0
- package/webpack.config.js +10 -4
- package/.babelrc +0 -12
- package/.dependabot/config.yml +0 -6
- package/.testcaferc.json +0 -5
- package/BookReader/bookreader-component-bundle.js +0 -1450
- package/BookReader/bookreader-component-bundle.js.map +0 -1
- package/BookReader/plugins/plugin.menu_toggle.js +0 -2
- package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
- package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
- package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
- package/src/BookNavigator/BookModel.js +0 -14
- package/src/BookNavigator/BookNavigator.js +0 -435
- package/src/BookNavigator/assets/book-loader.js +0 -27
- package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
- package/src/BookReaderComponent/BookReaderComponent.js +0 -112
- package/src/ItemNavigator/ItemNavigator.js +0 -372
- package/src/ItemNavigator/providers/sharing.js +0 -29
- package/src/dragscrollable-br.js +0 -261
- package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
- package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
- package/tests/BookReader/Mode1Up.test.js +0 -164
- package/tests/BookReader/utils.test.js +0 -109
- package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
@@ -0,0 +1,556 @@
|
|
1
|
+
// eslint-disable-next-line no-unused-vars
|
2
|
+
import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
|
3
|
+
// eslint-disable-next-line no-unused-vars
|
4
|
+
import { ModalManager } from '@internetarchive/modal-manager';
|
5
|
+
import { css, html, LitElement, nothing } from 'lit';
|
6
|
+
import SearchProvider from './search/search-provider.js';
|
7
|
+
import DownloadProvider from './downloads/downloads-provider.js';
|
8
|
+
import VisualAdjustmentProvider from './visual-adjustments/visual-adjustments-provider.js';
|
9
|
+
import BookmarksProvider from './bookmarks/bookmarks-provider.js';
|
10
|
+
import SharingProvider from './sharing.js';
|
11
|
+
import VolumesProvider from './volumes/volumes-provider.js';
|
12
|
+
import iaLogo from './assets/ia-logo.js';
|
13
|
+
|
14
|
+
const events = {
|
15
|
+
menuUpdated: 'menuUpdated',
|
16
|
+
updateSideMenu: 'updateSideMenu',
|
17
|
+
PostInit: 'PostInit',
|
18
|
+
ViewportInFullScreen: 'ViewportInFullScreen',
|
19
|
+
};
|
20
|
+
export class BookNavigator extends LitElement {
|
21
|
+
static get properties() {
|
22
|
+
return {
|
23
|
+
itemMD: { type: Object },
|
24
|
+
bookReaderLoaded: { type: Boolean },
|
25
|
+
bookreader: { type: Object },
|
26
|
+
bookIsRestricted: { type: Boolean },
|
27
|
+
downloadableTypes: { type: Array },
|
28
|
+
isAdmin: { type: Boolean },
|
29
|
+
lendingInitialized: { type: Boolean },
|
30
|
+
lendingStatus: { type: Object },
|
31
|
+
menuProviders: { type: Object },
|
32
|
+
menuShortcuts: { type: Array },
|
33
|
+
signedIn: { type: Boolean },
|
34
|
+
loaded: { type: Boolean },
|
35
|
+
sharedObserver: { type: Object, attribute: false },
|
36
|
+
modal: { type: Object, attribute: false },
|
37
|
+
fullscreenBranding: { type: Object },
|
38
|
+
};
|
39
|
+
}
|
40
|
+
|
41
|
+
constructor() {
|
42
|
+
super();
|
43
|
+
this.itemMD = undefined;
|
44
|
+
this.loaded = false;
|
45
|
+
this.bookReaderCannotLoad = false;
|
46
|
+
this.bookReaderLoaded = false;
|
47
|
+
this.bookreader = null;
|
48
|
+
this.bookIsRestricted = false;
|
49
|
+
this.downloadableTypes = [];
|
50
|
+
this.isAdmin = false;
|
51
|
+
this.lendingInitialized = false;
|
52
|
+
this.lendingStatus = {};
|
53
|
+
this.menuProviders = {};
|
54
|
+
this.menuShortcuts = [];
|
55
|
+
this.signedIn = false;
|
56
|
+
/** @type {ModalManager} */
|
57
|
+
this.modal = undefined;
|
58
|
+
/** @type {SharedResizeObserver} */
|
59
|
+
this.sharedObserver = undefined;
|
60
|
+
this.fullscreenBranding = iaLogo;
|
61
|
+
// Untracked properties
|
62
|
+
this.sharedObserverHandler = undefined;
|
63
|
+
this.brWidth = 0;
|
64
|
+
this.brHeight = 0;
|
65
|
+
this.shortcutOrder = [
|
66
|
+
/**
|
67
|
+
* sets exit FS button (`this.fullscreenBranding1)
|
68
|
+
* when `br.options.enableFSLogoShortcut`
|
69
|
+
*/
|
70
|
+
'fullscreen',
|
71
|
+
'volumes',
|
72
|
+
'search',
|
73
|
+
'bookmarks'
|
74
|
+
];
|
75
|
+
}
|
76
|
+
|
77
|
+
disconnectedCallback() {
|
78
|
+
this.sharedObserver.removeObserver({
|
79
|
+
target: this.mainBRContainer,
|
80
|
+
handler: this.sharedObserverHandler
|
81
|
+
});
|
82
|
+
}
|
83
|
+
|
84
|
+
firstUpdated() {
|
85
|
+
this.bindEventListeners();
|
86
|
+
this.emitPostInit();
|
87
|
+
this.loaded = true;
|
88
|
+
}
|
89
|
+
|
90
|
+
updated(changed) {
|
91
|
+
if (!this.bookreader || !this.itemMD || !this.bookReaderLoaded) {
|
92
|
+
return;
|
93
|
+
}
|
94
|
+
|
95
|
+
const reload = changed.has('loaded') && this.loaded;
|
96
|
+
if (reload
|
97
|
+
|| changed.has('itemMD')
|
98
|
+
|| changed.has('bookreader')
|
99
|
+
|| changed.has('signedIn')
|
100
|
+
|| changed.has('isAdmin')
|
101
|
+
|| changed.has('modal')) {
|
102
|
+
this.initializeBookSubmenus();
|
103
|
+
}
|
104
|
+
|
105
|
+
if (changed.has('sharedObserver') && this.bookreader) {
|
106
|
+
this.loadSharedObserver();
|
107
|
+
this.initializeBookSubmenus();
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
/**
|
112
|
+
* Global event emitter for when Book Navigator loads
|
113
|
+
*/
|
114
|
+
emitPostInit() {
|
115
|
+
// emit global event when book nav has loaded with current bookreader selector
|
116
|
+
this.dispatchEvent(new CustomEvent(`BrBookNav:${events.PostInit}`, {
|
117
|
+
detail: { brSelector: this.bookreader?.el },
|
118
|
+
bubbles: true,
|
119
|
+
composed: true,
|
120
|
+
}));
|
121
|
+
}
|
122
|
+
|
123
|
+
/**
|
124
|
+
* @typedef {{
|
125
|
+
* baseHost: string,
|
126
|
+
* modal: ModalManager,
|
127
|
+
* sharedObserver: SharedResizeObserver,
|
128
|
+
* bookreader: BookReader,
|
129
|
+
* item: Item,
|
130
|
+
* signedIn: boolean,
|
131
|
+
* isAdmin: boolean,
|
132
|
+
* onProviderChange: (BookReader, object) => void,
|
133
|
+
* }} baseProviderConfig
|
134
|
+
*
|
135
|
+
* @return {baseProviderConfig}
|
136
|
+
*/
|
137
|
+
get baseProviderConfig() {
|
138
|
+
return {
|
139
|
+
baseHost: this.baseHost,
|
140
|
+
modal: this.modal,
|
141
|
+
sharedObserver: this.sharedObserver,
|
142
|
+
bookreader: this.bookreader,
|
143
|
+
item: this.itemMD,
|
144
|
+
signedIn: this.signedIn,
|
145
|
+
isAdmin: this.isAdmin,
|
146
|
+
onProviderChange: () => {}
|
147
|
+
};
|
148
|
+
}
|
149
|
+
|
150
|
+
get isWideEnoughToOpenMenu() {
|
151
|
+
return this.brWidth >= 640;
|
152
|
+
}
|
153
|
+
/**
|
154
|
+
* Instantiates books submenus & their update callbacks
|
155
|
+
*
|
156
|
+
* NOTE: we are doing our best to scope bookreader's instance.
|
157
|
+
* If your submenu provider uses a bookreader instance to read, manually
|
158
|
+
* manipulate BookReader, please update the navigator's instance of it
|
159
|
+
* to keep it in sync.
|
160
|
+
*/
|
161
|
+
initializeBookSubmenus() {
|
162
|
+
const providers = {
|
163
|
+
downloads: new DownloadProvider(this.baseProviderConfig),
|
164
|
+
share: new SharingProvider(this.baseProviderConfig),
|
165
|
+
visualAdjustments: new VisualAdjustmentProvider({
|
166
|
+
...this.baseProviderConfig,
|
167
|
+
/** Update menu contents */
|
168
|
+
onProviderChange: () => {
|
169
|
+
this.updateMenuContents();
|
170
|
+
},
|
171
|
+
}),
|
172
|
+
};
|
173
|
+
|
174
|
+
if (this.bookreader.options.enableSearch) {
|
175
|
+
providers.search = new SearchProvider({
|
176
|
+
...this.baseProviderConfig,
|
177
|
+
/**
|
178
|
+
* Search specific menu updates
|
179
|
+
* @param {BookReader} brInstance
|
180
|
+
* @param {{ searchCanceled: boolean }} searchUpdates
|
181
|
+
*/
|
182
|
+
onProviderChange: (brInstance = null, searchUpdates = {}) => {
|
183
|
+
if (brInstance) {
|
184
|
+
/* refresh br instance reference */
|
185
|
+
this.bookreader = brInstance;
|
186
|
+
}
|
187
|
+
|
188
|
+
this.updateMenuContents();
|
189
|
+
|
190
|
+
if (searchUpdates.openMenu === false) {
|
191
|
+
return;
|
192
|
+
}
|
193
|
+
|
194
|
+
if (this.isWideEnoughToOpenMenu && !searchUpdates?.searchCanceled) {
|
195
|
+
/* open side search menu */
|
196
|
+
setTimeout(() => {
|
197
|
+
this.updateSideMenu('search', 'open');
|
198
|
+
}, 0);
|
199
|
+
}
|
200
|
+
},
|
201
|
+
});
|
202
|
+
}
|
203
|
+
|
204
|
+
if (this.bookreader.options.enableBookmarks) {
|
205
|
+
providers.bookmarks = new BookmarksProvider({
|
206
|
+
...this.baseProviderConfig,
|
207
|
+
onProviderChange: (bookmarks) => {
|
208
|
+
const method = Object.keys(bookmarks).length ? 'add' : 'remove';
|
209
|
+
this[`${method}MenuShortcut`]('bookmarks');
|
210
|
+
this.updateMenuContents();
|
211
|
+
}
|
212
|
+
});
|
213
|
+
}
|
214
|
+
|
215
|
+
// add shortcut for volumes if multipleBooksList exists
|
216
|
+
if (this.bookreader.options.enableMultipleBooks) {
|
217
|
+
providers.volumes = new VolumesProvider({
|
218
|
+
...this.baseProviderConfig,
|
219
|
+
onProviderChange: (brInstance = null, volumesUpdates = {}) => {
|
220
|
+
if (brInstance) {
|
221
|
+
/* refresh br instance reference */
|
222
|
+
this.bookreader = brInstance;
|
223
|
+
}
|
224
|
+
this.updateMenuContents();
|
225
|
+
if (this.isWideEnoughToOpenMenu) {
|
226
|
+
/* open side search menu */
|
227
|
+
setTimeout(() => {
|
228
|
+
this.updateSideMenu('volumes', 'open');
|
229
|
+
});
|
230
|
+
}
|
231
|
+
}
|
232
|
+
});
|
233
|
+
}
|
234
|
+
|
235
|
+
this.menuProviders = providers;
|
236
|
+
this.addMenuShortcut('search');
|
237
|
+
this.addMenuShortcut('volumes');
|
238
|
+
this.updateMenuContents();
|
239
|
+
}
|
240
|
+
|
241
|
+
/** gets element that houses the bookreader in light dom */
|
242
|
+
get mainBRContainer() {
|
243
|
+
return document.querySelector(this.bookreader?.el);
|
244
|
+
}
|
245
|
+
|
246
|
+
/** Fullscreen Shortcut */
|
247
|
+
addFullscreenShortcut() {
|
248
|
+
const closeFS = {
|
249
|
+
icon: this.fullscreenShortcut,
|
250
|
+
id: 'fullscreen',
|
251
|
+
};
|
252
|
+
this.menuShortcuts.push(closeFS);
|
253
|
+
this.sortMenuShortcuts();
|
254
|
+
this.emitMenuShortcutsUpdated();
|
255
|
+
}
|
256
|
+
|
257
|
+
deleteFullscreenShortcut() {
|
258
|
+
const updatedShortcuts = this.menuShortcuts.filter(({ id }) => {
|
259
|
+
return id !== 'fullscreen';
|
260
|
+
});
|
261
|
+
this.menuShortcuts = updatedShortcuts;
|
262
|
+
this.sortMenuShortcuts();
|
263
|
+
this.emitMenuShortcutsUpdated();
|
264
|
+
}
|
265
|
+
|
266
|
+
closeFullscreen() {
|
267
|
+
this.bookreader.exitFullScreen();
|
268
|
+
}
|
269
|
+
|
270
|
+
get fullscreenShortcut() {
|
271
|
+
return html`
|
272
|
+
<button
|
273
|
+
@click=${() => this.closeFullscreen()}
|
274
|
+
title="Exit fullscreen view"
|
275
|
+
>${this.fullscreenBranding}</button>
|
276
|
+
`;
|
277
|
+
}
|
278
|
+
/** End Fullscreen Shortcut */
|
279
|
+
|
280
|
+
/**
|
281
|
+
* Open side menu
|
282
|
+
* @param {string} menuId
|
283
|
+
* @param {('open'|'close'|'toggle')} action
|
284
|
+
*/
|
285
|
+
updateSideMenu(menuId = '', action = 'open') {
|
286
|
+
if (!menuId) {
|
287
|
+
return;
|
288
|
+
}
|
289
|
+
const event = new CustomEvent(
|
290
|
+
events.updateSideMenu, {
|
291
|
+
detail: { menuId, action },
|
292
|
+
},
|
293
|
+
);
|
294
|
+
this.dispatchEvent(event);
|
295
|
+
}
|
296
|
+
|
297
|
+
/**
|
298
|
+
* Sets order of menu and emits custom event when done
|
299
|
+
*/
|
300
|
+
updateMenuContents() {
|
301
|
+
const {
|
302
|
+
search, downloads, visualAdjustments, share, bookmarks, volumes
|
303
|
+
} = this.menuProviders;
|
304
|
+
const availableMenus = [volumes, search, bookmarks, visualAdjustments, share].filter((menu) => !!menu);
|
305
|
+
|
306
|
+
if (this.shouldShowDownloadsMenu()) {
|
307
|
+
downloads?.update(this.downloadableTypes);
|
308
|
+
availableMenus.splice(1, 0, downloads);
|
309
|
+
}
|
310
|
+
|
311
|
+
const event = new CustomEvent(
|
312
|
+
events.menuUpdated, {
|
313
|
+
detail: availableMenus,
|
314
|
+
},
|
315
|
+
);
|
316
|
+
this.dispatchEvent(event);
|
317
|
+
}
|
318
|
+
|
319
|
+
/**
|
320
|
+
* Confirms if we should show the downloads menu
|
321
|
+
* @returns {bool}
|
322
|
+
*/
|
323
|
+
shouldShowDownloadsMenu() {
|
324
|
+
if (this.bookIsRestricted === false) { return true; }
|
325
|
+
if (this.isAdmin) { return true; }
|
326
|
+
const { user_loan_record = {} } = this.lendingStatus;
|
327
|
+
const hasNoLoanRecord = Array.isArray(user_loan_record); /* (bc PHP assoc. arrays) */
|
328
|
+
|
329
|
+
if (hasNoLoanRecord) { return false; }
|
330
|
+
|
331
|
+
const hasValidLoan = user_loan_record.type && (user_loan_record.type !== 'SESSION_LOAN');
|
332
|
+
return hasValidLoan;
|
333
|
+
}
|
334
|
+
|
335
|
+
/**
|
336
|
+
* Adds a provider object to the menuShortcuts array property if it isn't
|
337
|
+
* already added. menuShortcuts are then sorted by shortcutOrder and
|
338
|
+
* a menuShortcutsUpdated event is emitted.
|
339
|
+
*
|
340
|
+
* @param {string} menuId - a string matching the id property of a provider
|
341
|
+
*/
|
342
|
+
addMenuShortcut(menuId) {
|
343
|
+
if (this.menuShortcuts.find((m) => m.id === menuId)) {
|
344
|
+
// menu is already there
|
345
|
+
return;
|
346
|
+
}
|
347
|
+
|
348
|
+
if (!this.menuProviders[menuId]) {
|
349
|
+
// no provider for this menu
|
350
|
+
return;
|
351
|
+
}
|
352
|
+
|
353
|
+
this.menuShortcuts.push(this.menuProviders[menuId]);
|
354
|
+
|
355
|
+
this.sortMenuShortcuts();
|
356
|
+
this.emitMenuShortcutsUpdated();
|
357
|
+
}
|
358
|
+
|
359
|
+
/**
|
360
|
+
* Removes a provider object from the menuShortcuts array and emits a
|
361
|
+
* menuShortcutsUpdated event.
|
362
|
+
*
|
363
|
+
* @param {string} menuId - a string matching the id property of a provider
|
364
|
+
*/
|
365
|
+
removeMenuShortcut(menuId) {
|
366
|
+
this.menuShortcuts = this.menuShortcuts.filter((m) => m.id !== menuId);
|
367
|
+
this.emitMenuShortcutsUpdated();
|
368
|
+
}
|
369
|
+
|
370
|
+
/**
|
371
|
+
* Sorts the menuShortcuts property by comparing each provider's id to
|
372
|
+
* the id in each iteration over the shortcutOrder array.
|
373
|
+
*/
|
374
|
+
sortMenuShortcuts() {
|
375
|
+
this.menuShortcuts = this.shortcutOrder.reduce((shortcuts, id) => {
|
376
|
+
const menu = this.menuShortcuts.find((m) => m.id === id);
|
377
|
+
if (menu) { shortcuts.push(menu); }
|
378
|
+
return shortcuts;
|
379
|
+
}, []);
|
380
|
+
}
|
381
|
+
|
382
|
+
emitMenuShortcutsUpdated() {
|
383
|
+
const event = new CustomEvent('menuShortcutsUpdated', {
|
384
|
+
detail: this.menuShortcuts,
|
385
|
+
});
|
386
|
+
this.dispatchEvent(event);
|
387
|
+
}
|
388
|
+
|
389
|
+
emitLoadingStatusUpdate(loaded) {
|
390
|
+
const event = new CustomEvent('loadingStateUpdated', {
|
391
|
+
detail: { loaded },
|
392
|
+
});
|
393
|
+
this.dispatchEvent(event);
|
394
|
+
}
|
395
|
+
|
396
|
+
/**
|
397
|
+
* Core bookreader event handler registry
|
398
|
+
*
|
399
|
+
* NOTE: we are trying to keep bookreader's instance in scope
|
400
|
+
* Please update Book Navigator's instance reference of it to keep it current
|
401
|
+
*/
|
402
|
+
bindEventListeners() {
|
403
|
+
window.addEventListener('BookReader:PostInit', (e) => {
|
404
|
+
this.bookreader = e.detail.props;
|
405
|
+
this.bookReaderLoaded = true;
|
406
|
+
this.bookReaderCannotLoad = false;
|
407
|
+
this.emitLoadingStatusUpdate(true);
|
408
|
+
this.loadSharedObserver();
|
409
|
+
setTimeout(() => {
|
410
|
+
this.bookreader.resize();
|
411
|
+
}, 0);
|
412
|
+
});
|
413
|
+
window.addEventListener('BookReader:fullscreenToggled', (event) => {
|
414
|
+
const { detail: { props: brInstance = null } } = event;
|
415
|
+
if (brInstance) {
|
416
|
+
this.bookreader = brInstance;
|
417
|
+
}
|
418
|
+
this.manageFullScreenBehavior();
|
419
|
+
}, { passive: true });
|
420
|
+
window.addEventListener('BookReader:ToggleSearchMenu', (event) => {
|
421
|
+
this.dispatchEvent(new CustomEvent(events.updateSideMenu, {
|
422
|
+
detail: { menuId: 'search', action: 'toggle' },
|
423
|
+
}));
|
424
|
+
});
|
425
|
+
window.addEventListener('LendingFlow:PostInit', ({ detail }) => {
|
426
|
+
const {
|
427
|
+
downloadTypesAvailable, lendingStatus, isAdmin, previewType,
|
428
|
+
} = detail;
|
429
|
+
this.lendingInitialized = true;
|
430
|
+
this.downloadableTypes = downloadTypesAvailable;
|
431
|
+
this.lendingStatus = lendingStatus;
|
432
|
+
this.isAdmin = isAdmin;
|
433
|
+
this.bookReaderCannotLoad = previewType === 'singlePagePreview';
|
434
|
+
this.emitLoadingStatusUpdate(true);
|
435
|
+
});
|
436
|
+
window.addEventListener('BRJSIA:PostInit', ({ detail }) => {
|
437
|
+
const { isRestricted, downloadURLs } = detail;
|
438
|
+
this.bookReaderLoaded = true;
|
439
|
+
this.downloadableTypes = downloadURLs;
|
440
|
+
this.bookIsRestricted = isRestricted;
|
441
|
+
});
|
442
|
+
}
|
443
|
+
|
444
|
+
loadSharedObserver() {
|
445
|
+
this.sharedObserverHandler = { handleResize: this.handleResize.bind(this) };
|
446
|
+
this.sharedObserver?.addObserver({
|
447
|
+
target: this.mainBRContainer,
|
448
|
+
handler: this.sharedObserverHandler
|
449
|
+
});
|
450
|
+
}
|
451
|
+
|
452
|
+
/**
|
453
|
+
* Uses resize observer to fire BookReader's `resize` functionality
|
454
|
+
* We do not want to trigger resize IF:
|
455
|
+
* - book animation is happening
|
456
|
+
* - book is in fullscreen (fullscreen is handled separately)
|
457
|
+
*
|
458
|
+
* @param { target: HTMLElement, contentRect: DOMRectReadOnly } entry
|
459
|
+
*/
|
460
|
+
handleResize({ contentRect, target }) {
|
461
|
+
const startBrWidth = this.brWidth;
|
462
|
+
const startBrHeight = this.brHeight;
|
463
|
+
const { animating } = this.bookreader;
|
464
|
+
|
465
|
+
if (target === this.mainBRContainer) {
|
466
|
+
this.brWidth = contentRect.width;
|
467
|
+
this.brHeight = contentRect.height;
|
468
|
+
}
|
469
|
+
|
470
|
+
if (!startBrWidth && this.brWidth) {
|
471
|
+
// loading up, let's update side menus
|
472
|
+
this.initializeBookSubmenus();
|
473
|
+
}
|
474
|
+
|
475
|
+
const widthChange = startBrWidth !== this.brWidth;
|
476
|
+
const heightChange = startBrHeight !== this.brHeight;
|
477
|
+
|
478
|
+
if (!animating && (widthChange || heightChange)) {
|
479
|
+
this.bookreader?.resize();
|
480
|
+
}
|
481
|
+
}
|
482
|
+
|
483
|
+
/**
|
484
|
+
* Manages Fullscreen behavior
|
485
|
+
* This makes sure that controls are _always_ in view
|
486
|
+
* We need this to accommodate LOAN BAR during fullscreen
|
487
|
+
*/
|
488
|
+
manageFullScreenBehavior() {
|
489
|
+
this.emitFullScreenState();
|
490
|
+
|
491
|
+
if (!this.bookreader.options.enableFSLogoShortcut) {
|
492
|
+
return;
|
493
|
+
}
|
494
|
+
|
495
|
+
const isFullScreen = this.bookreader.isFullscreen();
|
496
|
+
if (isFullScreen) {
|
497
|
+
this.addFullscreenShortcut();
|
498
|
+
} else {
|
499
|
+
this.deleteFullscreenShortcut();
|
500
|
+
}
|
501
|
+
}
|
502
|
+
|
503
|
+
/**
|
504
|
+
* Relays fullscreen toggle events
|
505
|
+
*/
|
506
|
+
emitFullScreenState() {
|
507
|
+
const isFullScreen = this.bookreader.isFullscreen();
|
508
|
+
const event = new CustomEvent('ViewportInFullScreen', {
|
509
|
+
detail: { isFullScreen },
|
510
|
+
});
|
511
|
+
this.dispatchEvent(event);
|
512
|
+
}
|
513
|
+
|
514
|
+
get itemImage() {
|
515
|
+
const identifier = this.itemMD?.metadata.identifier;
|
516
|
+
const url = `https://${this.baseHost}/services/img/${identifier}`;
|
517
|
+
return html`<img class="cover-img" src=${url} alt="cover image for ${identifier}">`;
|
518
|
+
}
|
519
|
+
|
520
|
+
get placeholder() {
|
521
|
+
return html`<div class="placeholder">${this.itemImage}</div>`;
|
522
|
+
}
|
523
|
+
|
524
|
+
render() {
|
525
|
+
return html`<div id="book-navigator__root">
|
526
|
+
${this.bookReaderCannotLoad ? this.placeholder : nothing}
|
527
|
+
${!this.bookReaderCannotLoad ? html`<slot name="main"></slot>` : nothing}
|
528
|
+
</div>
|
529
|
+
`;
|
530
|
+
}
|
531
|
+
|
532
|
+
static get styles() {
|
533
|
+
return css`
|
534
|
+
:host,
|
535
|
+
#book-navigator__root,
|
536
|
+
slot,
|
537
|
+
slot > * {
|
538
|
+
display: block;
|
539
|
+
height: inherit;
|
540
|
+
width: inherit;
|
541
|
+
}
|
542
|
+
.placeholder {
|
543
|
+
display: flex;
|
544
|
+
align-items: center;
|
545
|
+
justify-content: center;
|
546
|
+
flex-direction: column;
|
547
|
+
margin: 5%;
|
548
|
+
}
|
549
|
+
.cover-img {
|
550
|
+
max-height: 300px;
|
551
|
+
}
|
552
|
+
`;
|
553
|
+
}
|
554
|
+
}
|
555
|
+
|
556
|
+
customElements.define('book-navigator', BookNavigator);
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { LitElement, html, css } from 'lit
|
1
|
+
import { LitElement, html, css } from 'lit';
|
2
2
|
|
3
3
|
export default class BookmarkButton extends LitElement {
|
4
4
|
static get styles() {
|
@@ -12,7 +12,7 @@ export default class BookmarkButton extends LitElement {
|
|
12
12
|
height: 4rem;
|
13
13
|
width: 4rem;
|
14
14
|
background: transparent;
|
15
|
-
cursor: url('/
|
15
|
+
cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24' viewBox='0 0 16 24' width='16'%3E%3Cg fill='%23333' fill-rule='evenodd'%3E%3Cpath d='m15 0c.5522847 0 1 .44771525 1 1v23l-8-5.4545455-8 5.4545455v-23c0-.55228475.44771525-1 1-1zm-2 2h-10c-.51283584 0-.93550716.38604019-.99327227.88337887l-.00672773.11662113v18l6-4.3181818 6 4.3181818v-18c0-.51283584-.3860402-.93550716-.8833789-.99327227z'/%3E%3Cpath d='m8.75 6v2.25h2.25v1.5h-2.25v2.25h-1.5v-2.25h-2.25v-1.5h2.25v-2.25z' fill-rule='nonzero'/%3E%3C/g%3E%3C/svg%3E"), pointer;
|
16
16
|
position: relative;
|
17
17
|
}
|
18
18
|
button > * {
|
@@ -40,6 +40,7 @@ export default class BookmarkButton extends LitElement {
|
|
40
40
|
constructor() {
|
41
41
|
super();
|
42
42
|
this.state = 'hollow';
|
43
|
+
this.side = undefined;
|
43
44
|
}
|
44
45
|
|
45
46
|
handleClick(e) {
|
@@ -1,6 +1,5 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
3
|
-
import { css, html, LitElement } from 'lit-element';
|
1
|
+
import { repeat } from 'lit/directives/repeat.js';
|
2
|
+
import { css, html, LitElement, nothing } from 'lit';
|
4
3
|
import bookmarkColorsCSS from '../assets/bookmark-colors.js';
|
5
4
|
import buttonCSS from '../assets/button-base.js';
|
6
5
|
|
@@ -208,7 +207,8 @@ export class IABookmarkEdit extends LitElement {
|
|
208
207
|
grid-gap: 0 1rem;
|
209
208
|
justify-items: stretch;
|
210
209
|
}
|
211
|
-
|
210
|
+
`;
|
212
211
|
return [buttonCSS, bookmarkColorsCSS, bookmarkEditCSS];
|
213
212
|
}
|
214
213
|
}
|
214
|
+
customElements.define('ia-bookmark-edit', IABookmarkEdit);
|
@@ -1,6 +1,5 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
3
|
-
import { css, html, LitElement } from 'lit-element';
|
1
|
+
import { repeat } from 'lit/directives/repeat.js';
|
2
|
+
import { css, html, LitElement, nothing } from 'lit';
|
4
3
|
import './bookmark-edit.js';
|
5
4
|
import '@internetarchive/icon-edit-pencil/icon-edit-pencil.js';
|
6
5
|
import bookmarkColorsCSS from '../assets/bookmark-colors.js';
|
@@ -282,3 +281,4 @@ export class IABookmarksList extends LitElement {
|
|
282
281
|
return [main, bookmarkColorsCSS];
|
283
282
|
}
|
284
283
|
}
|
284
|
+
customElements.define('ia-bookmarks-list', IABookmarksList);
|
@@ -1,20 +1,15 @@
|
|
1
|
-
import { LitElement, html
|
1
|
+
import { LitElement, html } from 'lit';
|
2
2
|
import buttonStyles from '../assets/button-base.js';
|
3
3
|
|
4
4
|
class BookmarksLogin extends LitElement {
|
5
5
|
static get properties() {
|
6
6
|
return {
|
7
7
|
url: { type: String }
|
8
|
-
}
|
8
|
+
};
|
9
9
|
}
|
10
10
|
|
11
11
|
static get styles() {
|
12
|
-
|
13
|
-
a {
|
14
|
-
text-decoration: none;
|
15
|
-
}
|
16
|
-
`;
|
17
|
-
return [buttonStyles, mainCss];
|
12
|
+
return buttonStyles;
|
18
13
|
}
|
19
14
|
|
20
15
|
constructor() {
|
@@ -1,28 +1,41 @@
|
|
1
|
-
import { html } from 'lit
|
1
|
+
import { html } from 'lit';
|
2
2
|
import '../delete-modal-actions.js';
|
3
3
|
import './bookmark-button.js';
|
4
4
|
import './ia-bookmarks.js';
|
5
5
|
|
6
|
-
import
|
7
|
-
import
|
6
|
+
import './bookmark-edit.js';
|
7
|
+
import './bookmarks-list.js';
|
8
8
|
import { IAIconBookmark } from '@internetarchive/icon-bookmark';
|
9
9
|
|
10
|
-
customElements.define('ia-bookmark-edit', IABookmarkEdit);
|
11
|
-
customElements.define('ia-bookmarks-list', IABookmarksList);
|
12
10
|
customElements.define('icon-bookmark', IAIconBookmark);
|
13
11
|
|
14
12
|
export default class BookmarksProvider {
|
15
|
-
constructor(options
|
16
|
-
const
|
13
|
+
constructor(options) {
|
14
|
+
const {
|
15
|
+
baseHost,
|
16
|
+
signedIn,
|
17
|
+
bookreader,
|
18
|
+
modal,
|
19
|
+
onProviderChange,
|
20
|
+
} = options;
|
21
|
+
|
22
|
+
const referrerStr = `referer=${encodeURIComponent(location.href)}`;
|
23
|
+
const loginUrl = `https://${baseHost}/account/login?${referrerStr}`;
|
24
|
+
|
17
25
|
this.component = document.createElement('ia-bookmarks');
|
18
26
|
this.component.bookreader = bookreader;
|
19
|
-
this.component.
|
20
|
-
|
27
|
+
this.component.displayMode = signedIn ? 'bookmarks' : 'login';
|
28
|
+
this.component.modal = modal;
|
29
|
+
this.component.loginOptions = {
|
30
|
+
loginClicked: this.bookmarksLoginClicked,
|
31
|
+
loginUrl
|
32
|
+
};
|
21
33
|
this.bindEvents();
|
22
34
|
|
23
35
|
this.icon = html`<icon-bookmark state="hollow" style="--iconWidth: 16px; --iconHeight: 24px;"></icon-bookmark>`;
|
24
36
|
this.label = 'Bookmarks';
|
25
37
|
this.id = 'bookmarks';
|
38
|
+
this.onProviderChange = onProviderChange;
|
26
39
|
this.component.setup();
|
27
40
|
this.updateMenu(this.component.bookmarks.length);
|
28
41
|
}
|
@@ -33,14 +46,12 @@ export default class BookmarksProvider {
|
|
33
46
|
|
34
47
|
bindEvents() {
|
35
48
|
this.component.addEventListener('bookmarksChanged', this.bookmarksChanged.bind(this));
|
36
|
-
this.component.addEventListener('showItemNavigatorModal', this.showItemNavigatorModal);
|
37
|
-
this.component.addEventListener('closeItemNavigatorModal', this.closeItemNavigatorModal);
|
38
49
|
}
|
39
50
|
|
40
51
|
bookmarksChanged({ detail }) {
|
41
52
|
const bookmarksLength = Object.keys(detail.bookmarks).length;
|
42
53
|
this.updateMenu(bookmarksLength);
|
43
|
-
this.
|
54
|
+
this.onProviderChange(detail.bookmarks, detail.showSidePanel);
|
44
55
|
}
|
45
56
|
|
46
57
|
bookmarksLoginClicked() {
|