@internetarchive/bookreader 5.0.0-96 → 5.0.0-98
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 +2 -0
- package/BookReader/474.js.map +1 -0
- package/BookReader/BookReader.css +39 -34
- package/BookReader/BookReader.js +1 -1
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/bergamot-translator-worker.js +2966 -0
- package/BookReader/bergamot-translator-worker.wasm +0 -0
- package/BookReader/ia-bookreader-bundle.js +1 -1
- package/BookReader/ia-bookreader-bundle.js.map +1 -1
- package/BookReader/images/icon_experiment.svg +1 -0
- package/BookReader/images/translate.svg +1 -0
- package/BookReader/plugins/plugin.experiments.js +1 -1
- package/BookReader/plugins/plugin.experiments.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.translate.js +3 -0
- package/BookReader/plugins/plugin.translate.js.LICENSE.txt +1 -0
- package/BookReader/plugins/plugin.translate.js.map +1 -0
- package/BookReader/plugins/plugin.tts.js +1 -1
- package/BookReader/plugins/plugin.tts.js.map +1 -1
- package/BookReader/plugins/translator-worker.js +2 -0
- package/BookReader/plugins/translator-worker.js.map +1 -0
- package/BookReader/silence.mp3 +0 -0
- package/BookReader/translator-worker.js +475 -0
- package/package.json +6 -3
- package/src/BookNavigator/book-navigator.js +1 -0
- package/src/BookReader/Mode1UpLit.js +6 -1
- package/src/BookReader/Mode2UpLit.js +11 -1
- package/src/BookReader/Navbar/Navbar.js +61 -0
- package/src/BookReader/options.js +12 -8
- package/src/BookReader.js +67 -140
- package/src/assets/images/icon_experiment.svg +1 -0
- package/src/assets/images/translate.svg +1 -0
- package/src/assets/silence.mp3 +0 -0
- package/src/css/_BRnav.scss +0 -24
- package/src/css/_BRsearch.scss +1 -5
- package/src/css/_TextSelection.scss +38 -9
- package/src/plugins/plugin.experiments.js +34 -9
- package/src/plugins/plugin.text_selection.js +17 -20
- package/src/plugins/translate/TranslationManager.js +170 -0
- package/src/plugins/translate/plugin.translate.js +489 -0
- package/src/plugins/tts/AbstractTTSEngine.js +3 -4
- package/src/plugins/tts/PageChunk.js +28 -9
- package/src/plugins/tts/WebTTSEngine.js +5 -7
- package/src/plugins/tts/plugin.tts.js +40 -4
- package/src/plugins/tts/utils.js +21 -22
- package/src/util/cache.js +20 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
/** @typedef {import("../../BookReader.js").default} BookReader */
|
|
2
3
|
|
|
3
4
|
import 'jquery-ui/ui/widget.js';
|
|
@@ -120,6 +121,66 @@ export class Navbar {
|
|
|
120
121
|
});
|
|
121
122
|
}
|
|
122
123
|
|
|
124
|
+
bindControlClickHandlers() {
|
|
125
|
+
const jIcons = this.$nav.find('.BRicon');
|
|
126
|
+
|
|
127
|
+
// Map of jIcon class -> click handler
|
|
128
|
+
const navigationControls = {
|
|
129
|
+
book_left: () => {
|
|
130
|
+
this.br.trigger(EVENTS.stop);
|
|
131
|
+
this.br.left();
|
|
132
|
+
},
|
|
133
|
+
book_right: () => {
|
|
134
|
+
this.br.trigger(EVENTS.stop);
|
|
135
|
+
this.br.right();
|
|
136
|
+
},
|
|
137
|
+
book_top: this.br.first.bind(this.br),
|
|
138
|
+
book_bottom: this.br.last.bind(this.br),
|
|
139
|
+
book_leftmost: this.br.leftmost.bind(this.br),
|
|
140
|
+
book_rightmost: this.br.rightmost.bind(this.br),
|
|
141
|
+
onepg: () => {
|
|
142
|
+
this.br.switchMode('1up');
|
|
143
|
+
},
|
|
144
|
+
thumb: () => {
|
|
145
|
+
this.br.switchMode('thumb');
|
|
146
|
+
},
|
|
147
|
+
twopg: () => {
|
|
148
|
+
this.br.switchMode('2up');
|
|
149
|
+
},
|
|
150
|
+
zoom_in: () => {
|
|
151
|
+
this.br.trigger(EVENTS.stop);
|
|
152
|
+
this.br.zoom(1);
|
|
153
|
+
this.br.trigger(EVENTS.zoomIn);
|
|
154
|
+
},
|
|
155
|
+
zoom_out: () => {
|
|
156
|
+
this.br.trigger(EVENTS.stop);
|
|
157
|
+
this.br.zoom(-1);
|
|
158
|
+
this.br.trigger(EVENTS.zoomOut);
|
|
159
|
+
},
|
|
160
|
+
full: () => {
|
|
161
|
+
if (this.br.ui == 'embed') {
|
|
162
|
+
const url = this.br.$('.BRembedreturn a').attr('href');
|
|
163
|
+
window.open(url);
|
|
164
|
+
} else {
|
|
165
|
+
this.br.toggleFullscreen();
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// custom event for auto-loan-renew in ia-book-actions
|
|
171
|
+
// - to know if user is actively reading
|
|
172
|
+
this.$nav.find('nav.BRcontrols li button').on('click', () => {
|
|
173
|
+
this.br.trigger(EVENTS.userAction);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
for (const control in navigationControls) {
|
|
177
|
+
jIcons.filter(`.${control}`).on('click.bindNavigationHandlers', () => {
|
|
178
|
+
navigationControls[control]();
|
|
179
|
+
return false;
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
123
184
|
/**
|
|
124
185
|
* Toggle viewmode button to change page view
|
|
125
186
|
*/
|
|
@@ -147,21 +147,25 @@ export const DEFAULT_OPTIONS = {
|
|
|
147
147
|
**/
|
|
148
148
|
plugins: {
|
|
149
149
|
/** @type {Partial<import('../plugins/plugin.archive_analytics.js').ArchiveAnalyticsPlugin['options'>]}*/
|
|
150
|
-
archiveAnalytics:
|
|
150
|
+
archiveAnalytics: {},
|
|
151
151
|
/** @type {Partial<import('../plugins/plugin.autoplay.js').AutoplayPlugin['options'>]}*/
|
|
152
|
-
autoplay:
|
|
152
|
+
autoplay: {},
|
|
153
153
|
/** @type {Partial<import('../plugins/plugin.chapters.js').ChaptersPlugin['options']>} */
|
|
154
|
-
chapters:
|
|
154
|
+
chapters: {},
|
|
155
|
+
/** @type {Partial<import('../plugins/plugin.experiments.js').ExperimentsPlugin['options']>} */
|
|
156
|
+
experiments: {},
|
|
155
157
|
/** @type {Partial<import('../plugins/plugin.iiif.js').IiifPlugin['options']>} */
|
|
156
|
-
iiif:
|
|
158
|
+
iiif: {},
|
|
157
159
|
/** @type {Partial<import('../plugins/plugin.resume.js').ResumePlugin['options']>} */
|
|
158
|
-
resume:
|
|
160
|
+
resume: {},
|
|
159
161
|
/** @type {Partial<import('../plugins/search/plugin.search.js').SearchPlugin['options']>} */
|
|
160
|
-
search:
|
|
162
|
+
search: {},
|
|
161
163
|
/** @type {Partial<import('../plugins/plugin.text_selection.js').TextSelectionPlugin['options']>} */
|
|
162
|
-
textSelection:
|
|
164
|
+
textSelection: {},
|
|
165
|
+
/** @type {Partial<import('../plugins/translate/plugin.translate.js').TranslatePlugin['options']>} */
|
|
166
|
+
translate: {},
|
|
163
167
|
/** @type {Partial<import('../plugins/tts/plugin.tts.js').TtsPlugin['options']>} */
|
|
164
|
-
tts:
|
|
168
|
+
tts: {},
|
|
165
169
|
},
|
|
166
170
|
|
|
167
171
|
/**
|
package/src/BookReader.js
CHANGED
|
@@ -49,10 +49,47 @@ import { NAMED_REDUCE_SETS } from './BookReader/ReduceSet.js';
|
|
|
49
49
|
* @constructor
|
|
50
50
|
*/
|
|
51
51
|
export default function BookReader(overrides = {}) {
|
|
52
|
-
const options =
|
|
52
|
+
const options = BookReader.extendOptions({}, BookReader.defaultOptions, overrides, BookReader.optionOverrides);
|
|
53
53
|
this.setup(options);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Extend the default options for BookReader
|
|
58
|
+
* Accepts any number of option objects and merges them in order.
|
|
59
|
+
*
|
|
60
|
+
* Does a shallow merge of everything except plugin options. These are individually merged.
|
|
61
|
+
* @param {...Partial<BookReaderOptions>} newOptions
|
|
62
|
+
*/
|
|
63
|
+
BookReader.extendOptions = function(...newOptions) {
|
|
64
|
+
if (newOptions.length <= 1) {
|
|
65
|
+
return newOptions[0];
|
|
66
|
+
}
|
|
67
|
+
/** @type {Array<keyof BookReaderOptions>} */
|
|
68
|
+
const shallowOverrides = ['onePage', 'twoPage', 'vars'];
|
|
69
|
+
/** @type {Array<keyof BookReaderOptions>} */
|
|
70
|
+
const mapOverrides = ['plugins', 'controls'];
|
|
71
|
+
|
|
72
|
+
const result = newOptions.shift();
|
|
73
|
+
for (const opts of newOptions) {
|
|
74
|
+
for (const [key, value] of Object.entries(opts)) {
|
|
75
|
+
if (shallowOverrides.includes(key)) {
|
|
76
|
+
result[key] ||= {};
|
|
77
|
+
result[key] = Object.assign(result[key], value);
|
|
78
|
+
} else if (mapOverrides.includes(key)) {
|
|
79
|
+
result[key] ||= {};
|
|
80
|
+
for (const [name, mapValue] of Object.entries(value)) {
|
|
81
|
+
result[key][name] ||= {};
|
|
82
|
+
Object.assign(result[key][name], mapValue);
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
result[key] = value;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return result;
|
|
91
|
+
};
|
|
92
|
+
|
|
56
93
|
BookReader.version = PACKAGE_JSON.version;
|
|
57
94
|
|
|
58
95
|
// Mode constants
|
|
@@ -72,12 +109,16 @@ BookReader.PLUGINS = {
|
|
|
72
109
|
autoplay: null,
|
|
73
110
|
/** @type {typeof import('./plugins/plugin.chapters.js').ChaptersPlugin | null}*/
|
|
74
111
|
chapters: null,
|
|
112
|
+
/** @type {typeof import('./plugins/plugin.experiments.js').ExperimentsPlugin | null}*/
|
|
113
|
+
experiments: null,
|
|
75
114
|
/** @type {typeof import('./plugins/plugin.resume.js').ResumePlugin | null}*/
|
|
76
115
|
resume: null,
|
|
77
116
|
/** @type {typeof import('./plugins/search/plugin.search.js').SearchPlugin | null}*/
|
|
78
117
|
search: null,
|
|
79
118
|
/** @type {typeof import('./plugins/plugin.text_selection.js').TextSelectionPlugin | null}*/
|
|
80
119
|
textSelection: null,
|
|
120
|
+
/** @type {typeof import('./plugins/translate/plugin.translate.js').TranslatePlugin | null}*/
|
|
121
|
+
translate: null,
|
|
81
122
|
/** @type {typeof import('./plugins/tts/plugin.tts.js').TtsPlugin | null}*/
|
|
82
123
|
tts: null,
|
|
83
124
|
};
|
|
@@ -138,9 +179,11 @@ BookReader.prototype.setup = function(options) {
|
|
|
138
179
|
archiveAnalytics: BookReader.PLUGINS.archiveAnalytics ? new BookReader.PLUGINS.archiveAnalytics(this) : null,
|
|
139
180
|
autoplay: BookReader.PLUGINS.autoplay ? new BookReader.PLUGINS.autoplay(this) : null,
|
|
140
181
|
chapters: BookReader.PLUGINS.chapters ? new BookReader.PLUGINS.chapters(this) : null,
|
|
182
|
+
experiments: BookReader.PLUGINS.experiments ? new BookReader.PLUGINS.experiments(this) : null,
|
|
141
183
|
search: BookReader.PLUGINS.search ? new BookReader.PLUGINS.search(this) : null,
|
|
142
184
|
resume: BookReader.PLUGINS.resume ? new BookReader.PLUGINS.resume(this) : null,
|
|
143
185
|
textSelection: BookReader.PLUGINS.textSelection ? new BookReader.PLUGINS.textSelection(this) : null,
|
|
186
|
+
translate: BookReader.PLUGINS.translate ? new BookReader.PLUGINS.translate(this) : null,
|
|
144
187
|
tts: BookReader.PLUGINS.tts ? new BookReader.PLUGINS.tts(this) : null,
|
|
145
188
|
};
|
|
146
189
|
|
|
@@ -330,6 +373,24 @@ BookReader.prototype.setup = function(options) {
|
|
|
330
373
|
this.hasKeyFocus = true;
|
|
331
374
|
};
|
|
332
375
|
|
|
376
|
+
BookReader.prototype.initializePlugin = function(pluginName) {
|
|
377
|
+
const plugin = new BookReader.PLUGINS[pluginName](this);
|
|
378
|
+
this.plugins[pluginName] = plugin;
|
|
379
|
+
try {
|
|
380
|
+
plugin.setup(this.options.plugins?.[pluginName] ?? {});
|
|
381
|
+
this.options.plugins[pluginName] = plugin.options;
|
|
382
|
+
} catch (e) {
|
|
383
|
+
console.error(`Error setting up plugin ${pluginName} outside of regular cycle`, e);
|
|
384
|
+
throw e;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
try {
|
|
388
|
+
plugin.init();
|
|
389
|
+
} catch (e) {
|
|
390
|
+
console.error(`Error initializing plugin ${pluginName} outside of regular cycle`, e);
|
|
391
|
+
throw e;
|
|
392
|
+
}
|
|
393
|
+
};
|
|
333
394
|
/**
|
|
334
395
|
* Get all the HTML Elements that are being/can be rendered.
|
|
335
396
|
* Includes cached elements which might be rendered again.
|
|
@@ -347,6 +408,7 @@ BookReader.prototype.getActivePageContainerElements = function() {
|
|
|
347
408
|
* Get the HTML Elements for the rendered page. Note there can be more than one, since
|
|
348
409
|
* (at least as of writing) different modes can maintain different caches.
|
|
349
410
|
* @param {PageIndex} pageIndex
|
|
411
|
+
* @returns {HTMLElement[]}
|
|
350
412
|
*/
|
|
351
413
|
BookReader.prototype.getActivePageContainerElementsForIndex = function(pageIndex) {
|
|
352
414
|
return [
|
|
@@ -632,8 +694,10 @@ BookReader.prototype.init = function() {
|
|
|
632
694
|
this.initUIStrings();
|
|
633
695
|
|
|
634
696
|
// Bind to events
|
|
635
|
-
|
|
636
|
-
this.
|
|
697
|
+
this._components.navbar.bindControlClickHandlers();
|
|
698
|
+
for (const plugin of Object.values(this.plugins)) {
|
|
699
|
+
plugin._bindNavigationHandlers();
|
|
700
|
+
}
|
|
637
701
|
this.setupKeyListeners();
|
|
638
702
|
|
|
639
703
|
this.lastScroll = (new Date().getTime());
|
|
@@ -1497,141 +1561,6 @@ exposeOverrideableMethod(Toolbar, '_components.toolbar', 'buildInfoDiv');
|
|
|
1497
1561
|
BookReader.prototype.getToolBarHeight = Toolbar.prototype.getToolBarHeight;
|
|
1498
1562
|
exposeOverrideableMethod(Toolbar, '_components.toolbar', 'getToolBarHeight');
|
|
1499
1563
|
|
|
1500
|
-
/**
|
|
1501
|
-
* Bind navigation handlers
|
|
1502
|
-
*/
|
|
1503
|
-
BookReader.prototype.bindNavigationHandlers = function() {
|
|
1504
|
-
const self = this;
|
|
1505
|
-
const jIcons = this.$('.BRicon');
|
|
1506
|
-
|
|
1507
|
-
// Map of jIcon class -> click handler
|
|
1508
|
-
const navigationControls = {
|
|
1509
|
-
book_left: () => {
|
|
1510
|
-
this.trigger(BookReader.eventNames.stop);
|
|
1511
|
-
this.left();
|
|
1512
|
-
},
|
|
1513
|
-
book_right: () => {
|
|
1514
|
-
this.trigger(BookReader.eventNames.stop);
|
|
1515
|
-
this.right();
|
|
1516
|
-
},
|
|
1517
|
-
book_top: this.first.bind(this),
|
|
1518
|
-
book_bottom: this.last.bind(this),
|
|
1519
|
-
book_leftmost: this.leftmost.bind(this),
|
|
1520
|
-
book_rightmost: this.rightmost.bind(this),
|
|
1521
|
-
onepg: () => {
|
|
1522
|
-
this.switchMode(self.constMode1up);
|
|
1523
|
-
},
|
|
1524
|
-
thumb: () => {
|
|
1525
|
-
this.switchMode(self.constModeThumb);
|
|
1526
|
-
},
|
|
1527
|
-
twopg: () => {
|
|
1528
|
-
this.switchMode(self.constMode2up);
|
|
1529
|
-
},
|
|
1530
|
-
zoom_in: () => {
|
|
1531
|
-
this.trigger(BookReader.eventNames.stop);
|
|
1532
|
-
this.zoom(1);
|
|
1533
|
-
this.trigger(BookReader.eventNames.zoomIn);
|
|
1534
|
-
},
|
|
1535
|
-
zoom_out: () => {
|
|
1536
|
-
this.trigger(BookReader.eventNames.stop);
|
|
1537
|
-
this.zoom(-1);
|
|
1538
|
-
this.trigger(BookReader.eventNames.zoomOut);
|
|
1539
|
-
},
|
|
1540
|
-
full: () => {
|
|
1541
|
-
if (this.ui == 'embed') {
|
|
1542
|
-
const url = this.$('.BRembedreturn a').attr('href');
|
|
1543
|
-
window.open(url);
|
|
1544
|
-
} else {
|
|
1545
|
-
this.toggleFullscreen();
|
|
1546
|
-
}
|
|
1547
|
-
},
|
|
1548
|
-
};
|
|
1549
|
-
|
|
1550
|
-
// custom event for auto-loan-renew in ia-book-actions
|
|
1551
|
-
// - to know if user is actively reading
|
|
1552
|
-
this.$('nav.BRcontrols li button').on('click', () => {
|
|
1553
|
-
this.trigger(BookReader.eventNames.userAction);
|
|
1554
|
-
});
|
|
1555
|
-
|
|
1556
|
-
for (const control in navigationControls) {
|
|
1557
|
-
jIcons.filter(`.${control}`).on('click.bindNavigationHandlers', () => {
|
|
1558
|
-
navigationControls[control]();
|
|
1559
|
-
return false;
|
|
1560
|
-
});
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
|
-
const $brNavCntlBtmEl = this.$('.BRnavCntlBtm');
|
|
1564
|
-
const $brNavCntlTopEl = this.$('.BRnavCntlTop');
|
|
1565
|
-
|
|
1566
|
-
this.$('.BRnavCntl').click(
|
|
1567
|
-
function() {
|
|
1568
|
-
const promises = [];
|
|
1569
|
-
// TODO don't use magic constants
|
|
1570
|
-
// TODO move this to a function
|
|
1571
|
-
if ($brNavCntlBtmEl.hasClass('BRdn')) {
|
|
1572
|
-
if (self.refs.$BRtoolbar)
|
|
1573
|
-
promises.push(self.refs.$BRtoolbar.animate(
|
|
1574
|
-
{top: self.getToolBarHeight() * -1},
|
|
1575
|
-
).promise());
|
|
1576
|
-
promises.push(self.$('.BRfooter').animate({bottom: self.getFooterHeight() * -1}).promise());
|
|
1577
|
-
$brNavCntlBtmEl.addClass('BRup').removeClass('BRdn');
|
|
1578
|
-
$brNavCntlTopEl.addClass('BRdn').removeClass('BRup');
|
|
1579
|
-
self.$('.BRnavCntlBtm.BRnavCntl').animate({height:'45px'});
|
|
1580
|
-
self.$('.BRnavCntl').delay(1000).animate({opacity:.75}, 1000);
|
|
1581
|
-
} else {
|
|
1582
|
-
if (self.refs.$BRtoolbar)
|
|
1583
|
-
promises.push(self.refs.$BRtoolbar.animate({top:0}).promise());
|
|
1584
|
-
promises.push(self.$('.BRfooter').animate({bottom:0}).promise());
|
|
1585
|
-
$brNavCntlBtmEl.addClass('BRdn').removeClass('BRup');
|
|
1586
|
-
$brNavCntlTopEl.addClass('BRup').removeClass('BRdn');
|
|
1587
|
-
self.$('.BRnavCntlBtm.BRnavCntl').animate({height:'30px'});
|
|
1588
|
-
self.$('.BRvavCntl').animate({opacity:1});
|
|
1589
|
-
}
|
|
1590
|
-
$.when.apply($, promises).done(function() {
|
|
1591
|
-
// Only do full resize in auto mode and need to recalc. size
|
|
1592
|
-
if (self.mode == self.constMode2up && self.twoPage.autofit != null
|
|
1593
|
-
&& self.twoPage.autofit != 'none'
|
|
1594
|
-
) {
|
|
1595
|
-
self.resize();
|
|
1596
|
-
} else if (self.mode == self.constMode1up && self.onePage.autofit != null
|
|
1597
|
-
&& self.onePage.autofit != 'none') {
|
|
1598
|
-
self.resize();
|
|
1599
|
-
} else {
|
|
1600
|
-
// Don't do a full resize to avoid redrawing images
|
|
1601
|
-
self.resizeBRcontainer();
|
|
1602
|
-
}
|
|
1603
|
-
});
|
|
1604
|
-
},
|
|
1605
|
-
);
|
|
1606
|
-
$brNavCntlBtmEl
|
|
1607
|
-
.on("mouseover", function() {
|
|
1608
|
-
if ($(this).hasClass('BRup')) {
|
|
1609
|
-
self.$('.BRnavCntl').animate({opacity:1},250);
|
|
1610
|
-
}
|
|
1611
|
-
})
|
|
1612
|
-
.on("mouseleave", function() {
|
|
1613
|
-
if ($(this).hasClass('BRup')) {
|
|
1614
|
-
self.$('.BRnavCntl').animate({opacity:.75},250);
|
|
1615
|
-
}
|
|
1616
|
-
});
|
|
1617
|
-
$brNavCntlTopEl
|
|
1618
|
-
.on("mouseover", function() {
|
|
1619
|
-
if ($(this).hasClass('BRdn')) {
|
|
1620
|
-
self.$('.BRnavCntl').animate({opacity:1},250);
|
|
1621
|
-
}
|
|
1622
|
-
})
|
|
1623
|
-
.on("mouseleave", function() {
|
|
1624
|
-
if ($(this).hasClass('BRdn')) {
|
|
1625
|
-
self.$('.BRnavCntl').animate({opacity:.75},250);
|
|
1626
|
-
}
|
|
1627
|
-
});
|
|
1628
|
-
|
|
1629
|
-
// Call _bindNavigationHandlers on the plugins
|
|
1630
|
-
for (const plugin of Object.values(this.plugins)) {
|
|
1631
|
-
plugin._bindNavigationHandlers();
|
|
1632
|
-
}
|
|
1633
|
-
};
|
|
1634
|
-
|
|
1635
1564
|
/**************************/
|
|
1636
1565
|
/** BookModel extensions **/
|
|
1637
1566
|
/**************************/
|
|
@@ -1805,8 +1734,6 @@ BookReader.prototype.initUIStrings = function() {
|
|
|
1805
1734
|
'.book_right': 'Flip right',
|
|
1806
1735
|
'.play': 'Play',
|
|
1807
1736
|
'.pause': 'Pause',
|
|
1808
|
-
'.BRdn': 'Show/hide nav bar', // Would have to keep updating on state change to have just "Hide nav bar"
|
|
1809
|
-
'.BRup': 'Show/hide nav bar',
|
|
1810
1737
|
'.book_top': 'First page',
|
|
1811
1738
|
'.book_bottom': 'Last page',
|
|
1812
1739
|
'.book_leftmost': 'First page',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><g fill="#fff" fill-rule="evenodd"><path d="m20.5312017 91.3043478h59.513497c1.2006191 0 2.1739131-.973294 2.1739131-2.173913 0-.3822983-.1008154-.7578365-.2922774-1.0887357l-25.7859388-44.5652174c-.3886001-.6716082-1.1057054-1.0851774-1.8816356-1.0851774h-9.4292698c-.7956659 0-1.5277636.4346832-1.9086489 1.1332607l-24.2982884 44.5652174c-.5747365 1.0541176-.1861212 2.3745648.8679964 2.9493012.3192413.1740599.677043.2652642 1.0406524.2652642z"/><path d="m58.2338112 0c3.9857698 0 7.0754101 2.92605669 7.0754101 6.52173913 0 1.94814675-1.1751392 3.49748367-3.1329548 4.78763887-.7622726.5029309-1.2209368 1.3542647-1.2211436 2.2659686l-.0000001 17.2659447c0 1.4033895.3628136 2.7830137 1.0533233 4.0053358l29.9382305 52.9958632c.6905098 1.2223221 1.0533234 2.6019463 1.0533234 4.0053358 0 4.5023213-3.655118 8.1521739-8.1639346 8.1521739h-69.6705953c-1.3692898 0-2.7165851-.3439149-3.9178929-1.0000939-3.95568315-2.1606754-5.40829754-7.1143442-3.24450505-11.0643289l29.09149695-53.106279c.6571256-1.1995773 1.0015367-2.5449317 1.0015367-3.9122489l-.0000001-17.3410875c-.000193-.8514978-.3997534-1.6498707-1.0727831-2.1614374l-.1478555-.104365c-1.8735444-1.2352818-3.0298253-2.70631266-3.1268298-4.53659758l-.00663-.25182269c0-3.59709019 3.085096-6.52173913 7.07541-6.52173913zm0 5.43478261h-17.4163939c-.3341979 0-.655354.0973303-.9634683.29199092l-.1529759.10543374c-.2276736.17021467-.2742532.49276685-.1040386.72044045l.0538074.06119811.0627915.05193913.1617643.10919499c2.2021208 1.45291154 3.5596356 3.87504265 3.6577257 6.49699115l.0057053.3033755.0000002 17.3417027c0 2.2788621-.5740185 4.5211194-1.6692279 6.5204148l-29.0914969 53.106279c-.7212642 1.3166616-.2370594 2.9678845 1.0815017 3.6881097.4004359.2187263.8495344.3333646 1.3059643.3333646h69.6705953c1.5029388 0 2.7213115-1.2166175 2.7213115-2.7173913 0-.4677965-.1209379-.9276713-.3511078-1.3351119l-29.9382305-52.9958633c-1.1508495-2.0372034-1.7555389-4.336577-1.7555389-6.6755596l.0000002-17.2665599c.0005984-2.6392088 1.2800823-5.10829666 3.4230589-6.63488495l.2416409-.16570308c.2977633-.19621921.380081-.59667116.1838618-.89443446-.0526648-.07991901-.1224381-.14713032-.2042705-.1967699-.2372346-.14393755-.4815228-.22451299-.7328507-.24174888z" fill-rule="nonzero"/></g></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><g fill="#FFF"><path d="m55.6227664 40v-10.9816972c0-1.2005631.4447386-2.2302572 1.3342157-3.0890823.8894772-.858825 1.9338187-1.2888775 3.1330245-1.2901574h7.702184v6.5391015l14.2078094-10.6188404-14.2078094-10.5593242v6.6005376h-7.8252813c-3.5579086 0-6.6082065 1.2300012-9.1508934 3.6900038-2.542687 2.4600026-3.8146923 5.4095738-3.8160159 8.8487137v10.8607449z" transform="matrix(-1 0 0 1 129 0)"/><path d="m26.6227664 90v-10.9816972c0-1.2005631.4447386-2.2302572 1.3342157-3.0890823.8894772-.858825 1.9338187-1.2888775 3.1330245-1.2901574h7.702184v6.5391015l14.2078094-10.6188404-14.2078094-10.5593242v6.6005376h-7.8252813c-3.5579086 0-6.6082065 1.2300012-9.1508934 3.6900038-2.542687 2.4600026-3.8146923 5.4095738-3.8160159 8.8487137v10.8607449z" transform="matrix(1 0 0 -1 0 150)"/><g fill-rule="evenodd"><path d="m36.1711896 0c.7952259 0 1.5825239.11678603 2.361894.35035809.7793701.23357205 1.3385895.44226661 1.6776582.62608367.3390687.18381707.9354881.50929765 1.7892582.97644177v53.04711647h-41.11634795c-.26466873-.2667421-.47079323-.6253926-.61837349-1.0759518-.14758025-.4505591-.23600644-.8423796-.26527856-1.1754617v-52.7485865zm-15.8773502 11c-2.6260005.9445399-3.9390007 1.4168099-3.9390007 1.4168099.8613947 1.0405262 1.656859 2.1393299 2.3863927 3.2964109.2700118.4282536.5298575.8568906.7795373 1.2859111l-14.5207687.0008681v3l6.4238969.0000134c.8804258 3.5657294 2.3239844 6.8097976 4.3306759 9.7322048 1.0398193 1.5143213 2.176787 2.9231182 3.410903 4.2263908-3.5068695 3.0329696-7.8850877 5.246602-13.13321774 6.6415991 1.30042972 2.2665279 1.95064458 3.3997919 1.95064458 3.3997919 5.83922866-1.8768332 10.47451876-4.3674587 13.90587026-7.4718765.7278161.6172884 1.4851619 1.2034299 2.2700924 1.7596083 3.2815631 2.3252177 6.8996284 4.2293071 10.8541961 5.7122682 1.3246257-2.1759469 1.9869386-3.2639204 1.9869386-3.2639204-3.7993227-1.4042832-7.2042979-3.1143224-10.2149257-5.1301175-.8119265-.5436333-1.5953934-1.1239157-2.3504008-1.7408472 3.3115726-3.9242615 5.6922469-8.5457291 7.1440766-13.8651104l4.3889918-.0000045v-3l-12.2148765-.0011479c-.3495756-.7520023-.7243601-1.4925223-1.1243535-2.2215599-.7129337-1.2994097-1.4911578-2.5585071-2.3346725-3.7772922zm7.4469262 9.0006565c-1.3612535 4.5640835-3.3583061 8.3614158-5.9911579 11.3919968-1.0548712-1.0913671-2.041101-2.2689312-2.9598238-3.5334282-1.7358278-2.3891311-2.9991645-5.0087964-3.79001-7.858996z"/><path d="m94.1711896 45c.7952259 0 1.5825239.116786 2.361894.3503581.7793701.233572 1.3385895.4422666 1.6776582.6260837.3390687.183817.9354881.5092976 1.7892582.9764417v53.0471165h-41.116348c-.2646687-.2667421-.4707932-.6253926-.6183734-1.0759518-.1475803-.4505591-.2360065-.8423796-.2652786-1.1754617v-52.7485865zm-11.1769203 11h-7.8424068l-13.1518625 33h7.6962751l2.7277937-7.3487395h13.0057306l2.6303725 7.3487395h7.9398281zm-3.8794044 8.25 4.1351351 12.375h-8.5l4.272973-12.375z"/></g></g></svg>
|
|
Binary file
|
package/src/css/_BRnav.scss
CHANGED
|
@@ -35,14 +35,6 @@
|
|
|
35
35
|
border: 3px solid rgba(255,255,255,0.3);
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
|
|
39
|
-
.BRnavCntl {
|
|
40
|
-
z-index: $brZindexBase + 5;
|
|
41
|
-
background-color: $brColorDarkBorder;
|
|
42
|
-
}
|
|
43
|
-
.BRnavCntlBtm:hover {
|
|
44
|
-
background-color: $brColorThemeblue;
|
|
45
|
-
}
|
|
46
38
|
}
|
|
47
39
|
|
|
48
40
|
@mixin brNavLight {
|
|
@@ -66,14 +58,6 @@
|
|
|
66
58
|
border: 3px solid rgba($brColorThemeblue,0.3);
|
|
67
59
|
}
|
|
68
60
|
}
|
|
69
|
-
|
|
70
|
-
.BRnavCntl {
|
|
71
|
-
background-color: $brColorLightBorder;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
.BRnavCntlBtm:hover {
|
|
75
|
-
background-color: $brColorThemeblue;
|
|
76
|
-
}
|
|
77
61
|
}
|
|
78
62
|
|
|
79
63
|
@keyframes fadeUp {
|
|
@@ -319,20 +303,12 @@
|
|
|
319
303
|
font-size: .8em;
|
|
320
304
|
vertical-align: top;
|
|
321
305
|
}
|
|
322
|
-
.BRup {
|
|
323
|
-
background-image: url("images/nav_control-up.png");
|
|
324
|
-
background-repeat: no-repeat;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
306
|
|
|
328
307
|
/* Mobile Only */
|
|
329
308
|
@media (max-width: $brBreakPointMobile) {
|
|
330
309
|
/* hide navline chapters and search in mobile */
|
|
331
310
|
.BRnavline .BRchapter { display: none; }
|
|
332
311
|
|
|
333
|
-
.BRnavCntlBtm {
|
|
334
|
-
bottom: $brNavHeightMobile;
|
|
335
|
-
}
|
|
336
312
|
.BRpager.ui-slider {
|
|
337
313
|
height: 10px;
|
|
338
314
|
top: math.div($brNavHeightMobile, 2) - 5px;
|
package/src/css/_BRsearch.scss
CHANGED
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
// but they appear the same in the UI.
|
|
46
46
|
.searchHiliteLayer, .ttsHiliteLayer {
|
|
47
47
|
pointer-events: none;
|
|
48
|
+
z-index: 4;
|
|
48
49
|
|
|
49
50
|
rect {
|
|
50
51
|
// Note: Can't use fill-opacity ; safari inexplicably applies that to
|
|
@@ -241,11 +242,6 @@
|
|
|
241
242
|
height: 18px;
|
|
242
243
|
}
|
|
243
244
|
}
|
|
244
|
-
+ .BRnav {
|
|
245
|
-
.BRnavCntl {
|
|
246
|
-
display: none;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
245
|
}
|
|
250
246
|
}
|
|
251
247
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.BRtextLayer {
|
|
1
|
+
.BRtextLayer, .BRtranslateLayer {
|
|
2
2
|
z-index: 2;
|
|
3
3
|
position: absolute;
|
|
4
4
|
top: 0;
|
|
@@ -8,9 +8,16 @@
|
|
|
8
8
|
// Make it so right-clicking on "blank" part of text layer sends events to the image (for saving)
|
|
9
9
|
pointer-events: none;
|
|
10
10
|
cursor: text;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.BRtextLayer {
|
|
11
14
|
mix-blend-mode: multiply;
|
|
12
15
|
}
|
|
13
16
|
|
|
17
|
+
.BRtranslateLayer {
|
|
18
|
+
hyphens: auto;
|
|
19
|
+
}
|
|
20
|
+
|
|
14
21
|
.BRparagraphElement {
|
|
15
22
|
margin: 0;
|
|
16
23
|
cursor: text;
|
|
@@ -81,21 +88,20 @@
|
|
|
81
88
|
// These are Microsoft Edge specific fixed to make some of the
|
|
82
89
|
// browsers features work well. These are for the in-place
|
|
83
90
|
// translation.
|
|
91
|
+
.BRtextLayer:has([_istranslated="1"], msreadoutspan) {
|
|
92
|
+
mix-blend-mode: normal;
|
|
93
|
+
}
|
|
94
|
+
|
|
84
95
|
.BRwordElement, .BRspace {
|
|
85
96
|
&[_istranslated="1"], &[_msttexthash] {
|
|
86
|
-
background-color: #e4dccd;
|
|
87
97
|
color: black;
|
|
88
98
|
letter-spacing: unset !important;
|
|
89
|
-
background: #ccbfa7;
|
|
90
99
|
}
|
|
91
100
|
}
|
|
92
101
|
|
|
93
|
-
.BRlineElement font[_mstmutation="1"] {
|
|
94
|
-
background: #ccbfa7;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
102
|
.BRlineElement:has([_istranslated="1"], [_msttexthash]) {
|
|
98
|
-
background
|
|
103
|
+
background: rgba(248, 237, 192, 0.8);
|
|
104
|
+
backdrop-filter: blur(8px);
|
|
99
105
|
color: black;
|
|
100
106
|
text-align: justify;
|
|
101
107
|
width: inherit;
|
|
@@ -105,6 +111,29 @@
|
|
|
105
111
|
}
|
|
106
112
|
|
|
107
113
|
.BRlineElement[_msttexthash] {
|
|
108
|
-
background: #ccbfa7;
|
|
109
114
|
word-spacing: unset !important;
|
|
110
115
|
}
|
|
116
|
+
|
|
117
|
+
.BRtranslateLayer .BRparagraphElement {
|
|
118
|
+
pointer-events: auto;
|
|
119
|
+
overflow-y: auto;
|
|
120
|
+
background: rgba(248, 237, 192, 0.8);
|
|
121
|
+
backdrop-filter: blur(8px);
|
|
122
|
+
color:black;
|
|
123
|
+
line-height: 1em;
|
|
124
|
+
text-align: justify;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.BRtranslateLayer .BRparagraphElement .BRlineElement {
|
|
128
|
+
white-space: break-spaces;
|
|
129
|
+
display: inline-block;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.BRtextLayer.showingTranslation {
|
|
133
|
+
visibility: hidden;
|
|
134
|
+
pointer-events: none;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.BRtranslateLayer .BRparagraphElement.BRtranslateHidden {
|
|
138
|
+
display: none;
|
|
139
|
+
}
|
|
@@ -21,6 +21,9 @@ class ExperimentModel {
|
|
|
21
21
|
/** @type {string} */
|
|
22
22
|
learnMore;
|
|
23
23
|
|
|
24
|
+
/** @type {import("@/src/BookReader.js").default} */
|
|
25
|
+
br;
|
|
26
|
+
|
|
24
27
|
assetRoot = '/BookReader/';
|
|
25
28
|
|
|
26
29
|
enabledLoading = false;
|
|
@@ -46,10 +49,32 @@ export class ExperimentsPlugin extends BookReaderPlugin {
|
|
|
46
49
|
|
|
47
50
|
/** Where the state of this plugin is saved in localStorage */
|
|
48
51
|
localStorageKey: 'BrExperiments',
|
|
52
|
+
|
|
53
|
+
/** The experiments that should be shown in the experiments panel */
|
|
54
|
+
enabledExperiments: ['translate'],
|
|
49
55
|
}
|
|
50
56
|
|
|
51
57
|
/** @type {ExperimentModel[]} */
|
|
52
|
-
|
|
58
|
+
allExperiments = [
|
|
59
|
+
new class extends ExperimentModel {
|
|
60
|
+
name = 'translate';
|
|
61
|
+
title = 'Translate Plugin';
|
|
62
|
+
description = "Translate books directly in your browser.";
|
|
63
|
+
learnMore = 'https://mozilla.github.io/translations/';
|
|
64
|
+
icon = 'images/translate.svg';
|
|
65
|
+
enabled = false;
|
|
66
|
+
async enable({ manual = false}) {
|
|
67
|
+
await importAsScript(this.buildAssetPath('plugins/plugin.translate.js'));
|
|
68
|
+
this.br.initializePlugin('translate');
|
|
69
|
+
}
|
|
70
|
+
async disable() {
|
|
71
|
+
// need to reload to remove translate plugin script
|
|
72
|
+
// Sleep so that the event loop can finish processing before the reload
|
|
73
|
+
sleep(0).then(() => {
|
|
74
|
+
window.location.reload();
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}(),
|
|
53
78
|
new class extends ExperimentModel {
|
|
54
79
|
name = 'hypothesis';
|
|
55
80
|
title = 'Hypothes.is';
|
|
@@ -93,10 +118,11 @@ export class ExperimentsPlugin extends BookReaderPlugin {
|
|
|
93
118
|
return;
|
|
94
119
|
}
|
|
95
120
|
|
|
96
|
-
for (const experiment of this.
|
|
121
|
+
for (const experiment of this.allExperiments) {
|
|
97
122
|
// TODO: imagesBaseURL should be replaced with assetRoot everywhere
|
|
98
123
|
experiment.assetRoot = this.br.options.imagesBaseURL.replace(/images\/$/, '');
|
|
99
124
|
experiment.icon = experiment.buildAssetPath(experiment.icon);
|
|
125
|
+
experiment.br = this.br;
|
|
100
126
|
}
|
|
101
127
|
|
|
102
128
|
this._loadExperimentStates();
|
|
@@ -106,7 +132,7 @@ export class ExperimentsPlugin extends BookReaderPlugin {
|
|
|
106
132
|
|
|
107
133
|
_loadExperimentStates() {
|
|
108
134
|
const savedStates = JSON.parse(localStorage.getItem(this.options.localStorageKey) || '{}');
|
|
109
|
-
this.
|
|
135
|
+
this.allExperiments.forEach(experiment => {
|
|
110
136
|
if (savedStates[experiment.name] !== undefined) {
|
|
111
137
|
experiment.enabled = savedStates[experiment.name];
|
|
112
138
|
if (experiment.enabled) {
|
|
@@ -118,7 +144,7 @@ export class ExperimentsPlugin extends BookReaderPlugin {
|
|
|
118
144
|
|
|
119
145
|
_saveExperimentStates() {
|
|
120
146
|
const states = Object.fromEntries(
|
|
121
|
-
this.
|
|
147
|
+
this.allExperiments.map(experiment => [experiment.name, experiment.enabled]),
|
|
122
148
|
);
|
|
123
149
|
localStorage.setItem(this.options.localStorageKey, JSON.stringify(states));
|
|
124
150
|
}
|
|
@@ -145,13 +171,12 @@ export class ExperimentsPlugin extends BookReaderPlugin {
|
|
|
145
171
|
_render() {
|
|
146
172
|
this.br.shell.menuProviders['experiments'] = {
|
|
147
173
|
id: 'experiments',
|
|
148
|
-
// https://icon-sets.iconify.design/hugeicons/?icon-filter=eco-lab-02&query=lab
|
|
149
174
|
icon: html`
|
|
150
|
-
<
|
|
175
|
+
<img src="${this.br.options.imagesBaseURL}/icon_experiment.svg" width="26"/>
|
|
151
176
|
`,
|
|
152
177
|
label: 'Experiments',
|
|
153
178
|
component: html`<br-experiments-panel
|
|
154
|
-
.experiments="${this.
|
|
179
|
+
.experiments="${this.allExperiments.filter(experiment => this.options.enabledExperiments.includes(experiment.name))}"
|
|
155
180
|
@connected="${e => this._panel = e.target}"
|
|
156
181
|
@toggle="${async e => {
|
|
157
182
|
await this._toggleExperiment(e.detail.experiment, e.detail.enabled);
|
|
@@ -240,14 +265,14 @@ export class BrExperimentToggle extends LitElement {
|
|
|
240
265
|
|
|
241
266
|
render() {
|
|
242
267
|
return html`
|
|
243
|
-
<div class="experiment-card">
|
|
268
|
+
<div class="experiment-card" style="margin-bottom: 10px;">
|
|
244
269
|
<div style="display: flex; align-items: center; gap: 10px;">
|
|
245
270
|
<img src="${this.icon}" style="width: 20px; height: 20px;" alt="" />
|
|
246
271
|
<div style="flex-grow: 1; font-weight: bold;">${this.title}</div>
|
|
247
272
|
</div>
|
|
248
273
|
<p style="opacity: 0.9">
|
|
249
274
|
${this.description}
|
|
250
|
-
|
|
275
|
+
${this.learnMore ? html`<a href="${this.learnMore}" target="_blank">Learn more</a>.` : ''}
|
|
251
276
|
</p>
|
|
252
277
|
<div style="display: flex">
|
|
253
278
|
<div style="flex-grow: 1;"></div>
|