@internetarchive/bookreader 5.0.0-38 → 5.0.0-39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BookReader/BookReader.css +8 -0
- package/BookReader/BookReader.js +1 -1
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +99 -75
- package/BookReader/ia-bookreader-bundle.js.map +1 -1
- package/BookReader/icons/magnify-minus.svg +1 -1
- package/BookReader/icons/magnify-plus.svg +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.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/CHANGELOG.md +5 -0
- package/README.md +13 -0
- package/package.json +14 -14
- package/renovate.json +1 -1
- package/src/BookReader/Mode1UpLit.js +7 -1
- package/src/BookReader/Mode2Up.js +11 -0
- package/src/BookReader/ModeSmoothZoom.js +2 -0
- package/src/BookReader/PageContainer.js +10 -4
- package/src/BookReader/utils/ScrollClassAdder.js +31 -0
- package/src/assets/icons/magnify-minus.svg +3 -7
- package/src/assets/icons/magnify-plus.svg +3 -7
- package/src/css/_TextSelection.scss +13 -0
- package/tests/jest/BookReader/PageContainer.test.js +5 -4
- package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
- package/.husky/_/husky.sh +0 -30
- package/stat/BookNavigator/BookModel.js +0 -14
- package/stat/BookNavigator/BookNavigator.js +0 -524
- package/stat/BookNavigator/assets/bookmark-colors.js +0 -15
- package/stat/BookNavigator/assets/button-base.js +0 -61
- package/stat/BookNavigator/assets/ia-logo.js +0 -17
- package/stat/BookNavigator/assets/icon_checkmark.js +0 -6
- package/stat/BookNavigator/assets/icon_close.js +0 -3
- package/stat/BookNavigator/assets/icon_sort_asc.js +0 -5
- package/stat/BookNavigator/assets/icon_sort_desc.js +0 -5
- package/stat/BookNavigator/assets/icon_sort_neutral.js +0 -5
- package/stat/BookNavigator/assets/icon_volumes.js +0 -11
- package/stat/BookNavigator/bookmarks/bookmark-button.js +0 -64
- package/stat/BookNavigator/bookmarks/bookmark-edit.js +0 -215
- package/stat/BookNavigator/bookmarks/bookmarks-list.js +0 -285
- package/stat/BookNavigator/bookmarks/bookmarks-loginCTA.js +0 -28
- package/stat/BookNavigator/bookmarks/bookmarks-provider.js +0 -56
- package/stat/BookNavigator/bookmarks/ia-bookmarks.js +0 -523
- package/stat/BookNavigator/br-fullscreen-mgr.js +0 -82
- package/stat/BookNavigator/delete-modal-actions.js +0 -49
- package/stat/BookNavigator/downloads/downloads-provider.js +0 -72
- package/stat/BookNavigator/downloads/downloads.js +0 -139
- package/stat/BookNavigator/provider-config.js +0 -0
- package/stat/BookNavigator/search/a-search-result.js +0 -55
- package/stat/BookNavigator/search/search-provider.js +0 -180
- package/stat/BookNavigator/search/search-results.js +0 -360
- package/stat/BookNavigator/sharing.js +0 -31
- package/stat/BookNavigator/visual-adjustments/visual-adjustments-provider.js +0 -94
- package/stat/BookNavigator/visual-adjustments/visual-adjustments.js +0 -280
- package/stat/BookNavigator/volumes/volumes-provider.js +0 -83
- package/stat/BookNavigator/volumes/volumes.js +0 -178
- package/stat/BookReader/BookModel.js +0 -518
- package/stat/BookReader/DebugConsole.js +0 -54
- package/stat/BookReader/DragScrollable.js +0 -233
- package/stat/BookReader/ImageCache.js +0 -116
- package/stat/BookReader/Mode1Up.js +0 -102
- package/stat/BookReader/Mode1UpLit.js +0 -434
- package/stat/BookReader/Mode2Up.js +0 -1372
- package/stat/BookReader/ModeSmoothZoom.js +0 -177
- package/stat/BookReader/ModeThumb.js +0 -344
- package/stat/BookReader/Navbar/Navbar.js +0 -310
- package/stat/BookReader/PageContainer.js +0 -120
- package/stat/BookReader/ReduceSet.js +0 -26
- package/stat/BookReader/Toolbar/Toolbar.js +0 -384
- package/stat/BookReader/events.js +0 -20
- package/stat/BookReader/options.js +0 -324
- package/stat/BookReader/utils/HTMLDimensionsCacher.js +0 -44
- package/stat/BookReader/utils/classes.js +0 -36
- package/stat/BookReader/utils.js +0 -240
- package/stat/BookReader.js +0 -2550
- package/stat/BookReaderComponent/BookReaderComponent.js +0 -117
- package/stat/assets/icons/1up.svg +0 -12
- package/stat/assets/icons/2up.svg +0 -15
- package/stat/assets/icons/advance.svg +0 -26
- package/stat/assets/icons/chevron-right.svg +0 -1
- package/stat/assets/icons/close-circle-dark.svg +0 -1
- package/stat/assets/icons/close-circle.svg +0 -1
- package/stat/assets/icons/fullscreen.svg +0 -17
- package/stat/assets/icons/fullscreen_exit.svg +0 -17
- package/stat/assets/icons/hamburger.svg +0 -15
- package/stat/assets/icons/left-arrow.svg +0 -12
- package/stat/assets/icons/magnify-minus.svg +0 -16
- package/stat/assets/icons/magnify-plus.svg +0 -17
- package/stat/assets/icons/magnify.svg +0 -15
- package/stat/assets/icons/pause.svg +0 -23
- package/stat/assets/icons/play.svg +0 -22
- package/stat/assets/icons/playback-speed.svg +0 -34
- package/stat/assets/icons/read-aloud.svg +0 -22
- package/stat/assets/icons/review.svg +0 -22
- package/stat/assets/icons/thumbnails.svg +0 -17
- package/stat/assets/icons/voice.svg +0 -1
- package/stat/assets/icons/volume-full.svg +0 -22
- package/stat/assets/images/BRicons.png +0 -0
- package/stat/assets/images/BRicons.svg +0 -94
- package/stat/assets/images/BRicons_ia.png +0 -0
- package/stat/assets/images/back_pages.png +0 -0
- package/stat/assets/images/book_bottom_icon.png +0 -0
- package/stat/assets/images/book_down_icon.png +0 -0
- package/stat/assets/images/book_left_icon.png +0 -0
- package/stat/assets/images/book_leftmost_icon.png +0 -0
- package/stat/assets/images/book_right_icon.png +0 -0
- package/stat/assets/images/book_rightmost_icon.png +0 -0
- package/stat/assets/images/book_top_icon.png +0 -0
- package/stat/assets/images/book_up_icon.png +0 -0
- package/stat/assets/images/books_graphic.svg +0 -177
- package/stat/assets/images/booksplit.png +0 -0
- package/stat/assets/images/control_pause_icon.png +0 -0
- package/stat/assets/images/control_play_icon.png +0 -0
- package/stat/assets/images/embed_icon.png +0 -0
- package/stat/assets/images/icon-home-ia.png +0 -0
- package/stat/assets/images/icon_OL-logo-xs.png +0 -0
- package/stat/assets/images/icon_alert-xs.png +0 -0
- package/stat/assets/images/icon_book.svg +0 -12
- package/stat/assets/images/icon_bookmark.svg +0 -12
- package/stat/assets/images/icon_close-pop.png +0 -0
- package/stat/assets/images/icon_download.png +0 -0
- package/stat/assets/images/icon_gear.svg +0 -14
- package/stat/assets/images/icon_hamburger.svg +0 -20
- package/stat/assets/images/icon_home.png +0 -0
- package/stat/assets/images/icon_home.svg +0 -21
- package/stat/assets/images/icon_home_ia.png +0 -0
- package/stat/assets/images/icon_indicator.png +0 -0
- package/stat/assets/images/icon_info.svg +0 -11
- package/stat/assets/images/icon_one_page.svg +0 -8
- package/stat/assets/images/icon_pause.svg +0 -1
- package/stat/assets/images/icon_play.svg +0 -1
- package/stat/assets/images/icon_playback-rate.svg +0 -15
- package/stat/assets/images/icon_return.png +0 -0
- package/stat/assets/images/icon_search_button.svg +0 -8
- package/stat/assets/images/icon_share.svg +0 -9
- package/stat/assets/images/icon_skip-ahead.svg +0 -6
- package/stat/assets/images/icon_skip-back.svg +0 -13
- package/stat/assets/images/icon_speaker.svg +0 -18
- package/stat/assets/images/icon_speaker_open.svg +0 -10
- package/stat/assets/images/icon_thumbnails.svg +0 -12
- package/stat/assets/images/icon_toc.svg +0 -5
- package/stat/assets/images/icon_two_pages.svg +0 -9
- package/stat/assets/images/icon_zoomer.png +0 -0
- package/stat/assets/images/loading.gif +0 -0
- package/stat/assets/images/logo_icon.png +0 -0
- package/stat/assets/images/marker_chap-off.png +0 -0
- package/stat/assets/images/marker_chap-off.svg +0 -11
- package/stat/assets/images/marker_chap-off_ia.png +0 -0
- package/stat/assets/images/marker_chap-on.png +0 -0
- package/stat/assets/images/marker_chap-on.svg +0 -11
- package/stat/assets/images/marker_srch-on.svg +0 -11
- package/stat/assets/images/marker_srchchap-off.png +0 -0
- package/stat/assets/images/marker_srchchap-on.png +0 -0
- package/stat/assets/images/nav_control-dn.png +0 -0
- package/stat/assets/images/nav_control-dn_ia.png +0 -0
- package/stat/assets/images/nav_control-up.png +0 -0
- package/stat/assets/images/nav_control-up_ia.png +0 -0
- package/stat/assets/images/nav_control.png +0 -0
- package/stat/assets/images/one_page_mode_icon.png +0 -0
- package/stat/assets/images/paper-badge.png +0 -0
- package/stat/assets/images/print_icon.png +0 -0
- package/stat/assets/images/progressbar.gif +0 -0
- package/stat/assets/images/right_edges.png +0 -0
- package/stat/assets/images/slider.png +0 -0
- package/stat/assets/images/slider_ia.png +0 -0
- package/stat/assets/images/thumbnail_mode_icon.png +0 -0
- package/stat/assets/images/transparent.png +0 -0
- package/stat/assets/images/two_page_mode_icon.png +0 -0
- package/stat/assets/images/zoom_in_icon.png +0 -0
- package/stat/assets/images/zoom_out_icon.png +0 -0
- package/stat/css/BookReader.scss +0 -89
- package/stat/css/_BRBookmarks.scss +0 -29
- package/stat/css/_BRComponent.scss +0 -13
- package/stat/css/_BRfloat.scss +0 -197
- package/stat/css/_BRicon.scss +0 -48
- package/stat/css/_BRmain.scss +0 -251
- package/stat/css/_BRnav.scss +0 -359
- package/stat/css/_BRpages.scss +0 -139
- package/stat/css/_BRsearch.scss +0 -226
- package/stat/css/_BRtoolbar.scss +0 -84
- package/stat/css/_BRvendor.scss +0 -5
- package/stat/css/_MobileNav.scss +0 -194
- package/stat/css/_TextSelection.scss +0 -32
- package/stat/css/_colorbox.scss +0 -52
- package/stat/css/_controls.scss +0 -253
- package/stat/css/_icons.scss +0 -121
- package/stat/jquery-wrapper.js +0 -4
- package/stat/plugins/plugin.archive_analytics.js +0 -86
- package/stat/plugins/plugin.autoplay.js +0 -129
- package/stat/plugins/plugin.chapters.js +0 -248
- package/stat/plugins/plugin.iframe.js +0 -48
- package/stat/plugins/plugin.mobile_nav.js +0 -288
- package/stat/plugins/plugin.resume.js +0 -68
- package/stat/plugins/plugin.text_selection.js +0 -291
- package/stat/plugins/plugin.url.js +0 -198
- package/stat/plugins/plugin.vendor-fullscreen.js +0 -247
- package/stat/plugins/search/plugin.search.js +0 -439
- package/stat/plugins/search/view.js +0 -439
- package/stat/plugins/tts/AbstractTTSEngine.js +0 -249
- package/stat/plugins/tts/FestivalTTSEngine.js +0 -169
- package/stat/plugins/tts/PageChunk.js +0 -107
- package/stat/plugins/tts/PageChunkIterator.js +0 -163
- package/stat/plugins/tts/WebTTSEngine.js +0 -357
- package/stat/plugins/tts/plugin.tts.js +0 -357
- package/stat/plugins/tts/tooltip_dict.js +0 -15
- package/stat/plugins/tts/utils.js +0 -91
- package/stat/util/browserSniffing.js +0 -30
- package/stat/util/debouncer.js +0 -26
- package/stat/util/docCookies.js +0 -67
- package/stat/util/strings.js +0 -34
@@ -1,169 +0,0 @@
|
|
1
|
-
import AbstractTTSEngine from './AbstractTTSEngine.js';
|
2
|
-
import { sleep } from './utils.js';
|
3
|
-
/* global soundManager */
|
4
|
-
import 'soundmanager2';
|
5
|
-
import 'jquery.browser';
|
6
|
-
|
7
|
-
/** @typedef {import("./AbstractTTSEngine.js").TTSEngineOptions} TTSEngineOptions */
|
8
|
-
/** @typedef {import("./AbstractTTSEngine.js").AbstractTTSSound} AbstractTTSSound */
|
9
|
-
|
10
|
-
/**
|
11
|
-
* @extends AbstractTTSEngine
|
12
|
-
* TTS using Festival endpoint
|
13
|
-
**/
|
14
|
-
export default class FestivalTTSEngine extends AbstractTTSEngine {
|
15
|
-
/** @override */
|
16
|
-
static isSupported() {
|
17
|
-
return typeof(soundManager) !== 'undefined' && soundManager.supported();
|
18
|
-
}
|
19
|
-
|
20
|
-
/** @param {TTSEngineOptions} options */
|
21
|
-
constructor(options) {
|
22
|
-
super(options);
|
23
|
-
// $.browsers is sometimes undefined on some Android browsers :/
|
24
|
-
// Likely related to when $.browser was moved to npm
|
25
|
-
/** @type {'mp3' | 'ogg'} format of audio to get */
|
26
|
-
this.audioFormat = $.browser?.mozilla ? 'ogg' : 'mp3';
|
27
|
-
}
|
28
|
-
|
29
|
-
/** @override */
|
30
|
-
getVoices() {
|
31
|
-
return [
|
32
|
-
{ default: true, lang: "en-US", localService: false, name: "Festival - English (US)", voiceURI: null }
|
33
|
-
];
|
34
|
-
}
|
35
|
-
|
36
|
-
/** @override */
|
37
|
-
init() {
|
38
|
-
// setup sound manager
|
39
|
-
soundManager.setup({
|
40
|
-
debugMode: false,
|
41
|
-
// Note, there's a bug in Chrome regarding range requests.
|
42
|
-
// Flash is used as a workaround.
|
43
|
-
// See https://bugs.chromium.org/p/chromium/issues/detail?id=505707
|
44
|
-
preferFlash: true,
|
45
|
-
url: '/bookreader/BookReader/soundmanager/swf',
|
46
|
-
useHTML5Audio: true,
|
47
|
-
//flash 8 version of swf is buggy when calling play() on a sound that is still loading
|
48
|
-
flashVersion: 9
|
49
|
-
});
|
50
|
-
}
|
51
|
-
|
52
|
-
/**
|
53
|
-
* @override
|
54
|
-
* @param {number} leafIndex
|
55
|
-
* @param {number} numLeafs total number of leafs in the current book
|
56
|
-
*/
|
57
|
-
start(leafIndex, numLeafs) {
|
58
|
-
let promise = null;
|
59
|
-
|
60
|
-
// Hack for iOS
|
61
|
-
if (navigator.userAgent.match(/mobile/i)) {
|
62
|
-
promise = this.iOSCaptureUserIntentHack();
|
63
|
-
}
|
64
|
-
|
65
|
-
promise = promise || Promise.resolve();
|
66
|
-
promise.then(() => super.start(leafIndex, numLeafs));
|
67
|
-
}
|
68
|
-
|
69
|
-
/** @override */
|
70
|
-
createSound(chunk) {
|
71
|
-
return new FestivalTTSSound(this.getSoundUrl(chunk.text));
|
72
|
-
}
|
73
|
-
|
74
|
-
/**
|
75
|
-
* @private
|
76
|
-
* Get URL for audio that says this text
|
77
|
-
* @param {String} dataString the thing to say
|
78
|
-
* @return {String} url
|
79
|
-
*/
|
80
|
-
getSoundUrl(dataString) {
|
81
|
-
return 'https://' + this.opts.server + '/BookReader/BookReaderGetTTS.php?string='
|
82
|
-
+ encodeURIComponent(dataString)
|
83
|
-
+ '&format=.' + this.audioFormat;
|
84
|
-
}
|
85
|
-
|
86
|
-
/**
|
87
|
-
* @private
|
88
|
-
* Security restrictions require playback to be triggered
|
89
|
-
* by a user click/touch. This intention gets lost in the async calls
|
90
|
-
* on iOS, but, for some reason, if we start the audio here, it works.
|
91
|
-
* See https://stackoverflow.com/questions/12206631/html5-audio-cant-play-through-javascript-unless-triggered-manually-once
|
92
|
-
* @return {PromiseLike}
|
93
|
-
*/
|
94
|
-
iOSCaptureUserIntentHack() {
|
95
|
-
const sound = soundManager.createSound({ url: SILENCE_1MS[this.audioFormat] });
|
96
|
-
return new Promise(res => sound.play({onfinish: res}))
|
97
|
-
.then(() => sound.destruct());
|
98
|
-
}
|
99
|
-
}
|
100
|
-
|
101
|
-
/** @extends AbstractTTSSound */
|
102
|
-
class FestivalTTSSound {
|
103
|
-
/** @param {string} soundUrl **/
|
104
|
-
constructor(soundUrl) {
|
105
|
-
this.soundUrl = soundUrl;
|
106
|
-
/** @type {SMSound} */
|
107
|
-
this.sound = null;
|
108
|
-
this.rate = 1;
|
109
|
-
/** @type {function} calling this resolves the "play" promise */
|
110
|
-
this._finishResolver = null;
|
111
|
-
}
|
112
|
-
|
113
|
-
get loaded() {
|
114
|
-
return this.sound && this.sound.loaded;
|
115
|
-
}
|
116
|
-
|
117
|
-
load(onload) {
|
118
|
-
this.sound = soundManager.createSound({
|
119
|
-
url: this.soundUrl,
|
120
|
-
// API recommended, but only fires once play started on safari
|
121
|
-
onload: () => {
|
122
|
-
if (this.rate != 1) this.sound.setPlaybackRate(this.rate);
|
123
|
-
onload();
|
124
|
-
},
|
125
|
-
onresume: () => {
|
126
|
-
sleep(25).then(() => {
|
127
|
-
if (this.rate != 1) this.sound.setPlaybackRate(this.rate);
|
128
|
-
});
|
129
|
-
}
|
130
|
-
});
|
131
|
-
return this.sound.load();
|
132
|
-
}
|
133
|
-
|
134
|
-
play() {
|
135
|
-
return new Promise(res => {
|
136
|
-
this._finishResolver = res;
|
137
|
-
this.sound.play({ onfinish: res });
|
138
|
-
})
|
139
|
-
.then(() => this.sound.destruct());
|
140
|
-
}
|
141
|
-
|
142
|
-
/** @override */
|
143
|
-
stop() {
|
144
|
-
this.sound.stop();
|
145
|
-
return Promise.resolve();
|
146
|
-
}
|
147
|
-
|
148
|
-
/** @override */
|
149
|
-
pause() { this.sound.pause(); }
|
150
|
-
/** @override */
|
151
|
-
resume() { this.sound.resume(); }
|
152
|
-
/** @override */
|
153
|
-
setPlaybackRate(rate) {
|
154
|
-
this.rate = rate;
|
155
|
-
this.sound.setPlaybackRate(rate);
|
156
|
-
}
|
157
|
-
|
158
|
-
/** @override */
|
159
|
-
finish() {
|
160
|
-
this.sound.stop();
|
161
|
-
this._finishResolver();
|
162
|
-
}
|
163
|
-
}
|
164
|
-
|
165
|
-
/** Needed to capture the audio context for iOS hack. Generated using Audacity. */
|
166
|
-
const SILENCE_1MS = {
|
167
|
-
mp3: 'data:audio/mp3;base64,//uQxAAAAAAAAAAAAAAAAAAAAAAAWGluZwAAAA8AAAACAAACcQCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA//////////////////////////////////////////////////////////////////8AAAAeTEFNRTMuOTlyBJwAAAAAAAAAADUgJAaUQQABrgAAAnHIf8sZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//sQxAADwlwBKGAAACAAAD/AAAAEAAAAH///////////////+UBAMExBTUUzLjk5LjOqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqr/+xDEIAPAAAGkAAAAIAAANIAAAASqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqg==',
|
168
|
-
ogg: 'data:audio/ogg;base64,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',
|
169
|
-
};
|
@@ -1,107 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* Class to manage a 'chunk' (approximately a paragraph) of text on a page.
|
3
|
-
*/
|
4
|
-
export default class PageChunk {
|
5
|
-
/**
|
6
|
-
* @param {number} leafIndex
|
7
|
-
* @param {number} chunkIndex
|
8
|
-
* @param {string} text
|
9
|
-
* @param {DJVURect[]} lineRects
|
10
|
-
*/
|
11
|
-
constructor(leafIndex, chunkIndex, text, lineRects) {
|
12
|
-
this.leafIndex = leafIndex;
|
13
|
-
this.chunkIndex = chunkIndex;
|
14
|
-
this.text = text;
|
15
|
-
this.lineRects = lineRects;
|
16
|
-
}
|
17
|
-
|
18
|
-
/**
|
19
|
-
* @param {string} server
|
20
|
-
* @param {string} bookPath
|
21
|
-
* @param {number} leafIndex
|
22
|
-
* @return {Promise<PageChunk[]>}
|
23
|
-
*/
|
24
|
-
static fetch(server, bookPath, leafIndex) {
|
25
|
-
// jquery's ajax "PromiseLike" implementation is inconsistent with
|
26
|
-
// modern Promises, so convert it to a full promise (it doesn't forward
|
27
|
-
// a returned promise to the next handler in the chain, which kind of
|
28
|
-
// defeats the entire point of using promises to avoid "callback hell")
|
29
|
-
return new Promise((res, rej) => {
|
30
|
-
$.ajax({
|
31
|
-
type: 'GET',
|
32
|
-
url: `https://${server}/BookReader/BookReaderGetTextWrapper.php`,
|
33
|
-
dataType:'jsonp',
|
34
|
-
cache: true,
|
35
|
-
data: {
|
36
|
-
path: `${bookPath}_djvu.xml`,
|
37
|
-
page: leafIndex
|
38
|
-
},
|
39
|
-
error: rej,
|
40
|
-
})
|
41
|
-
.then(chunks => {
|
42
|
-
res(PageChunk._fromTextWrapperResponse(leafIndex, chunks));
|
43
|
-
});
|
44
|
-
});
|
45
|
-
}
|
46
|
-
|
47
|
-
/**
|
48
|
-
* Convert the response from BookReaderGetTextWrapper.php into a {@link PageChunk} instance
|
49
|
-
* @param {number} leafIndex
|
50
|
-
* @param {Array<[String, ...DJVURect[]]>} chunksResponse
|
51
|
-
* @return {PageChunk[]}
|
52
|
-
*/
|
53
|
-
static _fromTextWrapperResponse(leafIndex, chunksResponse) {
|
54
|
-
return chunksResponse.map((c, i) => {
|
55
|
-
const correctedLineRects = PageChunk._fixChunkRects(c.slice(1));
|
56
|
-
const correctedText = PageChunk._removeDanglingHyphens(c[0]);
|
57
|
-
return new PageChunk(leafIndex, i, correctedText, correctedLineRects);
|
58
|
-
});
|
59
|
-
}
|
60
|
-
|
61
|
-
/**
|
62
|
-
* @private
|
63
|
-
* Sometimes the first rectangle will be ridiculously wide/tall. Find those and fix them
|
64
|
-
* *NOTE*: Modifies the original array and returns it.
|
65
|
-
* *NOTE*: This should probably be fixed on the petabox side, and then removed here
|
66
|
-
* Has 2 problems:
|
67
|
-
* - If the rect is the last rect on the page (and hence the only rect in the array),
|
68
|
-
* the rect's size isn't fixed
|
69
|
-
* - Because this relies on the second rect, there's a chance it won't be the right
|
70
|
-
* width
|
71
|
-
* @param {DJVURect[]} rects
|
72
|
-
* @return {DJVURect[]}
|
73
|
-
*/
|
74
|
-
static _fixChunkRects(rects) {
|
75
|
-
if (rects.length < 2) return rects;
|
76
|
-
|
77
|
-
const [firstRect, secondRect] = rects;
|
78
|
-
const [left, bottom, right] = firstRect;
|
79
|
-
const width = right - left;
|
80
|
-
const secondHeight = secondRect[1] - secondRect[3];
|
81
|
-
const secondWidth = secondRect[2] - secondRect[0];
|
82
|
-
const secondRight = secondRect[2];
|
83
|
-
|
84
|
-
if (width > secondWidth * 30) {
|
85
|
-
// Set the end to be the same
|
86
|
-
firstRect[2] = secondRight;
|
87
|
-
// And the top to be the same height
|
88
|
-
firstRect[3] = bottom - secondHeight;
|
89
|
-
}
|
90
|
-
|
91
|
-
return rects;
|
92
|
-
}
|
93
|
-
|
94
|
-
/**
|
95
|
-
* Remove "dangling" hyphens from read aloud text to avoid TTS stuttering
|
96
|
-
* @param {string} text
|
97
|
-
* @return {string}
|
98
|
-
*/
|
99
|
-
static _removeDanglingHyphens(text) {
|
100
|
-
return text.replace(/-\s+/g, '');
|
101
|
-
}
|
102
|
-
}
|
103
|
-
|
104
|
-
/**
|
105
|
-
* @typedef {[number, number, number, number]} DJVURect
|
106
|
-
* coords are in l,b,r,t order
|
107
|
-
*/
|
@@ -1,163 +0,0 @@
|
|
1
|
-
import PageChunk from './PageChunk.js';
|
2
|
-
|
3
|
-
/**
|
4
|
-
* Class that iterates over the page chunks of a book; caching/buffering
|
5
|
-
* as much as possible to try to ensure a smooth experience.
|
6
|
-
*/
|
7
|
-
export default class PageChunkIterator {
|
8
|
-
/**
|
9
|
-
* @param {number} pageCount total number of pages
|
10
|
-
* @param {number} start page to start on
|
11
|
-
* @param {PageChunkIteratorOptions} opts
|
12
|
-
*/
|
13
|
-
constructor(pageCount, start, opts) {
|
14
|
-
this.pageCount = pageCount;
|
15
|
-
this.opts = Object.assign({}, DEFAULT_OPTS, opts);
|
16
|
-
/** Position in the chunk sequence */
|
17
|
-
this._cursor = { page: start, chunk: 0 };
|
18
|
-
/** @type {Object<number, PageChunk[]>} leaf index -> chunks*/
|
19
|
-
this._bufferedPages = {};
|
20
|
-
/** @type {Object<number, PromiseLike<PageChunk[]>} leaf index -> chunks*/
|
21
|
-
this._bufferingPages = {};
|
22
|
-
/**
|
23
|
-
* @type {Promise} promise that manages cursor modifications so that they
|
24
|
-
* happen in order triggered as opposed to order the server responds
|
25
|
-
**/
|
26
|
-
this._cursorLock = Promise.resolve();
|
27
|
-
}
|
28
|
-
|
29
|
-
/**
|
30
|
-
* Get the next chunk
|
31
|
-
* @return {PromiseLike<"__PageChunkIterator.AT_END__" | PageChunk>}
|
32
|
-
*/
|
33
|
-
next() {
|
34
|
-
return this._cursorLock = this._cursorLock
|
35
|
-
.then(() => this._nextUncontrolled());
|
36
|
-
}
|
37
|
-
|
38
|
-
/**
|
39
|
-
* Sends the cursor back 1
|
40
|
-
* @return {Promise}
|
41
|
-
**/
|
42
|
-
decrement() {
|
43
|
-
return this._cursorLock = this._cursorLock
|
44
|
-
.then(() => this._decrementUncontrolled());
|
45
|
-
}
|
46
|
-
|
47
|
-
/**
|
48
|
-
* Gets without ensuring synchronization. Since this iterator has a lot of async
|
49
|
-
* code, calling e.g. "next" twice (before the first call to next has finished)
|
50
|
-
* would cause the system to be in a weird state. To avoid that, we make sure calls
|
51
|
-
* to next and decrement (functions that modify the cursor) are synchronized,
|
52
|
-
* so that regardless how long it takes for one to respond, they'll always be executed
|
53
|
-
* in the correct order.
|
54
|
-
* @return {PromiseLike<"__PageChunkIterator.AT_END__" | PageChunk>}
|
55
|
-
*/
|
56
|
-
_nextUncontrolled() {
|
57
|
-
if (this._cursor.page == this.pageCount) {
|
58
|
-
return Promise.resolve(PageChunkIterator.AT_END);
|
59
|
-
}
|
60
|
-
|
61
|
-
this._recenterBuffer(this._cursor.page);
|
62
|
-
|
63
|
-
return this._fetchPageChunks(this._cursor.page)
|
64
|
-
.then(chunks => {
|
65
|
-
if (this._cursor.chunk == chunks.length) {
|
66
|
-
this._cursor.page++;
|
67
|
-
this._cursor.chunk = 0;
|
68
|
-
return this._nextUncontrolled();
|
69
|
-
}
|
70
|
-
return chunks[this._cursor.chunk++];
|
71
|
-
});
|
72
|
-
}
|
73
|
-
|
74
|
-
/**
|
75
|
-
* Decrements without ensuring synchronization. (See {@link PageChunkIterator._nextUncontrolled});
|
76
|
-
* @return {Promise}
|
77
|
-
*/
|
78
|
-
_decrementUncontrolled() {
|
79
|
-
let cursorChangePromise = Promise.resolve();
|
80
|
-
|
81
|
-
if (this._cursor.chunk > 0) {
|
82
|
-
this._cursor.chunk--;
|
83
|
-
} else if (this._cursor.page > 0) {
|
84
|
-
this._cursor.page--;
|
85
|
-
// Go back possibly multiple pages, because pages can be blank
|
86
|
-
cursorChangePromise = this._fetchPageChunks(this._cursor.page)
|
87
|
-
.then(prevPageChunks => {
|
88
|
-
if (prevPageChunks.length == 0) return this._decrementUncontrolled();
|
89
|
-
else this._cursor.chunk = prevPageChunks.length - 1;
|
90
|
-
});
|
91
|
-
}
|
92
|
-
|
93
|
-
return cursorChangePromise
|
94
|
-
.then(() => this._fetchPageChunks(this._cursor.page));
|
95
|
-
}
|
96
|
-
|
97
|
-
/**
|
98
|
-
* Recenter the buffer around the provided page index
|
99
|
-
* @param {number} index
|
100
|
-
*/
|
101
|
-
_recenterBuffer(index) {
|
102
|
-
const start = Math.max(0, index - this.opts.pageBufferSize);
|
103
|
-
const end = Math.min(this.pageCount, index + this.opts.pageBufferSize + 1);
|
104
|
-
for (let i = start; i < end; i++) {
|
105
|
-
this._fetchPageChunks(i);
|
106
|
-
}
|
107
|
-
|
108
|
-
this._removePageFromBuffer(start - 1);
|
109
|
-
this._removePageFromBuffer(end + 1);
|
110
|
-
}
|
111
|
-
|
112
|
-
/**
|
113
|
-
* @param {number} index
|
114
|
-
*/
|
115
|
-
_removePageFromBuffer(index) {
|
116
|
-
delete this._bufferingPages[index];
|
117
|
-
delete this._bufferedPages[index];
|
118
|
-
}
|
119
|
-
|
120
|
-
/**
|
121
|
-
* Fetches the chunks on a page; checks the buffer, so it won't make unnecessary
|
122
|
-
* requests if it's called multiple times for the same index.
|
123
|
-
* @param {number} index
|
124
|
-
* @return {Promise<PageChunk[]>}
|
125
|
-
*/
|
126
|
-
_fetchPageChunks(index) {
|
127
|
-
if (index in this._bufferingPages) return this._bufferingPages[index];
|
128
|
-
if (index in this._bufferedPages) return Promise.resolve(this._bufferedPages[index]);
|
129
|
-
|
130
|
-
this._bufferingPages[index] = this._fetchPageChunksDirect(index)
|
131
|
-
.then(chunks => {
|
132
|
-
delete this._bufferingPages[index];
|
133
|
-
this._bufferedPages[index] = chunks;
|
134
|
-
return chunks;
|
135
|
-
});
|
136
|
-
|
137
|
-
return this._bufferingPages[index];
|
138
|
-
}
|
139
|
-
|
140
|
-
/**
|
141
|
-
* Fetches a page without checking buffer
|
142
|
-
* @param {number} index
|
143
|
-
*/
|
144
|
-
_fetchPageChunksDirect(index) {
|
145
|
-
return PageChunk.fetch(this.opts.server, this.opts.bookPath, index);
|
146
|
-
}
|
147
|
-
}
|
148
|
-
|
149
|
-
PageChunkIterator.AT_END = "__PageChunkIterator.AT_END__";
|
150
|
-
|
151
|
-
/** @type {PageChunkIteratorOptions} */
|
152
|
-
const DEFAULT_OPTS = {
|
153
|
-
server: null,
|
154
|
-
bookPath: null,
|
155
|
-
pageBufferSize: 2,
|
156
|
-
};
|
157
|
-
|
158
|
-
/**
|
159
|
-
* @typedef {Object} PageChunkIteratorOptions
|
160
|
-
* @property {string} server
|
161
|
-
* @property {string} bookPath
|
162
|
-
* @property {number} [pageBufferSize] number of pages to buffer before/after the current page
|
163
|
-
*/
|