@internetarchive/bookreader 5.0.0-101 → 5.0.0-103
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/474.js +1 -1
- package/BookReader/474.js.map +1 -1
- package/BookReader/BookReader.css +71 -8
- package/BookReader/BookReader.js +1 -1
- package/BookReader/BookReader.js.LICENSE.txt +1 -1
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +148 -109
- package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +13 -1
- 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/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 -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/slider-toggle.svg +1 -0
- package/BookReader/icons/thumbnails.svg +1 -1
- package/BookReader/icons/voice.svg +1 -1
- package/BookReader/icons/volume-full.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_bookmark.svg +1 -1
- package/BookReader/images/icon_gear.svg +1 -1
- package/BookReader/images/icon_hamburger.svg +1 -1
- package/BookReader/images/icon_home.svg +1 -1
- package/BookReader/images/icon_info.svg +1 -1
- package/BookReader/images/icon_one_page.svg +1 -1
- package/BookReader/images/icon_pause.svg +1 -1
- package/BookReader/images/icon_play.svg +1 -1
- package/BookReader/images/icon_playback-rate.svg +1 -1
- package/BookReader/images/icon_search_button.svg +1 -1
- package/BookReader/images/icon_share.svg +1 -1
- package/BookReader/images/icon_skip-back.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/images/translate.svg +1 -1
- package/BookReader/jquery-3.js +1 -1
- 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 +2 -2
- package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -1
- package/BookReader/plugins/plugin.chapters.js.map +1 -1
- package/BookReader/plugins/plugin.experiments.js +1 -1
- package/BookReader/plugins/plugin.experiments.js.LICENSE.txt +1 -1
- package/BookReader/plugins/plugin.experiments.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.iiif.js +1 -1
- package/BookReader/plugins/plugin.iiif.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.LICENSE.txt +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.LICENSE.txt +1 -1
- package/BookReader/plugins/plugin.text_selection.js.map +1 -1
- package/BookReader/plugins/plugin.translate.js +4 -4
- package/BookReader/plugins/plugin.translate.js.LICENSE.txt +1 -1
- package/BookReader/plugins/plugin.translate.js.map +1 -1
- package/BookReader/plugins/plugin.tts.js +1 -1
- package/BookReader/plugins/plugin.tts.js.LICENSE.txt +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/plugins/translator-worker.js +1 -1
- package/BookReader/plugins/translator-worker.js.map +1 -1
- package/BookReader/webcomponents-bundle.js +1 -1
- package/BookReader/webcomponents-bundle.js.map +1 -1
- package/package.json +21 -21
- package/src/BookNavigator/assets/button-base.js +0 -1
- package/src/BookNavigator/bookmarks/bookmarks-provider.js +1 -1
- package/src/BookNavigator/downloads/downloads-provider.js +1 -1
- package/src/BookNavigator/search/search-provider.js +5 -1
- package/src/BookNavigator/search/search-results.js +84 -63
- package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +5 -5
- package/src/BookNavigator/visual-adjustments/visual-adjustments.js +77 -59
- package/src/BookReader/Navbar/Navbar.js +61 -73
- package/src/BookReader/options.js +6 -0
- package/src/BookReader.js +12 -0
- package/src/assets/icons/slider-toggle.svg +1 -0
- package/src/css/_BRnav.scss +57 -4
- package/src/css/_icons.scss +7 -0
- package/src/plugins/plugin.chapters.js +1 -1
- package/src/plugins/plugin.experiments.js +1 -1
- package/src/plugins/plugin.text_selection.js +9 -0
- package/src/plugins/search/plugin.search.js +4 -0
- package/src/plugins/search/utils.js +8 -1
- package/src/plugins/search/view.js +1 -1
- package/src/plugins/translate/TranslationManager.js +6 -4
- package/src/plugins/tts/utils.js +43 -17
|
@@ -23,18 +23,23 @@ export class Navbar {
|
|
|
23
23
|
|
|
24
24
|
/** @type {Object} controls will be switch over "this.maximumControls" */
|
|
25
25
|
this.minimumControls = [
|
|
26
|
-
'viewmode',
|
|
26
|
+
'toggle_slider', 'viewmode',
|
|
27
27
|
];
|
|
28
28
|
/** @type {Object} controls will be switch over "this.minimumControls" */
|
|
29
29
|
this.maximumControls = [
|
|
30
|
-
'book_left', 'book_right', 'zoom_in', 'zoom_out', 'onepg', 'twopg', 'thumb',
|
|
30
|
+
'BRnavpos', 'book_left', 'book_right', 'zoom_in', 'zoom_out', 'onepg', 'twopg', 'thumb',
|
|
31
31
|
];
|
|
32
32
|
|
|
33
33
|
this.updateNavIndexThrottled = throttle(this.updateNavIndex.bind(this), 250, false);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
/**
|
|
37
|
+
* @param {string} controlName
|
|
38
|
+
* @param {Object} optionOverrides
|
|
39
|
+
*/
|
|
40
|
+
controlFor(controlName, optionOverrides = null) {
|
|
41
|
+
const brOption = this.br.options.controls[controlName];
|
|
42
|
+
const option = Object.assign({},brOption, optionOverrides);
|
|
38
43
|
if (!option.visible) { return ''; }
|
|
39
44
|
if (option.template) {
|
|
40
45
|
return `<li>${option.template(this.br)}</li>`;
|
|
@@ -50,6 +55,7 @@ export class Navbar {
|
|
|
50
55
|
/** @private */
|
|
51
56
|
_renderControls() {
|
|
52
57
|
return [
|
|
58
|
+
'toggleSlider',
|
|
53
59
|
'bookLeft',
|
|
54
60
|
'bookRight',
|
|
55
61
|
'onePage',
|
|
@@ -126,6 +132,9 @@ export class Navbar {
|
|
|
126
132
|
|
|
127
133
|
// Map of jIcon class -> click handler
|
|
128
134
|
const navigationControls = {
|
|
135
|
+
toggle_slider: () => {
|
|
136
|
+
this.br.toggleSlider();
|
|
137
|
+
},
|
|
129
138
|
book_left: () => {
|
|
130
139
|
this.br.trigger(EVENTS.stop);
|
|
131
140
|
this.br.left();
|
|
@@ -199,71 +208,48 @@ export class Navbar {
|
|
|
199
208
|
* Switch navbar controls on mobile and desktop
|
|
200
209
|
*/
|
|
201
210
|
switchNavbarControls() {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
} else {
|
|
209
|
-
this.showMaximumNavPageNum();
|
|
210
|
-
// we don't want navbar controls switching with liner-notes
|
|
211
|
-
if (this.br.options.bookType !== 'linerNotes') {
|
|
212
|
-
this.showMaximumNavbarControls();
|
|
211
|
+
// we don't want navbar controls switching with liner-notes
|
|
212
|
+
if (this.br.options.bookType !== 'linerNotes') {
|
|
213
|
+
if (this.br.refs.$brContainer.prop('clientWidth') < 640) {
|
|
214
|
+
this.showMobileControls();
|
|
215
|
+
} else {
|
|
216
|
+
this.showDesktopControls();
|
|
213
217
|
}
|
|
214
218
|
}
|
|
215
219
|
}
|
|
216
220
|
|
|
217
221
|
/**
|
|
218
|
-
* Switch Book
|
|
219
|
-
|
|
220
|
-
showMinimumNavPageNum() {
|
|
221
|
-
const minElement = document.querySelector('.BRcurrentpage.BRmin');
|
|
222
|
-
const maxElement = document.querySelector('.BRcurrentpage.BRmax');
|
|
223
|
-
|
|
224
|
-
if (minElement) minElement.classList.remove('hide');
|
|
225
|
-
if (maxElement) maxElement.classList.add('hide');
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Switch Book Nav page number display to maximum/desktop
|
|
230
|
-
*/
|
|
231
|
-
showMaximumNavPageNum() {
|
|
232
|
-
const minElement = document.querySelector('.BRcurrentpage.BRmin');
|
|
233
|
-
const maxElement = document.querySelector('.BRcurrentpage.BRmax');
|
|
234
|
-
|
|
235
|
-
if (minElement) minElement.classList.add('hide');
|
|
236
|
-
if (maxElement) maxElement.classList.remove('hide');
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Switch Book Navbar controls to minimised
|
|
241
|
-
* NOTE: only `this.minimumControls` and `this.maximumControls` switch on resize
|
|
222
|
+
* Switch Book controls to mobile mode
|
|
223
|
+
* NOTE: `this.minimumControls`, `this.maximumControls`, and .BRnavMobile switch on resize
|
|
242
224
|
*/
|
|
243
|
-
|
|
225
|
+
showMobileControls() {
|
|
244
226
|
this.minimumControls.forEach((control) => {
|
|
245
|
-
const element = document.querySelector(`.controls .${control}`);
|
|
227
|
+
const element = document.querySelector(`.BRnavMain .controls .${control}`);
|
|
246
228
|
if (element) element.classList.remove('hide');
|
|
247
229
|
});
|
|
248
230
|
this.maximumControls.forEach((control) => {
|
|
249
|
-
const element = document.querySelector(`.controls .${control}`);
|
|
231
|
+
const element = document.querySelector(`.BRnavMain .controls .${control}`);
|
|
250
232
|
if (element) element.classList.add('hide');
|
|
251
233
|
});
|
|
234
|
+
const mobileNav = document.querySelector(`.BRnavMobile`);
|
|
235
|
+
if (mobileNav) mobileNav.classList.remove('hide');
|
|
252
236
|
}
|
|
253
237
|
|
|
254
238
|
/**
|
|
255
|
-
* Switch Book
|
|
256
|
-
* NOTE:
|
|
239
|
+
* Switch Book controls to desktop mode
|
|
240
|
+
* NOTE: `this.minimumControls`, `this.maximumControls`, and .BRnavMobile switch on resize
|
|
257
241
|
*/
|
|
258
|
-
|
|
242
|
+
showDesktopControls() {
|
|
259
243
|
this.maximumControls.forEach((control) => {
|
|
260
|
-
const element = document.querySelector(`.controls .${control}`);
|
|
244
|
+
const element = document.querySelector(`.BRnavMain .controls .${control}`);
|
|
261
245
|
if (element) element.classList.remove('hide');
|
|
262
246
|
});
|
|
263
247
|
this.minimumControls.forEach((control) => {
|
|
264
|
-
const element = document.querySelector(`.controls .${control}`);
|
|
248
|
+
const element = document.querySelector(`.BRnavMain .controls .${control}`);
|
|
265
249
|
if (element) element.classList.add('hide');
|
|
266
250
|
});
|
|
251
|
+
const mobileNav = document.querySelector(`.BRnavMobile`);
|
|
252
|
+
if (mobileNav) mobileNav.classList.add('hide');
|
|
267
253
|
}
|
|
268
254
|
|
|
269
255
|
/**
|
|
@@ -282,7 +268,7 @@ export class Navbar {
|
|
|
282
268
|
|
|
283
269
|
br.refs.$BRfooter = this.$root = $(`<div class="BRfooter"></div>`);
|
|
284
270
|
br.refs.$BRnav = this.$nav = $(
|
|
285
|
-
`<div class="BRnav
|
|
271
|
+
`<div class="BRnav BRnavMobile docked">
|
|
286
272
|
${title ? `<div class="BRnavTitle">${title}</div>` : ''}
|
|
287
273
|
<nav class="BRcontrols">
|
|
288
274
|
<ul class="controls">
|
|
@@ -291,10 +277,24 @@ export class Navbar {
|
|
|
291
277
|
<div class="BRpager"></div>
|
|
292
278
|
<div class="BRnavline"></div>
|
|
293
279
|
</div>
|
|
280
|
+
</li>
|
|
281
|
+
${this.controlFor('bookLeft', {visible: true})}
|
|
282
|
+
${this.controlFor('bookRight', {visible: true})}
|
|
283
|
+
</ul>
|
|
284
|
+
</nav>
|
|
285
|
+
</div>
|
|
286
|
+
<div class="BRnav BRnavMain">
|
|
287
|
+
${title ? `<div class="BRnavTitle">${title}</div>` : ''}
|
|
288
|
+
<nav class="BRcontrols">
|
|
289
|
+
<ul class="controls">
|
|
290
|
+
<li class="scrubber">
|
|
294
291
|
<p>
|
|
295
|
-
<span class="BRcurrentpage
|
|
296
|
-
<span class="BRcurrentpage BRmin"></span>
|
|
292
|
+
<span class="BRcurrentpage"></span>
|
|
297
293
|
</p>
|
|
294
|
+
<div class="BRnavpos hide">
|
|
295
|
+
<div class="BRpager"></div>
|
|
296
|
+
<div class="BRnavline"></div>
|
|
297
|
+
</div>
|
|
298
298
|
</li>
|
|
299
299
|
${this._renderControls()}
|
|
300
300
|
</ul>
|
|
@@ -304,7 +304,8 @@ export class Navbar {
|
|
|
304
304
|
this.$root.append(this.$nav);
|
|
305
305
|
br.refs.$br.append(this.$root);
|
|
306
306
|
|
|
307
|
-
|
|
307
|
+
/** @type {JQuery} sliders */
|
|
308
|
+
const $sliders = this.$root.find('.BRpager').slider({
|
|
308
309
|
animate: true,
|
|
309
310
|
min: 0,
|
|
310
311
|
max: br.book.getNumLeafs() - 1,
|
|
@@ -312,16 +313,16 @@ export class Navbar {
|
|
|
312
313
|
range: "min",
|
|
313
314
|
});
|
|
314
315
|
|
|
315
|
-
$
|
|
316
|
+
$sliders.on('slide', (event, ui) => {
|
|
316
317
|
this.updateNavPageNum(ui.value);
|
|
317
318
|
return true;
|
|
318
319
|
});
|
|
319
320
|
|
|
320
|
-
$
|
|
321
|
+
$sliders.on('slidechange', (event, ui) => {
|
|
321
322
|
this.updateNavPageNum(ui.value);
|
|
322
323
|
// recursion prevention for jumpToIndex
|
|
323
|
-
if ($
|
|
324
|
-
$
|
|
324
|
+
if ($(event.currentTarget).data('swallowchange')) {
|
|
325
|
+
$(event.currentTarget).data('swallowchange', false);
|
|
325
326
|
} else {
|
|
326
327
|
br.jumpToIndex(ui.value);
|
|
327
328
|
}
|
|
@@ -337,10 +338,9 @@ export class Navbar {
|
|
|
337
338
|
/**
|
|
338
339
|
* Returns the textual representation of the current page for the navbar
|
|
339
340
|
* @param {number} index
|
|
340
|
-
* @param {boolean} [useMaxFormat = false]
|
|
341
341
|
* @return {string}
|
|
342
342
|
*/
|
|
343
|
-
getNavPageNumString(index
|
|
343
|
+
getNavPageNumString(index) {
|
|
344
344
|
const { br } = this;
|
|
345
345
|
// Accessible index starts at 0 (alas) so we add 1 to make human
|
|
346
346
|
const pageNum = br.book.getPageNum(index);
|
|
@@ -360,7 +360,7 @@ export class Navbar {
|
|
|
360
360
|
this.maxPageNum = maxPageNum;
|
|
361
361
|
}
|
|
362
362
|
|
|
363
|
-
return getNavPageNumHtml(index, numLeafs, pageNum, pageType, this.maxPageNum
|
|
363
|
+
return getNavPageNumHtml(index, numLeafs, pageNum, pageType, this.maxPageNum);
|
|
364
364
|
|
|
365
365
|
}
|
|
366
366
|
|
|
@@ -369,8 +369,7 @@ export class Navbar {
|
|
|
369
369
|
* @param {number} index
|
|
370
370
|
*/
|
|
371
371
|
updateNavPageNum(index) {
|
|
372
|
-
this.$root.find('.BRcurrentpage
|
|
373
|
-
this.$root.find('.BRcurrentpage.BRmin').html(this.getNavPageNumString(index));
|
|
372
|
+
this.$root.find('.BRcurrentpage').html(this.getNavPageNumString(index, true));
|
|
374
373
|
}
|
|
375
374
|
|
|
376
375
|
/**
|
|
@@ -392,25 +391,14 @@ export class Navbar {
|
|
|
392
391
|
* @param {number|string} pageNum
|
|
393
392
|
* @param {*} pageType - Deprecated
|
|
394
393
|
* @param {number} maxPageNum
|
|
395
|
-
* @param {boolean} [useMaxFormat = false]
|
|
396
394
|
* @return {string}
|
|
397
395
|
*/
|
|
398
|
-
export function getNavPageNumHtml(index, numLeafs, pageNum, pageType, maxPageNum
|
|
396
|
+
export function getNavPageNumHtml(index, numLeafs, pageNum, pageType, maxPageNum) {
|
|
399
397
|
const pageIsAsserted = pageNum[0] != 'n';
|
|
400
398
|
const pageIndex = index + 1;
|
|
401
399
|
|
|
402
400
|
if (!pageIsAsserted) {
|
|
403
401
|
pageNum = '—';
|
|
404
402
|
}
|
|
405
|
-
|
|
406
|
-
if (useMaxFormat === true) {
|
|
407
|
-
return `Page ${pageNum} (${pageIndex}/${numLeafs})`;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
if (!pageIsAsserted) {
|
|
411
|
-
return `(${pageIndex} of ${numLeafs})`;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
const bookLengthLabel = (maxPageNum && parseFloat(pageNum)) ? ` of ${maxPageNum}` : '';
|
|
415
|
-
return `${pageNum}${bookLengthLabel}`;
|
|
403
|
+
return `Page ${pageNum} (${pageIndex}/${numLeafs})`;
|
|
416
404
|
}
|
|
@@ -258,6 +258,12 @@ export const DEFAULT_OPTIONS = {
|
|
|
258
258
|
getEmbedCode: null,
|
|
259
259
|
|
|
260
260
|
controls: {
|
|
261
|
+
toggleSlider: {
|
|
262
|
+
visible: true,
|
|
263
|
+
label: 'Toggle page controls',
|
|
264
|
+
className: 'toggle_slider',
|
|
265
|
+
iconClassName: 'toggle-slider',
|
|
266
|
+
},
|
|
261
267
|
bookLeft: {
|
|
262
268
|
visible: true,
|
|
263
269
|
label: 'Flip left',
|
package/src/BookReader.js
CHANGED
|
@@ -1380,6 +1380,17 @@ BookReader.prototype.exitFullScreen = async function () {
|
|
|
1380
1380
|
this.refs.$br.removeClass('BRfullscreenAnimation');
|
|
1381
1381
|
};
|
|
1382
1382
|
|
|
1383
|
+
/**
|
|
1384
|
+
* Toggles the mobile slider and page controls
|
|
1385
|
+
*/
|
|
1386
|
+
BookReader.prototype.toggleSlider = function () {
|
|
1387
|
+
const toggleButton = this.refs.$BRnav.find('.toggle_slider');
|
|
1388
|
+
const mobileControls = this.refs.$br.find('.BRnavMobile');
|
|
1389
|
+
|
|
1390
|
+
toggleButton.toggleClass('active');
|
|
1391
|
+
mobileControls.toggleClass('docked');
|
|
1392
|
+
};
|
|
1393
|
+
|
|
1383
1394
|
/**
|
|
1384
1395
|
* Returns the currently active index
|
|
1385
1396
|
* @return {number}
|
|
@@ -1734,6 +1745,7 @@ BookReader.prototype.initUIStrings = function() {
|
|
|
1734
1745
|
'.share': 'Share this book',
|
|
1735
1746
|
'.info': 'About this book',
|
|
1736
1747
|
'.full': 'Toggle fullscreen',
|
|
1748
|
+
'.toggle_slider': 'Toggle page controls',
|
|
1737
1749
|
'.book_left': 'Flip left',
|
|
1738
1750
|
'.book_right': 'Flip right',
|
|
1739
1751
|
'.play': 'Play',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg height="100" viewBox="0 0 100 100" width="100" xmlns="http://www.w3.org/2000/svg"><g fill="#fff" fill-rule="evenodd" transform="translate(0 23)"><path d="m35 0v54l-35-27.8266318zm30 0 35 26.1733682-35 27.8266318z"/><circle cx="50" cy="27.236059" r="10"/></g></svg>
|
package/src/css/_BRnav.scss
CHANGED
|
@@ -118,7 +118,6 @@
|
|
|
118
118
|
height: 100%;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
|
|
122
121
|
.BRToolbarButton {
|
|
123
122
|
.icon {
|
|
124
123
|
width: $toolbarHeight;
|
|
@@ -226,6 +225,12 @@
|
|
|
226
225
|
border: none;
|
|
227
226
|
}
|
|
228
227
|
|
|
228
|
+
&.ui-slider-docked {
|
|
229
|
+
height: 1px;
|
|
230
|
+
width: 100%;
|
|
231
|
+
margin: 0px;
|
|
232
|
+
}
|
|
233
|
+
|
|
229
234
|
.ui-slider-horizontal .ui-slider-handle,
|
|
230
235
|
.ui-slider-handle {
|
|
231
236
|
position: absolute;
|
|
@@ -262,10 +267,10 @@
|
|
|
262
267
|
}
|
|
263
268
|
.BRcurrentpage {
|
|
264
269
|
display: inline-block;
|
|
265
|
-
text-align:
|
|
270
|
+
text-align: left;
|
|
266
271
|
padding: 0 0 0 0;
|
|
267
272
|
font-size: $brFontSizeSmaller;
|
|
268
|
-
margin-left:
|
|
273
|
+
margin-left: 15px;
|
|
269
274
|
margin-right: 10px;
|
|
270
275
|
line-height: 1;
|
|
271
276
|
}
|
|
@@ -310,7 +315,6 @@
|
|
|
310
315
|
.BRnavline .BRchapter { display: none; }
|
|
311
316
|
|
|
312
317
|
.BRpager.ui-slider {
|
|
313
|
-
height: 10px;
|
|
314
318
|
top: math.div($brNavHeightMobile, 2) - 5px;
|
|
315
319
|
}
|
|
316
320
|
}
|
|
@@ -325,3 +329,52 @@
|
|
|
325
329
|
.DrawerSettingsWrapper .zoom_in {
|
|
326
330
|
background-position: -1384px center;
|
|
327
331
|
}
|
|
332
|
+
|
|
333
|
+
.BRnavMobile {
|
|
334
|
+
box-sizing: content-box;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.BRnavMobile.docked {
|
|
338
|
+
height: 0px;
|
|
339
|
+
border: none;
|
|
340
|
+
.BRcontrols .scrubber .BRpager.ui-slider {
|
|
341
|
+
top: -1px;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
.ui-slider,
|
|
345
|
+
.ui-slider-range {
|
|
346
|
+
height: 2px;
|
|
347
|
+
border-radius: 0px;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.BRnavpos {
|
|
351
|
+
margin: 0px;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.scrubber {
|
|
355
|
+
margin: 0px;
|
|
356
|
+
padding: 0px;
|
|
357
|
+
height: 0px;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.controls {
|
|
361
|
+
padding: 0px;
|
|
362
|
+
background-color: transparent;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.BRnavline {
|
|
366
|
+
display: none;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
.ui-slider-handle {
|
|
370
|
+
display: none;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
button {
|
|
374
|
+
display: none;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
.BRnavMobile.hide {
|
|
379
|
+
display: none;
|
|
380
|
+
}
|
package/src/css/_icons.scss
CHANGED
|
@@ -110,7 +110,7 @@ export class ChaptersPlugin extends BookReaderPlugin {
|
|
|
110
110
|
_render() {
|
|
111
111
|
this.br.shell.menuProviders['chapters'] = {
|
|
112
112
|
id: 'chapters',
|
|
113
|
-
icon: html`<ia-icon-toc style="width: var(--iconWidth); height: var(--iconHeight);"></ia-icon-toc>`,
|
|
113
|
+
icon: html`<ia-icon-toc aria-hidden="true" role="presentation" style="width: var(--iconWidth); height: var(--iconHeight);"></ia-icon-toc>`,
|
|
114
114
|
label: 'Table of Contents',
|
|
115
115
|
component: html`<br-chapters-panel
|
|
116
116
|
.contents="${this._tocEntries}"
|
|
@@ -174,7 +174,7 @@ export class ExperimentsPlugin extends BookReaderPlugin {
|
|
|
174
174
|
this.br.shell.menuProviders['experiments'] = {
|
|
175
175
|
id: 'experiments',
|
|
176
176
|
icon: html`
|
|
177
|
-
<img src="${this.br.options.imagesBaseURL}/icon_experiment.svg" width="26"/>
|
|
177
|
+
<img src="${this.br.options.imagesBaseURL}/icon_experiment.svg" alt="" width="26"/>
|
|
178
178
|
`,
|
|
179
179
|
label: 'Experiments',
|
|
180
180
|
component: html`<br-experiments-panel
|
|
@@ -137,6 +137,15 @@ export class TextSelectionPlugin extends BookReaderPlugin {
|
|
|
137
137
|
if ($textLayers.length) return;
|
|
138
138
|
const XMLpage = await this.getPageText(pageIndex);
|
|
139
139
|
if (!XMLpage) return;
|
|
140
|
+
// Seeing some 0 left and 0 top coordinates in OCR, remove it entirely to prevent odd rendering
|
|
141
|
+
// eg https://archive.org/details/illustratedbooko00robe/page/n11/mode/2up
|
|
142
|
+
$(XMLpage).find("WORD").filter((_, ele) => {
|
|
143
|
+
const [left, , , top] = ele.getAttribute('coords').split(",").map(parseFloat);
|
|
144
|
+
if (left == 0 && top == 0) {
|
|
145
|
+
console.error("Found invalid ocr word coordinates");
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
}).remove();
|
|
140
149
|
recursivelyAddCoords(XMLpage);
|
|
141
150
|
|
|
142
151
|
const totalWords = $(XMLpage).find("WORD").length;
|
|
@@ -26,6 +26,7 @@ import SearchView from './view.js';
|
|
|
26
26
|
import { marshallSearchResults } from './utils.js';
|
|
27
27
|
import { BookReaderPlugin } from '../../BookReaderPlugin.js';
|
|
28
28
|
import { applyVariables } from '../../util/strings.js';
|
|
29
|
+
import { toISO6391 } from '../tts/utils.js';
|
|
29
30
|
/** @typedef {import('../../BookReader/PageContainer').PageContainer} PageContainer */
|
|
30
31
|
/** @typedef {import('../../BookReader/BookModel').PageIndex} PageIndex */
|
|
31
32
|
/** @typedef {import('../../BookReader/BookModel').LeafNum} LeafNum */
|
|
@@ -239,11 +240,13 @@ export class SearchPlugin extends BookReaderPlugin {
|
|
|
239
240
|
* @param {boolean} options.goToFirstResult
|
|
240
241
|
*/
|
|
241
242
|
BRSearchCallback(results, options) {
|
|
243
|
+
const bookLangCode = toISO6391(this.br.options.bookLanguage);
|
|
242
244
|
marshallSearchResults(
|
|
243
245
|
results,
|
|
244
246
|
pageNum => this.br.book.getPageNum(this.br.book.leafNumToIndex(pageNum)),
|
|
245
247
|
this.options.preTag,
|
|
246
248
|
this.options.postTag,
|
|
249
|
+
bookLangCode,
|
|
247
250
|
);
|
|
248
251
|
this.searchResults = results || null;
|
|
249
252
|
|
|
@@ -435,6 +438,7 @@ BookReader?.registerPlugin('search', SearchPlugin);
|
|
|
435
438
|
* @property {string} displayPageNumber (fake field) The page number as it should be displayed in the UI.
|
|
436
439
|
* @property {string} html (computed field) The html-escaped raw html to display in the UI.
|
|
437
440
|
* @property {string} text
|
|
441
|
+
* @property {string} lang (fake field) The ISO 639-1 language code of the book
|
|
438
442
|
* @property {Array<{ page: number, boxes: SearchInsideMatchBox[] }>} par
|
|
439
443
|
*/
|
|
440
444
|
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
import { escapeHTML, escapeRegExp } from '../../BookReader/utils.js';
|
|
3
|
+
/** @typedef {import('@/src/plugins/search/plugin.search.js').SearchInsideResults} SearchInsideResults */
|
|
4
|
+
/** @typedef {import('@/src/plugins/search/plugin.search.js').LeafNum} LeafNum */
|
|
5
|
+
/** @typedef {import('@/src/plugins/search/plugin.search.js').PageNumString} PageNumString */
|
|
2
6
|
|
|
3
7
|
/**
|
|
4
8
|
* @param {string} match
|
|
@@ -26,14 +30,17 @@ export function renderMatch(match, preTag, postTag) {
|
|
|
26
30
|
* @param {(pageNum: LeafNum) => PageNumString} displayPageNumberFn
|
|
27
31
|
* @param {string} preTag
|
|
28
32
|
* @param {string} postTag
|
|
33
|
+
* @param {string | null} bookLanguage The ISO 639-1 language code of the book
|
|
29
34
|
*/
|
|
30
|
-
export function marshallSearchResults(results, displayPageNumberFn, preTag, postTag) {
|
|
35
|
+
export function marshallSearchResults(results, displayPageNumberFn, preTag, postTag, bookLanguage) {
|
|
31
36
|
// Attach matchIndex to a few things to make it easier to identify
|
|
32
37
|
// an active/selected match
|
|
38
|
+
|
|
33
39
|
for (const [index, match] of results.matches.entries()) {
|
|
34
40
|
match.matchIndex = index;
|
|
35
41
|
match.displayPageNumber = displayPageNumberFn(match.par[0].page);
|
|
36
42
|
match.html = renderMatch(match.text, preTag, postTag);
|
|
43
|
+
match.lang = bookLanguage;
|
|
37
44
|
for (const par of match.par) {
|
|
38
45
|
for (const box of par.boxes) {
|
|
39
46
|
box.matchIndex = index;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import { Cache } from '../../util/cache.js';
|
|
3
3
|
import { BatchTranslator } from '@internetarchive/bergamot-translator/translator.js';
|
|
4
|
-
import { toISO6391 } from '../tts/utils.js';
|
|
4
|
+
import { toISO6391, toNativeName } from '../tts/utils.js';
|
|
5
5
|
|
|
6
6
|
export class TranslationManager {
|
|
7
7
|
/** @type {Cache<{index: string, response: string}>} */
|
|
@@ -36,7 +36,7 @@ export class TranslationManager {
|
|
|
36
36
|
|
|
37
37
|
constructor() {
|
|
38
38
|
//TODO Should default to the book language as the first element
|
|
39
|
-
const enModel = {code: "en", name: "English", type: "prod"};
|
|
39
|
+
const enModel = {code: "en", name: "English (en)", type: "prod"};
|
|
40
40
|
this.fromLanguages.push(enModel);
|
|
41
41
|
this.toLanguages.push(enModel);
|
|
42
42
|
}
|
|
@@ -77,10 +77,12 @@ export class TranslationManager {
|
|
|
77
77
|
// List of dev models found here https://github.com/mozilla/firefox-translations-models/tree/main/models/base
|
|
78
78
|
// There are also differences between the model types in the repo above here: https://github.com/mozilla/firefox-translations-models?tab=readme-ov-file#firefox-translations-models
|
|
79
79
|
if (firstLang !== "en") {
|
|
80
|
-
|
|
80
|
+
const name = `${toNativeName(firstLang)} (${toISO6391(firstLang)})`;
|
|
81
|
+
this.fromLanguages.push({code: firstLang, name: name, type: "prod"});
|
|
81
82
|
}
|
|
82
83
|
if (secondLang !== "en") {
|
|
83
|
-
|
|
84
|
+
const name = `${toNativeName(secondLang)} (${toISO6391(secondLang)})`;
|
|
85
|
+
this.toLanguages.push({code: secondLang, name: name, type: "prod"});
|
|
84
86
|
}
|
|
85
87
|
}
|
|
86
88
|
this._initResolve([this.modelRegistry]);
|
package/src/plugins/tts/utils.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
import langs from 'iso-language-codes';
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -24,43 +25,68 @@ export function isAndroid(userAgent = navigator.userAgent) {
|
|
|
24
25
|
const specialLangs = {
|
|
25
26
|
"zh-hans": "中文 (Zhōngwén)",
|
|
26
27
|
};
|
|
28
|
+
|
|
27
29
|
/**
|
|
28
30
|
* @typedef {string} ISO6391
|
|
29
31
|
* Language code in ISO 639-1 format. e.g. en, fr, zh
|
|
30
|
-
* Can also retrieve language native name + ISO 639-1 code
|
|
31
32
|
**/
|
|
32
33
|
|
|
33
34
|
/**
|
|
34
35
|
* @param {string} language in some format
|
|
35
|
-
* @param {boolean?} getName gets Native Name + language code if true
|
|
36
36
|
* @return {ISO6391?}
|
|
37
37
|
*/
|
|
38
|
-
export function toISO6391(language
|
|
38
|
+
export function toISO6391(language) {
|
|
39
39
|
if (!language) return null;
|
|
40
|
-
language = language.
|
|
40
|
+
language = language.toLocaleLowerCase();
|
|
41
|
+
if (specialLangs[language]) {
|
|
42
|
+
return language;
|
|
43
|
+
}
|
|
44
|
+
const codeObj = (
|
|
45
|
+
findLanguage(language, ['iso639_1']) ||
|
|
46
|
+
findLanguage(language, ['iso639_2T']) ||
|
|
47
|
+
findLanguage(language, ['iso639_2B', 'name', 'nativeName'])
|
|
48
|
+
);
|
|
49
|
+
if (codeObj) return codeObj.iso639_1;
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
41
52
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
53
|
+
/**
|
|
54
|
+
*
|
|
55
|
+
* @param {string} language
|
|
56
|
+
* @returns {string}
|
|
57
|
+
*/
|
|
58
|
+
export function toNativeName(language) {
|
|
59
|
+
if (!language) return null;
|
|
60
|
+
language = language.toLocaleLowerCase();
|
|
61
|
+
if (specialLangs[language]) {
|
|
62
|
+
return specialLangs[language];
|
|
63
|
+
}
|
|
64
|
+
const codeObj = (
|
|
65
|
+
findLanguage(language, ['iso639_1']) ||
|
|
66
|
+
findLanguage(language, ['iso639_2T']) ||
|
|
67
|
+
findLanguage(language, ['iso639_2B', 'name', 'nativeName'])
|
|
68
|
+
);
|
|
69
|
+
if (codeObj?.nativeName) return codeObj.nativeName.split(", ")[0];
|
|
70
|
+
return null;
|
|
45
71
|
}
|
|
46
72
|
|
|
73
|
+
/** @typedef {import('iso-language-codes').Code} Code */
|
|
74
|
+
|
|
47
75
|
/**
|
|
48
|
-
* Searches for the given long in the given columns.
|
|
49
76
|
* @param {string} language
|
|
50
|
-
* @param {Array<
|
|
51
|
-
* @
|
|
52
|
-
* @return {ISO6391?}
|
|
77
|
+
* @param {Array<'iso639_1' | 'iso639_2T' | 'iso639_2B' | 'nativeName' | 'name'>} fields
|
|
78
|
+
* @returns {Code | null}
|
|
53
79
|
*/
|
|
54
|
-
function
|
|
80
|
+
function findLanguage(language, fields) {
|
|
81
|
+
if (!language) return null;
|
|
82
|
+
language = language.toLowerCase();
|
|
55
83
|
for (const lang of langs) {
|
|
56
|
-
for (const
|
|
57
|
-
if (lang[
|
|
58
|
-
|
|
59
|
-
return lang.iso639_1;
|
|
84
|
+
for (const codeType of fields) {
|
|
85
|
+
if (lang[codeType]?.toLowerCase().split(", ").includes(language)) {
|
|
86
|
+
return lang;
|
|
60
87
|
}
|
|
61
88
|
}
|
|
62
89
|
}
|
|
63
|
-
if (specialLangs[language]) return `${specialLangs[language]} (${language})`;
|
|
64
90
|
return null;
|
|
65
91
|
}
|
|
66
92
|
|