mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Refactor table of contents into its own class
This commit is contained in:
parent
063ef77ff1
commit
a711c8e9f7
3 changed files with 140 additions and 62 deletions
|
@ -99,6 +99,7 @@
|
||||||
"src/components/sanatizefilename.js",
|
"src/components/sanatizefilename.js",
|
||||||
"src/components/scrollManager.js",
|
"src/components/scrollManager.js",
|
||||||
"src/components/bookPlayer/plugin.js",
|
"src/components/bookPlayer/plugin.js",
|
||||||
|
"src/components/bookPlayer/tableOfContent.js",
|
||||||
"src/components/syncplay/playbackPermissionManager.js",
|
"src/components/syncplay/playbackPermissionManager.js",
|
||||||
"src/components/syncplay/groupSelectionMenu.js",
|
"src/components/syncplay/groupSelectionMenu.js",
|
||||||
"src/components/syncplay/timeSyncManager.js",
|
"src/components/syncplay/timeSyncManager.js",
|
||||||
|
|
|
@ -9,12 +9,18 @@ import 'css!./style';
|
||||||
import 'material-icons';
|
import 'material-icons';
|
||||||
import 'paper-icon-button-light';
|
import 'paper-icon-button-light';
|
||||||
|
|
||||||
|
import TableOfContent from './tableOfContent';
|
||||||
|
|
||||||
export class BookPlayer {
|
export class BookPlayer {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.name = 'Book Player';
|
this.name = 'Book Player';
|
||||||
this.type = 'mediaplayer';
|
this.type = 'mediaplayer';
|
||||||
this.id = 'bookplayer';
|
this.id = 'bookplayer';
|
||||||
this.priority = 1;
|
this.priority = 1;
|
||||||
|
|
||||||
|
this.onDialogClosed = this.onDialogClosed.bind(this);
|
||||||
|
this.openTableOfContents = this.openTableOfContents.bind(this);
|
||||||
|
this.onWindowKeyUp = this.onWindowKeyUp.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
play(options) {
|
play(options) {
|
||||||
|
@ -24,6 +30,8 @@ export class BookPlayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
|
this.unbindEvents();
|
||||||
|
|
||||||
let elem = this._mediaElement;
|
let elem = this._mediaElement;
|
||||||
let tocElement = this._tocElement;
|
let tocElement = this._tocElement;
|
||||||
let rendition = this._rendition;
|
let rendition = this._rendition;
|
||||||
|
@ -34,7 +42,7 @@ export class BookPlayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tocElement) {
|
if (tocElement) {
|
||||||
dialogHelper.close(tocElement);
|
tocElement.destroy();
|
||||||
this._tocElement = null;
|
this._tocElement = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,9 +68,12 @@ export class BookPlayer {
|
||||||
book.package.metadata.direction === 'rtl' ? rendition.next() : rendition.prev();
|
book.package.metadata.direction === 'rtl' ? rendition.next() : rendition.prev();
|
||||||
break;
|
break;
|
||||||
case 'Escape':
|
case 'Escape':
|
||||||
dialogHelper.close(this._mediaElement);
|
|
||||||
if (this._tocElement) {
|
if (this._tocElement) {
|
||||||
dialogHelper.close(this._tocElement);
|
// Close table of contents on ESC if it is open
|
||||||
|
this._tocElement.destroy();
|
||||||
|
} else {
|
||||||
|
// Otherwise stop the entire book player
|
||||||
|
this.stop();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -72,17 +83,42 @@ export class BookPlayer {
|
||||||
this.stop();
|
this.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceLinks(contents, f) {
|
bindMediaElementEvents() {
|
||||||
let links = contents.querySelectorAll('a[href]');
|
let elem = this._mediaElement;
|
||||||
|
|
||||||
links.forEach((link) => {
|
elem.addEventListener('close', this.onDialogClosed, {once: true});
|
||||||
let href = link.getAttribute('href');
|
elem.querySelector('.btnBookplayerExit').addEventListener('click', this.onDialogClosed, {once: true});
|
||||||
|
elem.querySelector('.btnBookplayerToc').addEventListener('click', this.openTableOfContents);
|
||||||
|
}
|
||||||
|
|
||||||
link.onclick = () => {
|
bindEvents() {
|
||||||
f(href);
|
this.bindMediaElementEvents();
|
||||||
return false;
|
|
||||||
};
|
document.addEventListener('keyup', this.onWindowKeyUp);
|
||||||
});
|
// FIXME: I don't really get why document keyup event is not triggered when epub is in focus
|
||||||
|
this._rendition.on('keyup', this.onWindowKeyUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
unbindMediaElementEvents() {
|
||||||
|
let elem = this._mediaElement;
|
||||||
|
|
||||||
|
elem.removeEventListener('close', this.onDialogClosed);
|
||||||
|
elem.querySelector('.btnBookplayerExit').removeEventListener('click', this.onDialogClosed);
|
||||||
|
elem.querySelector('.btnBookplayerToc').removeEventListener('click', this.openTableOfContents);
|
||||||
|
}
|
||||||
|
|
||||||
|
unbindEvents() {
|
||||||
|
if (this._mediaElement) {
|
||||||
|
this.unbindMediaElementEvents();
|
||||||
|
}
|
||||||
|
document.removeEventListener('keyup', this.onWindowKeyUp);
|
||||||
|
if (this._rendition) {
|
||||||
|
this._rendition.off('keyup', this.onWindowKeyUp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
openTableOfContents() {
|
||||||
|
this._tocElement = new TableOfContent(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
createMediaElement() {
|
createMediaElement() {
|
||||||
|
@ -115,53 +151,7 @@ export class BookPlayer {
|
||||||
|
|
||||||
elem.innerHTML = html;
|
elem.innerHTML = html;
|
||||||
|
|
||||||
elem.querySelector('.btnBookplayerExit').addEventListener('click', () => {
|
|
||||||
dialogHelper.close(elem);
|
|
||||||
});
|
|
||||||
|
|
||||||
elem.querySelector('.btnBookplayerToc').addEventListener('click', () => {
|
|
||||||
let rendition = this._rendition;
|
|
||||||
if (rendition) {
|
|
||||||
let tocElement = dialogHelper.createDialog({
|
|
||||||
size: 'small',
|
|
||||||
autoFocus: false,
|
|
||||||
removeOnClose: true
|
|
||||||
});
|
|
||||||
tocElement.id = 'dialogToc';
|
|
||||||
|
|
||||||
let tocHtml = '<div class="topRightActionButtons">';
|
|
||||||
tocHtml += '<button is="paper-icon-button-light" class="autoSize bookplayerButton btnBookplayerTocClose hide-mouse-idle-tv" tabindex="-1"><span class="material-icons bookplayerButtonIcon close"></span></button>';
|
|
||||||
tocHtml += '</div>';
|
|
||||||
tocHtml += '<ul class="toc">';
|
|
||||||
rendition.book.navigation.forEach((chapter) => {
|
|
||||||
tocHtml += '<li>';
|
|
||||||
// Remove '../' from href
|
|
||||||
let link = chapter.href.startsWith('../') ? chapter.href.substr(3) : chapter.href;
|
|
||||||
tocHtml += `<a href="${rendition.book.path.directory + link}">${chapter.label}</a>`;
|
|
||||||
tocHtml += '</li>';
|
|
||||||
});
|
|
||||||
tocHtml += '</ul>';
|
|
||||||
tocElement.innerHTML = tocHtml;
|
|
||||||
|
|
||||||
tocElement.querySelector('.btnBookplayerTocClose').addEventListener('click', () => {
|
|
||||||
dialogHelper.close(tocElement);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.replaceLinks(tocElement, (href) => {
|
|
||||||
let relative = rendition.book.path.relative(href);
|
|
||||||
rendition.display(relative);
|
|
||||||
dialogHelper.close(tocElement);
|
|
||||||
});
|
|
||||||
|
|
||||||
this._tocElement = tocElement;
|
|
||||||
|
|
||||||
dialogHelper.open(tocElement);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
dialogHelper.open(elem);
|
dialogHelper.open(elem);
|
||||||
|
|
||||||
elem.addEventListener('close', this.onDialogClosed.bind(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._mediaElement = elem;
|
this._mediaElement = elem;
|
||||||
|
@ -201,10 +191,7 @@ export class BookPlayer {
|
||||||
this._currentSrc = downloadHref;
|
this._currentSrc = downloadHref;
|
||||||
this._rendition = rendition;
|
this._rendition = rendition;
|
||||||
return rendition.display().then(() => {
|
return rendition.display().then(() => {
|
||||||
document.addEventListener('keyup', this.onWindowKeyUp.bind(this));
|
this.bindEvents();
|
||||||
|
|
||||||
// FIXME: I don't really get why document keyup event is not triggered when epub is in focus
|
|
||||||
this._rendition.on('keyup', this.onWindowKeyUp.bind(this));
|
|
||||||
|
|
||||||
loading.hide();
|
loading.hide();
|
||||||
return resolve();
|
return resolve();
|
||||||
|
|
90
src/components/bookPlayer/tableOfContent.js
Normal file
90
src/components/bookPlayer/tableOfContent.js
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
import dialogHelper from 'dialogHelper';
|
||||||
|
|
||||||
|
export default class TableOfContent {
|
||||||
|
constructor(bookPlayer) {
|
||||||
|
this._bookPlayer = bookPlayer;
|
||||||
|
this._rendition = bookPlayer._rendition;
|
||||||
|
|
||||||
|
this.onDialogClosed = this.onDialogClosed.bind(this);
|
||||||
|
|
||||||
|
this.createMediaElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
let elem = this._elem;
|
||||||
|
if (elem) {
|
||||||
|
this.unbindEvents();
|
||||||
|
dialogHelper.close(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._bookPlayer._tocElement = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bindEvents() {
|
||||||
|
let elem = this._elem;
|
||||||
|
|
||||||
|
elem.addEventListener('close', this.onDialogClosed, {once: true});
|
||||||
|
elem.querySelector('.btnBookplayerTocClose').addEventListener('click', this.onDialogClosed, {once: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
unbindEvents() {
|
||||||
|
let elem = this._elem;
|
||||||
|
|
||||||
|
elem.removeEventListener('close', this.onDialogClosed);
|
||||||
|
elem.querySelector('.btnBookplayerTocClose').removeEventListener('click', this.onDialogClosed);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDialogClosed() {
|
||||||
|
this.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
replaceLinks(contents, f) {
|
||||||
|
let links = contents.querySelectorAll('a[href]');
|
||||||
|
|
||||||
|
links.forEach((link) => {
|
||||||
|
let href = link.getAttribute('href');
|
||||||
|
|
||||||
|
link.onclick = () => {
|
||||||
|
f(href);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createMediaElement() {
|
||||||
|
let rendition = this._rendition;
|
||||||
|
|
||||||
|
let elem = dialogHelper.createDialog({
|
||||||
|
size: 'small',
|
||||||
|
autoFocus: false,
|
||||||
|
removeOnClose: true
|
||||||
|
});
|
||||||
|
elem.id = 'dialogToc';
|
||||||
|
|
||||||
|
let tocHtml = '<div class="topRightActionButtons">';
|
||||||
|
tocHtml += '<button is="paper-icon-button-light" class="autoSize bookplayerButton btnBookplayerTocClose hide-mouse-idle-tv" tabindex="-1"><span class="material-icons bookplayerButtonIcon close"></span></button>';
|
||||||
|
tocHtml += '</div>';
|
||||||
|
tocHtml += '<ul class="toc">';
|
||||||
|
rendition.book.navigation.forEach((chapter) => {
|
||||||
|
tocHtml += '<li>';
|
||||||
|
// Remove '../' from href
|
||||||
|
let link = chapter.href.startsWith('../') ? chapter.href.substr(3) : chapter.href;
|
||||||
|
tocHtml += `<a href="${rendition.book.path.directory + link}">${chapter.label}</a>`;
|
||||||
|
tocHtml += '</li>';
|
||||||
|
});
|
||||||
|
tocHtml += '</ul>';
|
||||||
|
elem.innerHTML = tocHtml;
|
||||||
|
|
||||||
|
this.replaceLinks(elem, (href) => {
|
||||||
|
let relative = rendition.book.path.relative(href);
|
||||||
|
rendition.display(relative);
|
||||||
|
this.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
this._elem = elem;
|
||||||
|
|
||||||
|
this.bindEvents();
|
||||||
|
|
||||||
|
dialogHelper.open(elem);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue