@internetarchive/bookreader 5.0.0-71 → 5.0.0-73
Sign up to get free protection for your applications and to get access to all the features.
- 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', () => {
|