@internetarchive/bookreader 5.0.0-24-sortingstate-11 → 5.0.0-26
Sign up to get free protection for your applications and to get access to all the features.
- package/BookReader/BookReader.css +4 -0
- package/BookReader/BookReader.js +2 -32145
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/bookreader-component-bundle.js +1286 -11256
- package/BookReader/bookreader-component-bundle.js.map +1 -1
- package/BookReader/icons/1up.svg +1 -12
- package/BookReader/icons/2up.svg +1 -15
- package/BookReader/icons/advance.svg +3 -26
- package/BookReader/icons/chevron-right.svg +1 -1
- package/BookReader/icons/close-circle-dark.svg +1 -1
- package/BookReader/icons/close-circle.svg +1 -1
- package/BookReader/icons/fullscreen.svg +1 -17
- package/BookReader/icons/fullscreen_exit.svg +1 -17
- package/BookReader/icons/hamburger.svg +1 -15
- package/BookReader/icons/left-arrow.svg +1 -12
- package/BookReader/icons/magnify-minus.svg +1 -16
- package/BookReader/icons/magnify-plus.svg +1 -17
- package/BookReader/icons/magnify.svg +1 -15
- package/BookReader/icons/pause.svg +1 -23
- package/BookReader/icons/play.svg +1 -22
- package/BookReader/icons/playback-speed.svg +1 -34
- package/BookReader/icons/read-aloud.svg +1 -22
- package/BookReader/icons/review.svg +3 -22
- package/BookReader/icons/thumbnails.svg +1 -17
- package/BookReader/icons/voice.svg +1 -1
- package/BookReader/icons/volume-full.svg +1 -22
- package/BookReader/images/BRicons.svg +5 -94
- package/BookReader/images/books_graphic.svg +1 -177
- package/BookReader/images/icon_book.svg +1 -12
- package/BookReader/images/icon_bookmark.svg +1 -12
- package/BookReader/images/icon_gear.svg +1 -14
- package/BookReader/images/icon_hamburger.svg +1 -20
- package/BookReader/images/icon_home.svg +1 -21
- package/BookReader/images/icon_info.svg +1 -11
- package/BookReader/images/icon_one_page.svg +1 -8
- package/BookReader/images/icon_pause.svg +1 -1
- package/BookReader/images/icon_play.svg +1 -1
- package/BookReader/images/icon_playback-rate.svg +1 -15
- package/BookReader/images/icon_search_button.svg +1 -8
- package/BookReader/images/icon_share.svg +1 -9
- package/BookReader/images/icon_skip-ahead.svg +1 -6
- package/BookReader/images/icon_skip-back.svg +2 -13
- package/BookReader/images/icon_speaker.svg +1 -18
- package/BookReader/images/icon_speaker_open.svg +1 -10
- package/BookReader/images/icon_thumbnails.svg +1 -12
- package/BookReader/images/icon_toc.svg +1 -5
- package/BookReader/images/icon_two_pages.svg +1 -9
- package/BookReader/images/marker_chap-off.svg +1 -11
- package/BookReader/images/marker_chap-on.svg +1 -11
- package/BookReader/images/marker_srch-on.svg +1 -11
- package/BookReader/jquery-1.10.1.js +2 -108
- package/BookReader/plugins/plugin.archive_analytics.js +1 -170
- package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
- package/BookReader/plugins/plugin.autoplay.js +1 -163
- package/BookReader/plugins/plugin.autoplay.js.map +1 -1
- package/BookReader/plugins/plugin.chapters.js +1 -333
- package/BookReader/plugins/plugin.chapters.js.map +1 -1
- package/BookReader/plugins/plugin.iframe.js +1 -72
- package/BookReader/plugins/plugin.iframe.js.map +1 -1
- package/BookReader/plugins/plugin.mobile_nav.js +1 -332
- package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
- package/BookReader/plugins/plugin.resume.js +1 -241
- package/BookReader/plugins/plugin.resume.js.map +1 -1
- package/BookReader/plugins/plugin.search.js +1 -1263
- package/BookReader/plugins/plugin.search.js.map +1 -1
- package/BookReader/plugins/plugin.text_selection.js +1 -839
- package/BookReader/plugins/plugin.text_selection.js.map +1 -1
- package/BookReader/plugins/plugin.tts.js +2 -9114
- package/BookReader/plugins/plugin.tts.js.map +1 -1
- package/BookReader/plugins/plugin.url.js +1 -768
- package/BookReader/plugins/plugin.url.js.map +1 -1
- package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -326
- package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
- package/BookReader/webcomponents-bundle.js +2 -411
- package/BookReader/webcomponents-bundle.js.map +1 -1
- package/BookReaderDemo/demo-internetarchive.html +86 -4
- package/CHANGELOG.md +5 -0
- package/package.json +1 -1
- package/src/BookNavigator/bookmarks/ia-bookmarks.js +1 -0
- package/src/BookNavigator/volumes/volumes-provider.js +9 -40
- package/src/BookReader.js +102 -64
- package/src/css/_controls.scss +4 -0
- package/src/plugins/plugin.url.js +2 -218
- package/tests/jest/BookReader.keyboard.test.js +190 -0
- package/tests/jest/plugins/plugin.url.test.js +1 -151
- package/.nvmrc +0 -1
@@ -29,6 +29,10 @@
|
|
29
29
|
<script type="module" src="../BookReader/bookreader-component-bundle.js"></script>
|
30
30
|
|
31
31
|
<link rel="stylesheet" href="BookReaderDemo.css"/>
|
32
|
+
|
33
|
+
<!-- IA scripts -->
|
34
|
+
<script src="https://archive.org/bookreader/BookReaderJSIA.js"></script>
|
35
|
+
|
32
36
|
</head>
|
33
37
|
|
34
38
|
<body>
|
@@ -59,16 +63,94 @@
|
|
59
63
|
<script id="pageUrl" type="text/javascript"></script>
|
60
64
|
|
61
65
|
<script>
|
62
|
-
|
66
|
+
// gather params here
|
67
|
+
const urlParams = new URLSearchParams(window.location.search);
|
68
|
+
|
69
|
+
const ocaid = urlParams.get('ocaid');
|
70
|
+
const openFullImmersionTheater = urlParams.get('view') === 'theater';
|
71
|
+
const ui = urlParams.get('ui');
|
72
|
+
const autoflip = urlParams.get('autoflip');
|
73
|
+
const searchTerm = urlParams.get('q');
|
63
74
|
|
64
75
|
// Override options coming from IA
|
65
76
|
BookReader.optionOverrides.imagesBaseURL = '/BookReader/images/';
|
66
77
|
|
78
|
+
const initializeBookReader = (brManifest) => {
|
79
|
+
console.log('initializeBookReader', brManifest);
|
80
|
+
const br = new BookReader();
|
81
|
+
const iaBookManifestUrl = '';
|
82
|
+
|
83
|
+
const customAutoflipParams = {
|
84
|
+
autoflip: !!autoflip,
|
85
|
+
flipSpeed: urlParams.flipSpeed || 2000,
|
86
|
+
flipDelay: urlParams.flipDelay || 5000
|
87
|
+
};
|
88
|
+
|
89
|
+
const options = {
|
90
|
+
el: '#BookReader',
|
91
|
+
/* Url plugin - IA uses History mode for URL */
|
92
|
+
// commenting these out as demo uses hash mode
|
93
|
+
// keeping them here for reference
|
94
|
+
// urlHistoryBasePath: `/details/{$ocaid}/`,
|
95
|
+
// resumeCookiePath: `/details/{$ocaid}/`,
|
96
|
+
// urlMode: 'history',
|
97
|
+
// Only reflect these params onto the URL
|
98
|
+
// urlTrackedParams: ['page', 'search', 'mode'],
|
99
|
+
/* End url plugin */
|
100
|
+
enableBookTitleLink: false,
|
101
|
+
bookUrlText: null,
|
102
|
+
startFullscreen: urlParams.view === 'theater',
|
103
|
+
initialSearchTerm: searchTerm ? searchTerm : '',
|
104
|
+
// leaving this option commented out bc we change given user agent on archive.org
|
105
|
+
// onePage: { autofit: <?=json_encode($this->ios ? 'width' : 'auto')?> },
|
106
|
+
showToolbar: false,
|
107
|
+
/* Multiple volumes */
|
108
|
+
// To show multiple volumes:
|
109
|
+
enableMultipleBooks: false, // turn this on
|
110
|
+
multipleBooksList: [], // populate this // TODO: get sample blob and tie into demo
|
111
|
+
/* End multiple volumes */
|
112
|
+
};
|
113
|
+
|
114
|
+
// we want to show item as embedded when ?ui=embed is in URI
|
115
|
+
if (ui === 'embed') {
|
116
|
+
options.mode = 1;
|
117
|
+
options.ui = 'embed';
|
118
|
+
}
|
119
|
+
|
120
|
+
// we expect this at the global level
|
121
|
+
BookReaderJSIAinit(brManifest.data, { ...options });
|
122
|
+
|
123
|
+
if (customAutoflipParams.autoflip) {
|
124
|
+
br.autoToggle(customAutoflipParams);
|
125
|
+
}
|
126
|
+
}
|
127
|
+
|
128
|
+
const fetchBookManifestAndInitializeBookreader = async (iaMetadata) => {
|
129
|
+
const {
|
130
|
+
metadata: {
|
131
|
+
identifier
|
132
|
+
},
|
133
|
+
} = iaMetadata;
|
134
|
+
|
135
|
+
const locator =`https://archive.org/bookreader/BookReaderJSLocate.php?format=json&subPrefix=&id=${identifier}`;
|
136
|
+
// Todo: move from `locator` to create `iaManifestUrl` url from `iaMetadata`
|
137
|
+
// so we can support multiple volumes
|
138
|
+
// const iaManifestUrl = `https://${server}/BookReader/BookReaderJSIA.php?format=jsonp&itemPath=${dir}&id=${identifier}`;
|
139
|
+
|
140
|
+
const manifest = await fetch(locator)
|
141
|
+
.then(response => response.json())
|
142
|
+
|
143
|
+
initializeBookReader(manifest);
|
144
|
+
}
|
145
|
+
|
67
146
|
// Temp; Circumvent bug in BookReaderJSIA code
|
68
147
|
window.Sentry = null;
|
69
|
-
|
70
|
-
|
71
|
-
|
148
|
+
window.logError = function(e) {
|
149
|
+
console.error(e);
|
150
|
+
};
|
151
|
+
fetch(`https://archive.org/metadata/${ocaid}`)
|
152
|
+
.then(response => response.json())
|
153
|
+
.then(iaMetadata => fetchBookManifestAndInitializeBookreader(iaMetadata));
|
72
154
|
</script>
|
73
155
|
|
74
156
|
</body>
|
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
@@ -7,16 +7,8 @@ import volumesIcon from '../assets/icon_volumes.js';
|
|
7
7
|
|
8
8
|
import './volumes.js';
|
9
9
|
|
10
|
-
const sortType = {
|
11
|
-
title_asc: 'title_asc',
|
12
|
-
title_desc: 'title_desc',
|
13
|
-
default: 'default'
|
14
|
-
};
|
15
10
|
export default class VolumesProvider {
|
16
11
|
|
17
|
-
/**
|
18
|
-
* @param {import('../../BookReader').default} bookreader
|
19
|
-
*/
|
20
12
|
constructor(baseHost, bookreader, optionChange) {
|
21
13
|
this.optionChange = optionChange;
|
22
14
|
this.component = document.createElement("viewable-files");
|
@@ -25,9 +17,6 @@ export default class VolumesProvider {
|
|
25
17
|
this.viewableFiles = Object.keys(files).map(item => files[item]);
|
26
18
|
this.volumeCount = Object.keys(files).length;
|
27
19
|
|
28
|
-
/** @type {import('../../BookReader').default} */
|
29
|
-
this.bookreader = bookreader;
|
30
|
-
|
31
20
|
this.component.subPrefix = bookreader.options.subPrefix || "";
|
32
21
|
this.component.hostUrl = baseHost;
|
33
22
|
this.component.viewableFiles = this.viewableFiles;
|
@@ -36,28 +25,20 @@ export default class VolumesProvider {
|
|
36
25
|
this.label = `Viewable files (${this.volumeCount})`;
|
37
26
|
this.icon = html`${volumesIcon}`;
|
38
27
|
|
39
|
-
|
40
|
-
this.
|
41
|
-
const urlSortValue = this.bookreader.urlPlugin.getUrlParam('sort');
|
42
|
-
console.log('urlSortValue: ', urlSortValue);
|
43
|
-
if (urlSortValue === sortType.title_asc || urlSortValue === sortType.title_desc) {
|
44
|
-
this.sortOrderBy = urlSortValue;
|
45
|
-
} else {
|
46
|
-
this.sortOrderBy = sortType.default;
|
47
|
-
}
|
48
|
-
this.sortVolumes(this.sortOrderBy);
|
28
|
+
this.sortOrderBy = "orig_sort";
|
29
|
+
this.sortVolumes("orig_sort");
|
49
30
|
}
|
50
31
|
|
51
32
|
get sortButton() {
|
52
33
|
const sortIcons = {
|
53
|
-
|
34
|
+
orig_sort: html`
|
54
35
|
<button class="sort-by neutral-icon" aria-label="Sort volumes in initial order" @click=${() => this.sortVolumes("title_asc")}>${sortNeutralIcon}</button>
|
55
36
|
`,
|
56
37
|
title_asc: html`
|
57
38
|
<button class="sort-by asc-icon" aria-label="Sort volumes in ascending order" @click=${() => this.sortVolumes("title_desc")}>${sortAscIcon}</button>
|
58
39
|
`,
|
59
40
|
title_desc: html`
|
60
|
-
<button class="sort-by desc-icon" aria-label="Sort volumes in descending order" @click=${() => this.sortVolumes("
|
41
|
+
<button class="sort-by desc-icon" aria-label="Sort volumes in descending order" @click=${() => this.sortVolumes("orig_sort")}>${sortDescIcon}</button>
|
61
42
|
`,
|
62
43
|
};
|
63
44
|
|
@@ -65,40 +46,28 @@ export default class VolumesProvider {
|
|
65
46
|
}
|
66
47
|
|
67
48
|
/**
|
68
|
-
* @param {'
|
49
|
+
* @param {'orig_sort' | 'title_asc' | 'title_desc'} sortByType
|
69
50
|
*/
|
70
51
|
sortVolumes(sortByType) {
|
71
52
|
let sortedFiles = [];
|
72
53
|
|
73
54
|
const files = this.viewableFiles;
|
74
55
|
sortedFiles = files.sort((a, b) => {
|
75
|
-
if (sortByType ===
|
76
|
-
else if (sortByType ===
|
77
|
-
else return a.
|
56
|
+
if (sortByType === 'orig_sort') return a.orig_sort - b.orig_sort;
|
57
|
+
else if (sortByType === 'title_asc') return a.title.localeCompare(b.title);
|
58
|
+
else return b.title.localeCompare(a.title);
|
78
59
|
});
|
79
60
|
|
80
61
|
this.sortOrderBy = sortByType;
|
81
62
|
this.component.viewableFiles = [...sortedFiles];
|
82
63
|
this.actionButton = this.sortButton;
|
83
|
-
|
84
|
-
if (this.sortOrderBy !== sortType.default) {
|
85
|
-
this.bookreader.urlPlugin.setUrlParam('sort', sortByType);
|
86
|
-
} else {
|
87
|
-
this.bookreader.urlPlugin.removeUrlParam('sort');
|
88
|
-
}
|
89
|
-
|
90
|
-
const urlSchema = this.bookreader.urlPlugin.urlSchema;
|
91
|
-
const urlState = this.bookreader.urlPlugin.urlState;
|
92
|
-
this.bookreader.urlPlugin.urlStateToUrlString(urlSchema, urlState);
|
93
|
-
this.bookreader.urlPlugin.pushToAddressBar();
|
94
|
-
|
95
64
|
this.optionChange(this.bookreader);
|
96
65
|
|
97
66
|
this.multipleFilesClicked(sortByType);
|
98
67
|
}
|
99
68
|
|
100
69
|
/**
|
101
|
-
* @param {'
|
70
|
+
* @param {'orig_sort' | 'title_asc' | 'title_desc'} orderBy
|
102
71
|
*/
|
103
72
|
multipleFilesClicked(orderBy) {
|
104
73
|
if (!window.archive_analytics) {
|
package/src/BookReader.js
CHANGED
@@ -264,6 +264,15 @@ BookReader.prototype.setup = function(options) {
|
|
264
264
|
useSrcSet: this.options.useSrcSet,
|
265
265
|
reduceSet: this.reduceSet,
|
266
266
|
});
|
267
|
+
|
268
|
+
/**
|
269
|
+
* Flag if BookReader has "focus" for keyboard shortcuts
|
270
|
+
* Initially true, set to false when:
|
271
|
+
* - BookReader scrolled out of view
|
272
|
+
* Set to true when:
|
273
|
+
* - BookReader scrolled into view
|
274
|
+
*/
|
275
|
+
this.hasKeyFocus = true;
|
267
276
|
};
|
268
277
|
|
269
278
|
/**
|
@@ -662,87 +671,116 @@ BookReader.prototype.resize = function() {
|
|
662
671
|
};
|
663
672
|
|
664
673
|
/**
|
665
|
-
* Binds keyboard event listeners
|
674
|
+
* Binds keyboard and keyboard focus event listeners
|
666
675
|
*/
|
667
|
-
BookReader.prototype.setupKeyListeners = function() {
|
668
|
-
var self = this;
|
676
|
+
BookReader.prototype.setupKeyListeners = function () {
|
669
677
|
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
678
|
+
// Keyboard focus by BookReader in viewport
|
679
|
+
//
|
680
|
+
// Intersection observer and callback sets BookReader keyboard
|
681
|
+
// "focus" flag off when the BookReader is not in the viewport.
|
682
|
+
if (window.IntersectionObserver) {
|
683
|
+
const observer = new IntersectionObserver((entries) => {
|
684
|
+
entries.forEach((entry) => {
|
685
|
+
if (entry.intersectionRatio === 0) {
|
686
|
+
this.hasKeyFocus = false;
|
687
|
+
} else {
|
688
|
+
this.hasKeyFocus = true;
|
689
|
+
}
|
690
|
+
});
|
691
|
+
}, {
|
692
|
+
root: null,
|
693
|
+
rootMargin: '0px',
|
694
|
+
threshold: [0, 0.05, 1],
|
695
|
+
});
|
696
|
+
observer.observe(this.refs.$br[0]);
|
697
|
+
}
|
698
|
+
|
699
|
+
// Keyboard listeners
|
700
|
+
document.addEventListener('keydown', (e) => {
|
701
|
+
|
702
|
+
// Ignore if BookReader "focus" flag not set
|
703
|
+
if (!this.hasKeyFocus) {
|
704
|
+
return;
|
705
|
+
}
|
706
|
+
|
707
|
+
// Ignore if modifiers are active.
|
708
|
+
if (e.getModifierState('Control') ||
|
709
|
+
e.getModifierState('Alt') ||
|
710
|
+
e.getModifierState('Meta') ||
|
711
|
+
e.getModifierState('Win') /* hack for IE */) {
|
712
|
+
return;
|
713
|
+
}
|
714
|
+
|
715
|
+
// Ignore in input elements
|
716
|
+
if (utils.isInputActive()) {
|
717
|
+
return;
|
718
|
+
}
|
719
|
+
|
720
|
+
// KeyboardEvent code values:
|
721
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values
|
722
|
+
switch (e.key) {
|
723
|
+
|
724
|
+
// Page navigation
|
725
|
+
case "Home":
|
726
|
+
e.preventDefault();
|
727
|
+
this.first();
|
699
728
|
break;
|
700
|
-
case
|
701
|
-
|
702
|
-
|
703
|
-
e.preventDefault();
|
704
|
-
self.next();
|
705
|
-
}
|
729
|
+
case "End":
|
730
|
+
e.preventDefault();
|
731
|
+
this.last();
|
706
732
|
break;
|
707
|
-
case
|
708
|
-
|
733
|
+
case "ArrowDown":
|
734
|
+
case "PageDown":
|
735
|
+
case "Down": // hack for IE and old Gecko
|
736
|
+
// In 1up and thumb mode page scrolling handled by browser
|
737
|
+
if (this.constMode2up === this.mode) {
|
709
738
|
e.preventDefault();
|
710
|
-
|
739
|
+
this.next();
|
711
740
|
}
|
712
741
|
break;
|
713
|
-
case
|
714
|
-
|
742
|
+
case "ArrowUp":
|
743
|
+
case "PageUp":
|
744
|
+
case "Up": // hack for IE and old Gecko
|
745
|
+
// In 1up and thumb mode page scrolling handled by browser
|
746
|
+
if (this.constMode2up === this.mode) {
|
715
747
|
e.preventDefault();
|
716
|
-
|
748
|
+
this.prev();
|
717
749
|
}
|
718
750
|
break;
|
719
|
-
case
|
720
|
-
|
751
|
+
case "ArrowLeft":
|
752
|
+
case "Left": // hack for IE and old Gecko
|
753
|
+
// No y-scrolling in thumb mode
|
754
|
+
if (this.constModeThumb != this.mode) {
|
721
755
|
e.preventDefault();
|
722
|
-
|
756
|
+
this.left();
|
723
757
|
}
|
724
758
|
break;
|
725
|
-
case
|
726
|
-
|
759
|
+
case "ArrowRight":
|
760
|
+
case "Right": // hack for IE and old Gecko
|
761
|
+
// No y-scrolling in thumb mode
|
762
|
+
if (this.constModeThumb != this.mode) {
|
727
763
|
e.preventDefault();
|
728
|
-
|
764
|
+
this.right();
|
729
765
|
}
|
730
766
|
break;
|
731
|
-
|
732
|
-
case
|
733
|
-
case
|
734
|
-
|
735
|
-
|
736
|
-
self.zoom(-1);
|
737
|
-
}
|
767
|
+
// Zoom
|
768
|
+
case '-':
|
769
|
+
case 'Subtract':
|
770
|
+
e.preventDefault();
|
771
|
+
this.zoom(-1);
|
738
772
|
break;
|
739
|
-
case
|
740
|
-
case
|
741
|
-
case
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
773
|
+
case '+':
|
774
|
+
case '=':
|
775
|
+
case 'Add':
|
776
|
+
e.preventDefault();
|
777
|
+
this.zoom(1);
|
778
|
+
break;
|
779
|
+
// Fullscreen
|
780
|
+
case 'F':
|
781
|
+
case 'f':
|
782
|
+
e.preventDefault();
|
783
|
+
this.toggleFullscreen();
|
746
784
|
break;
|
747
785
|
}
|
748
786
|
});
|