@internetarchive/bookreader 5.0.0-71 → 5.0.0-73
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/.github/workflows/node.js.yml +16 -16
- package/.github/workflows/npm-publish.yml +6 -6
- package/BookReader/BookReader.css +9 -6
- package/BookReader/BookReader.js +1 -1
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +9 -9
- package/BookReader/ia-bookreader-bundle.js.map +1 -1
- package/BookReader/icons/1up.svg +1 -1
- package/BookReader/icons/2up.svg +1 -1
- package/BookReader/icons/advance.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 -1
- package/BookReader/icons/fullscreen_exit.svg +1 -1
- package/BookReader/icons/hamburger.svg +1 -1
- package/BookReader/icons/left-arrow.svg +1 -1
- package/BookReader/icons/magnify-minus.svg +1 -1
- package/BookReader/icons/magnify-plus.svg +1 -1
- package/BookReader/icons/magnify.svg +1 -1
- package/BookReader/icons/pause.svg +1 -1
- package/BookReader/icons/play.svg +1 -1
- package/BookReader/icons/playback-speed.svg +1 -1
- package/BookReader/icons/read-aloud.svg +1 -1
- package/BookReader/icons/review.svg +1 -1
- package/BookReader/icons/thumbnails.svg +1 -1
- package/BookReader/images/BRicons.svg +2 -2
- package/BookReader/images/books_graphic.svg +1 -1
- package/BookReader/images/icon_book.svg +1 -1
- package/BookReader/images/icon_gear.svg +1 -1
- package/BookReader/images/icon_info.svg +1 -1
- package/BookReader/images/icon_one_page.svg +1 -1
- package/BookReader/images/icon_search_button.svg +1 -1
- package/BookReader/images/icon_share.svg +1 -1
- package/BookReader/images/icon_speaker.svg +1 -1
- package/BookReader/images/icon_speaker_open.svg +1 -1
- package/BookReader/images/icon_thumbnails.svg +1 -1
- package/BookReader/images/icon_toc.svg +1 -1
- package/BookReader/images/icon_two_pages.svg +1 -1
- package/BookReader/images/marker_chap-off.svg +1 -1
- package/BookReader/images/marker_chap-on.svg +1 -1
- package/BookReader/images/marker_srch-on.svg +1 -1
- package/BookReader/plugins/plugin.archive_analytics.js +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 +2 -2
- package/BookReader/plugins/plugin.chapters.js.map +1 -1
- package/BookReader/plugins/plugin.resume.js +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/BookReaderDemo/BookReaderDemo.css +3 -0
- package/CHANGELOG.md +11 -0
- package/netlify.toml +1 -1
- package/package.json +14 -15
- package/scripts/preversion.js +0 -4
- package/src/BookReader/options.js +3 -0
- package/src/BookReader/utils/SelectionObserver.js +3 -1
- package/src/css/_BRsearch.scss +4 -6
- package/src/plugins/plugin.chapters.js +36 -16
- package/src/plugins/tts/AbstractTTSEngine.js +5 -2
- package/src/plugins/tts/plugin.tts.js +1 -1
- package/src/plugins/tts/utils.js +15 -0
- package/tests/jest/BookReader/utils/SelectionObserver.test.js +14 -0
- package/tests/jest/plugins/plugin.chapters.test.js +51 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
# 5.0.0-73
|
|
2
|
+
- Feature: Add `table_of_contents` option to work with chapters plugin @cdrini
|
|
3
|
+
- Fix: Simple demos not working @xonx4l
|
|
4
|
+
- Dev: Update test/build dependencies @cdrini
|
|
5
|
+
|
|
6
|
+
# 5.0.0-72
|
|
7
|
+
- Fix: Play/pause button out of sync with ReadAloud @sbwhitt
|
|
8
|
+
- Fix: BookReader not loading in sandboxed iframe @cdrini
|
|
9
|
+
- Dev: Fix noisy sentry error firing on any selection @cdrini
|
|
10
|
+
- Dev: Update to Node 20 @cdrini
|
|
11
|
+
|
|
1
12
|
# 5.0.0-71
|
|
2
13
|
- Dev: update jest monorepo @renovate
|
|
3
14
|
- Fix: Share & Mutliple View menu panel refactor @iisa
|
package/netlify.toml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@internetarchive/bookreader",
|
|
3
|
-
"version": "5.0.0-
|
|
3
|
+
"version": "5.0.0-73",
|
|
4
4
|
"description": "The Internet Archive BookReader.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -40,18 +40,18 @@
|
|
|
40
40
|
"lit": "^2.5.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@babel/core": "7.
|
|
44
|
-
"@babel/eslint-parser": "7.
|
|
43
|
+
"@babel/core": "7.23.3",
|
|
44
|
+
"@babel/eslint-parser": "7.23.3",
|
|
45
45
|
"@babel/plugin-proposal-class-properties": "7.18.6",
|
|
46
|
-
"@babel/plugin-proposal-decorators": "7.
|
|
47
|
-
"@babel/preset-env": "7.
|
|
48
|
-
"@open-wc/testing-helpers": "
|
|
49
|
-
"@types/jest": "29.5.
|
|
46
|
+
"@babel/plugin-proposal-decorators": "7.23.3",
|
|
47
|
+
"@babel/preset-env": "7.23.3",
|
|
48
|
+
"@open-wc/testing-helpers": "3.0.0",
|
|
49
|
+
"@types/jest": "29.5.10",
|
|
50
50
|
"@webcomponents/webcomponentsjs": "^2.6.0",
|
|
51
51
|
"babel-loader": "9.1.3",
|
|
52
52
|
"codecov": "^3.8.3",
|
|
53
53
|
"concurrently": "7.6.0",
|
|
54
|
-
"core-js": "3.
|
|
54
|
+
"core-js": "3.33.3",
|
|
55
55
|
"cpx2": "4.2.3",
|
|
56
56
|
"eslint": "^7.32.0",
|
|
57
57
|
"eslint-plugin-no-jquery": "^2.7.0",
|
|
@@ -67,21 +67,20 @@
|
|
|
67
67
|
"jquery-ui-touch-punch": "0.2.3",
|
|
68
68
|
"jquery.browser": "0.1.0",
|
|
69
69
|
"live-server": "1.2.2",
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"sinon": "^15.1.0",
|
|
70
|
+
"regenerator-runtime": "0.14.0",
|
|
71
|
+
"sass": "1.69.5",
|
|
72
|
+
"sinon": "17.0.1",
|
|
74
73
|
"soundmanager2": "2.97.20170602",
|
|
75
|
-
"svgo": "3.0.
|
|
74
|
+
"svgo": "3.0.4",
|
|
76
75
|
"testcafe": "2.6.2",
|
|
77
76
|
"testcafe-browser-provider-browserstack": "^1.13.2-alpha.1",
|
|
78
|
-
"webpack": "5.
|
|
77
|
+
"webpack": "5.89.0",
|
|
79
78
|
"webpack-cli": "5.1.4"
|
|
80
79
|
},
|
|
81
80
|
"jest": {
|
|
82
81
|
"testEnvironment": "jsdom",
|
|
83
82
|
"transformIgnorePatterns": [
|
|
84
|
-
"node_modules/(?!(lit-html|lit-element|lit|@lit|@internetarchive|@open-wc)/)"
|
|
83
|
+
"node_modules/(?!(sinon|lit-html|lit-element|lit|@lit|@internetarchive|@open-wc)/)"
|
|
85
84
|
],
|
|
86
85
|
"moduleNameMapper": {
|
|
87
86
|
"^@/(.*)$": "<rootDir>/$1"
|
package/scripts/preversion.js
CHANGED
|
@@ -2,10 +2,6 @@ const { version: OLD_VERSION } = require('../package.json');
|
|
|
2
2
|
const OLD_RELEASE_URL = `https://api.github.com/repos/internetarchive/bookreader/releases/tags/v${OLD_VERSION}`;
|
|
3
3
|
|
|
4
4
|
async function main() {
|
|
5
|
-
// Need this because fetch is ESM-only, and we're on Node 16. Someday we should
|
|
6
|
-
// be able to move this up to the top without renaming this file to a .mjs or whatever
|
|
7
|
-
const {default: fetch} = await import('node-fetch');
|
|
8
|
-
|
|
9
5
|
const {created_at} = await fetch(OLD_RELEASE_URL).then(r => r.json());
|
|
10
6
|
const today = new Date().toISOString().slice(0, -5);
|
|
11
7
|
const searchUrl = 'https://github.com/internetarchive/bookreader/pulls?' + new URLSearchParams({
|
|
@@ -180,6 +180,9 @@ export const DEFAULT_OPTIONS = {
|
|
|
180
180
|
*/
|
|
181
181
|
data: [],
|
|
182
182
|
|
|
183
|
+
/** @type {import('../plugins/plugin.chapters.js').TocEntry[]} */
|
|
184
|
+
table_of_contents: null,
|
|
185
|
+
|
|
183
186
|
/** Advanced methods for page rendering */
|
|
184
187
|
/** @type {() => number} */
|
|
185
188
|
getNumLeafs: null,
|
|
@@ -30,8 +30,10 @@ export class SelectionObserver {
|
|
|
30
30
|
const sel = window.getSelection();
|
|
31
31
|
|
|
32
32
|
if (!this.selecting && sel.toString()) {
|
|
33
|
+
const target = $(sel.anchorNode).closest(this.selector)[0];
|
|
34
|
+
if (!target) return;
|
|
35
|
+
this.target = target;
|
|
33
36
|
this.selecting = true;
|
|
34
|
-
this.target = $(sel.anchorNode).closest(this.selector)[0];
|
|
35
37
|
this.handler('started', this.target);
|
|
36
38
|
}
|
|
37
39
|
|
package/src/css/_BRsearch.scss
CHANGED
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
display: none;
|
|
10
10
|
position: absolute;
|
|
11
11
|
bottom: calc(100% + 5px);
|
|
12
|
-
left:
|
|
13
|
-
transform: translateX(-50%);
|
|
12
|
+
left: -14px;
|
|
14
13
|
width: 350px;
|
|
15
14
|
max-width: 100vw;
|
|
16
15
|
padding: 12px 14px;
|
|
@@ -34,9 +33,7 @@
|
|
|
34
33
|
position: absolute;
|
|
35
34
|
content: "";
|
|
36
35
|
bottom: -9px;
|
|
37
|
-
left:
|
|
38
|
-
margin-left: -1px;
|
|
39
|
-
transform: translateX(-50%);
|
|
36
|
+
left: 0;
|
|
40
37
|
width: 30px;
|
|
41
38
|
height: 10px;
|
|
42
39
|
clip-path: polygon(0 0, 100% 0, 50% 100%);
|
|
@@ -131,9 +128,10 @@
|
|
|
131
128
|
main {
|
|
132
129
|
@include ellipsis-lines(4);
|
|
133
130
|
margin-bottom: 6px;
|
|
131
|
+
&:before { content: "“"; }
|
|
132
|
+
&:after { content: "”"; }
|
|
134
133
|
}
|
|
135
134
|
footer {
|
|
136
|
-
text-align: center;
|
|
137
135
|
font-size: 0.85em;
|
|
138
136
|
opacity: .8;
|
|
139
137
|
}
|
|
@@ -28,11 +28,28 @@ BookReader.prototype.init = (function(super_) {
|
|
|
28
28
|
})(BookReader.prototype.init);
|
|
29
29
|
|
|
30
30
|
BookReader.prototype._chapterInit = async function() {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
let rawTableOfContents = null;
|
|
32
|
+
// Prefer IA TOC for now, until we update the second half to check for
|
|
33
|
+
// `openlibrary_edition` on the IA metadata instead of making a bunch of
|
|
34
|
+
// requests to OL.
|
|
35
|
+
if (this.options.table_of_contents?.length) {
|
|
36
|
+
rawTableOfContents = this.options.table_of_contents;
|
|
37
|
+
} else {
|
|
38
|
+
const olEdition = await this.getOpenLibraryRecord(this.options.olHost, this.options.bookId);
|
|
39
|
+
if (olEdition?.table_of_contents?.length) {
|
|
40
|
+
rawTableOfContents = olEdition.table_of_contents;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (rawTableOfContents) {
|
|
45
|
+
this._tocEntries = rawTableOfContents
|
|
46
|
+
.map(rawTOCEntry => (Object.assign({}, rawTOCEntry, {
|
|
47
|
+
pageIndex: (
|
|
48
|
+
typeof(rawTOCEntry.leaf) == 'number' ? this.book.leafNumToIndex(rawTOCEntry.leaf) :
|
|
49
|
+
rawTOCEntry.pagenum ? this.book.getPageIndex(rawTOCEntry.pagenum) :
|
|
50
|
+
undefined
|
|
51
|
+
),
|
|
52
|
+
})));
|
|
36
53
|
this._chaptersRender(this._tocEntries);
|
|
37
54
|
this.bind(BookReader.eventNames.pageChanged, () => this._chaptersUpdateCurrent());
|
|
38
55
|
}
|
|
@@ -60,19 +77,18 @@ BookReader.prototype._chaptersRender = function() {
|
|
|
60
77
|
/>`,
|
|
61
78
|
};
|
|
62
79
|
shell.updateMenuContents();
|
|
63
|
-
|
|
64
|
-
this._chaptersRenderMarker(tocEntry);
|
|
65
|
-
}
|
|
80
|
+
this._tocEntries.forEach((tocEntry, i) => this._chaptersRenderMarker(tocEntry, i));
|
|
66
81
|
};
|
|
67
82
|
|
|
68
83
|
/**
|
|
69
84
|
* @typedef {Object} TocEntry
|
|
70
85
|
* Table of contents entry as defined by Open Library, with some extra values for internal use
|
|
71
|
-
* @property {
|
|
72
|
-
* @property {
|
|
73
|
-
* @property {string}
|
|
74
|
-
* @property {
|
|
75
|
-
* @property {
|
|
86
|
+
* @property {number} [level]
|
|
87
|
+
* @property {string} [label]
|
|
88
|
+
* @property {string} [title]
|
|
89
|
+
* @property {PageString} [pagenum]
|
|
90
|
+
* @property {LeafNum} [leaf]
|
|
91
|
+
* @property {number} [pageIndex] - Added
|
|
76
92
|
*
|
|
77
93
|
* @example {
|
|
78
94
|
* "pagenum": "17",
|
|
@@ -84,21 +100,25 @@ BookReader.prototype._chaptersRender = function() {
|
|
|
84
100
|
|
|
85
101
|
/**
|
|
86
102
|
* @param {TocEntry} tocEntry
|
|
103
|
+
* @param {number} entryIndex
|
|
87
104
|
*/
|
|
88
|
-
BookReader.prototype._chaptersRenderMarker = function(tocEntry) {
|
|
105
|
+
BookReader.prototype._chaptersRenderMarker = function(tocEntry, entryIndex) {
|
|
89
106
|
if (tocEntry.pageIndex == undefined) return;
|
|
90
107
|
|
|
91
108
|
//creates a string with non-void tocEntry.label and tocEntry.title
|
|
92
109
|
const chapterStr = [tocEntry.label, tocEntry.title]
|
|
93
110
|
.filter(x => x)
|
|
94
|
-
.join(' ')
|
|
111
|
+
.join(' ') || `Chapter ${entryIndex + 1}`;
|
|
95
112
|
|
|
96
113
|
const percentThrough = BookReader.util.cssPercentage(tocEntry.pageIndex, this.book.getNumLeafs() - 1);
|
|
97
114
|
$(`<div></div>`)
|
|
98
115
|
.append(
|
|
99
116
|
$('<div />')
|
|
100
117
|
.text(chapterStr)
|
|
101
|
-
.append(
|
|
118
|
+
.append(
|
|
119
|
+
$('<div class="BRchapterPage" />')
|
|
120
|
+
.text(this.book.getPageName(tocEntry.pageIndex))
|
|
121
|
+
)
|
|
102
122
|
)
|
|
103
123
|
.addClass('BRchapter')
|
|
104
124
|
.css({ left: percentThrough })
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import PageChunkIterator from './PageChunkIterator.js';
|
|
2
|
+
import { hasLocalStorage } from './utils.js';
|
|
2
3
|
/** @typedef {import('./utils.js').ISO6391} ISO6391 */
|
|
3
4
|
/** @typedef {import('./PageChunk.js')} PageChunk */
|
|
4
5
|
|
|
@@ -80,6 +81,7 @@ export default class AbstractTTSEngine {
|
|
|
80
81
|
*/
|
|
81
82
|
start(leafIndex, numLeafs) {
|
|
82
83
|
this.playing = true;
|
|
84
|
+
this.paused = false;
|
|
83
85
|
this.opts.onLoadingStart();
|
|
84
86
|
|
|
85
87
|
this._chunkIterator = new PageChunkIterator(numLeafs, leafIndex, {
|
|
@@ -95,6 +97,7 @@ export default class AbstractTTSEngine {
|
|
|
95
97
|
stop() {
|
|
96
98
|
if (this.activeSound) this.activeSound.stop();
|
|
97
99
|
this.playing = false;
|
|
100
|
+
this.paused = true;
|
|
98
101
|
this._chunkIterator = null;
|
|
99
102
|
this.activeSound = null;
|
|
100
103
|
this.events.trigger('stop');
|
|
@@ -143,7 +146,7 @@ export default class AbstractTTSEngine {
|
|
|
143
146
|
this.events.off('voiceschanged', this.updateBestVoice);
|
|
144
147
|
this.voice = this.getVoices().find(voice => voice.voiceURI === voiceURI);
|
|
145
148
|
// if the current book has a language set, store the selected voice with the book language as a suffix
|
|
146
|
-
if (this.opts.bookLanguage) {
|
|
149
|
+
if (this.opts.bookLanguage && hasLocalStorage()) {
|
|
147
150
|
localStorage.setItem(`BRtts-voice-${this.opts.bookLanguage}`, this.voice.voiceURI);
|
|
148
151
|
}
|
|
149
152
|
if (this.activeSound) this.activeSound.setVoice(this.voice);
|
|
@@ -247,7 +250,7 @@ export default class AbstractTTSEngine {
|
|
|
247
250
|
* @return {SpeechSynthesisVoice | undefined}
|
|
248
251
|
*/
|
|
249
252
|
static getMatchingStoredVoice(voices, bookLanguage) {
|
|
250
|
-
const storedVoice = localStorage.getItem(`BRtts-voice-${bookLanguage}`);
|
|
253
|
+
const storedVoice = hasLocalStorage() && localStorage.getItem(`BRtts-voice-${bookLanguage}`);
|
|
251
254
|
return (storedVoice ? voices.find(v => v.voiceURI === storedVoice) : undefined);
|
|
252
255
|
}
|
|
253
256
|
|
package/src/plugins/tts/utils.js
CHANGED
|
@@ -64,3 +64,18 @@ function searchForISO6391(language, columnsToSearch) {
|
|
|
64
64
|
}
|
|
65
65
|
return null;
|
|
66
66
|
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Checks whether the current browser supports localStorage or
|
|
70
|
+
* if the current context has access to it.
|
|
71
|
+
* @return {boolean}
|
|
72
|
+
*/
|
|
73
|
+
export function hasLocalStorage() {
|
|
74
|
+
try {
|
|
75
|
+
return !!window.localStorage;
|
|
76
|
+
} catch (e) {
|
|
77
|
+
// Will throw in sandboxed iframe
|
|
78
|
+
// DOMException: Window.localStorage getter: Forbidden in a sandboxed document without the 'allow-same-origin' flag.
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -40,4 +40,18 @@ describe("SelectionObserver", () => {
|
|
|
40
40
|
observer._onSelectionChange();
|
|
41
41
|
expect(handler.callCount).toBe(2);
|
|
42
42
|
});
|
|
43
|
+
|
|
44
|
+
test('Only fires when selection started in selector', () => {
|
|
45
|
+
const handler = sinon.spy();
|
|
46
|
+
const observer = new SelectionObserver(".text-layer", handler);
|
|
47
|
+
const target = document.createElement("div");
|
|
48
|
+
target.classList.add("text-layer");
|
|
49
|
+
|
|
50
|
+
// stub window.getSelection
|
|
51
|
+
const getSelectionStub = sinon.stub(window, "getSelection");
|
|
52
|
+
getSelectionStub.returns({ toString: () => "test", anchorNode: document.body });
|
|
53
|
+
observer._onSelectionChange();
|
|
54
|
+
expect(handler.callCount).toBe(0);
|
|
55
|
+
expect(observer.selecting).toBe(false);
|
|
56
|
+
});
|
|
43
57
|
});
|
|
@@ -4,7 +4,9 @@ import BookReader from "@/src/BookReader.js";
|
|
|
4
4
|
import "@/src/plugins/plugin.chapters.js";
|
|
5
5
|
import { BookModel } from "@/src/BookReader/BookModel";
|
|
6
6
|
import { deepCopy } from "../utils";
|
|
7
|
+
/** @typedef {import('@/src/plugins/plugin.chapters').TocEntry} TocEntry */
|
|
7
8
|
|
|
9
|
+
/** @type {TocEntry[]} */
|
|
8
10
|
const SAMPLE_TOC = [{
|
|
9
11
|
"pagenum": "3",
|
|
10
12
|
"level": 1,
|
|
@@ -34,16 +36,15 @@ const SAMPLE_TOC = [{
|
|
|
34
36
|
"pageIndex": 40,
|
|
35
37
|
}];
|
|
36
38
|
|
|
39
|
+
/** @type {TocEntry[]} */
|
|
37
40
|
const SAMPLE_TOC_UNDEF = [
|
|
38
41
|
{
|
|
39
|
-
"pagenum": "undefined",
|
|
40
42
|
"level": 1,
|
|
41
43
|
"label": "CHAPTER I",
|
|
42
44
|
"type": { "key": "/type/toc_item" },
|
|
43
45
|
"title": "THE COUNTRY AND THE MISSION 1",
|
|
44
46
|
},
|
|
45
47
|
{
|
|
46
|
-
"pagenum": "undefined",
|
|
47
48
|
"level": 1,
|
|
48
49
|
"label": "CHAPTER II",
|
|
49
50
|
"type": { "key": "/type/toc_item" },
|
|
@@ -51,6 +52,18 @@ const SAMPLE_TOC_UNDEF = [
|
|
|
51
52
|
},
|
|
52
53
|
];
|
|
53
54
|
|
|
55
|
+
/** @type {TocEntry[]} */
|
|
56
|
+
const SAMPLE_TOC_OPTION = [
|
|
57
|
+
{
|
|
58
|
+
"level": 1,
|
|
59
|
+
"title": "THE COUNTRY AND THE MISSION 1",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"level": 1,
|
|
63
|
+
"title": "THE COUNTRY AND THE MISSION 2",
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
|
|
54
67
|
afterEach(() => {
|
|
55
68
|
sinon.restore();
|
|
56
69
|
});
|
|
@@ -92,7 +105,7 @@ describe("BRChaptersPlugin", () => {
|
|
|
92
105
|
},
|
|
93
106
|
getOpenLibraryRecord: async () => ({
|
|
94
107
|
"title": "The Adventures of Sherlock Holmes",
|
|
95
|
-
"table_of_contents": deepCopy(
|
|
108
|
+
"table_of_contents": deepCopy(SAMPLE_TOC_OPTION),
|
|
96
109
|
"ocaid": "adventureofsherl0000unse",
|
|
97
110
|
}),
|
|
98
111
|
_chaptersRender: sinon.stub(),
|
|
@@ -100,6 +113,41 @@ describe("BRChaptersPlugin", () => {
|
|
|
100
113
|
await BookReader.prototype._chapterInit.call(fakeBR);
|
|
101
114
|
expect(fakeBR._chaptersRender.callCount).toBe(1);
|
|
102
115
|
});
|
|
116
|
+
|
|
117
|
+
test("does not fetch open library record if table of contents in options", async () => {
|
|
118
|
+
const fakeBR = {
|
|
119
|
+
options: {
|
|
120
|
+
table_of_contents: deepCopy(SAMPLE_TOC_UNDEF),
|
|
121
|
+
},
|
|
122
|
+
bind: sinon.stub(),
|
|
123
|
+
getOpenLibraryRecord: sinon.stub(),
|
|
124
|
+
_chaptersRender: sinon.stub(),
|
|
125
|
+
};
|
|
126
|
+
await BookReader.prototype._chapterInit.call(fakeBR);
|
|
127
|
+
expect(fakeBR.getOpenLibraryRecord.callCount).toBe(0);
|
|
128
|
+
expect(fakeBR._chaptersRender.callCount).toBe(1);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("converts leafs and pagenums to page index", async () => {
|
|
132
|
+
const table_of_contents = deepCopy(SAMPLE_TOC_UNDEF);
|
|
133
|
+
table_of_contents[0].leaf = 0;
|
|
134
|
+
table_of_contents[1].pagenum = '17';
|
|
135
|
+
const fakeBR = {
|
|
136
|
+
options: {
|
|
137
|
+
table_of_contents,
|
|
138
|
+
},
|
|
139
|
+
bind: sinon.stub(),
|
|
140
|
+
book: {
|
|
141
|
+
leafNumToIndex: (leaf) => leaf + 1,
|
|
142
|
+
getPageIndex: (str) => parseFloat(str),
|
|
143
|
+
},
|
|
144
|
+
_chaptersRender: sinon.stub(),
|
|
145
|
+
};
|
|
146
|
+
await BookReader.prototype._chapterInit.call(fakeBR);
|
|
147
|
+
expect(fakeBR._chaptersRender.callCount).toBe(1);
|
|
148
|
+
expect(fakeBR._tocEntries[0].pageIndex).toBe(1);
|
|
149
|
+
expect(fakeBR._tocEntries[1].pageIndex).toBe(17);
|
|
150
|
+
});
|
|
103
151
|
});
|
|
104
152
|
|
|
105
153
|
describe('_chaptersRender', () => {
|