diff --git a/src/plugins/pdfPlayer/plugin.js b/src/plugins/pdfPlayer/plugin.js
index 7b7e3fa4b8f..474afb33441 100644
--- a/src/plugins/pdfPlayer/plugin.js
+++ b/src/plugins/pdfPlayer/plugin.js
@@ -18,8 +18,10 @@ export class PdfPlayer {
this.priority = 1;
this.onDialogClosed = this.onDialogClosed.bind(this);
+ this.onScreenResize = this.onScreenResize.bind(this);
+ this.onFullPage = this.onFullPage.bind(this);
this.onWindowKeyDown = this.onWindowKeyDown.bind(this);
- this.onTouchStart = this.onTouchStart.bind(this);
+ this.onClick = this.onClick.bind(this);
}
play(options) {
@@ -113,18 +115,32 @@ export class PdfPlayer {
e.preventDefault();
this.stop();
break;
+ case 'Home':
+ this.setPage(1);
+ break;
+ case 'End':
+ this.setPage(-1);
+ break;
}
}
- onTouchStart(e) {
- if (!this.loaded || !e.touches || e.touches.length === 0) return;
- if (e.touches[0].clientX < dom.getWindowSize().innerWidth / 2) {
+ onClick(e) {
+ if (!this.loaded) return;
+ if (e.clientX < dom.getWindowSize().innerWidth / 2) {
this.previous();
} else {
this.next();
}
}
+ onFullPage() {
+ this.mediaElement.querySelector('#pdfContainer').classList.toggle('fullPage');
+ }
+
+ onScreenResize() {
+ this.reloadPage();
+ }
+
onDialogClosed() {
this.stop();
}
@@ -133,21 +149,26 @@ export class PdfPlayer {
const elem = this.mediaElement;
elem.addEventListener('close', this.onDialogClosed, { once: true });
+ elem.querySelector('#pdfContainer').addEventListener('click', this.onClick);
elem.querySelector('.btnExit').addEventListener('click', this.onDialogClosed, { once: true });
+ elem.querySelector('.btnFull').addEventListener('click', this.onFullPage);
}
bindEvents() {
this.bindMediaElementEvents();
document.addEventListener('keydown', this.onWindowKeyDown);
- document.addEventListener('touchstart', this.onTouchStart);
+ if ('screen' in window) window.screen.orientation.addEventListener('change', this.onScreenResize);
+ else document.addEventListener('orientationchange', this.onScreenResize);
}
unbindMediaElementEvents() {
const elem = this.mediaElement;
elem.removeEventListener('close', this.onDialogClosed);
+ elem.querySelector('#pdfContainer').removeEventListener('click', this.onClick);
elem.querySelector('.btnExit').removeEventListener('click', this.onDialogClosed);
+ elem.querySelector('.btnFull').removeEventListener('click', this.onFullPage);
}
unbindEvents() {
@@ -156,7 +177,8 @@ export class PdfPlayer {
}
document.removeEventListener('keydown', this.onWindowKeyDown);
- document.removeEventListener('touchstart', this.onTouchStart);
+ if ('screen' in window) window.screen.orientation.removeEventListener('change', this.onScreenResize);
+ else document.removeEventListener('orientationchange', this.onScreenResize);
}
createMediaElement() {
@@ -177,8 +199,9 @@ export class PdfPlayer {
});
let html = '';
- html += '';
+ html += '
';
html += '';
+ html += '';
html += '';
html += '
';
@@ -237,31 +260,47 @@ export class PdfPlayer {
}
next() {
- if (this.progress === this.duration() - 1) return;
- this.loadPage(this.progress + 2);
- this.progress = this.progress + 1;
-
- Events.trigger(this, 'pause');
+ const visiblePages = this.mediaElement.querySelector('#pdfContainer').childElementCount;
+ const newPage = 1 + Math.min(this.progress + visiblePages, this.duration() - 1);
+ this.setPage(newPage);
}
previous() {
- if (this.progress === 0) return;
- this.loadPage(this.progress);
- this.progress = this.progress - 1;
+ const visiblePages = this.mediaElement.querySelector('#pdfContainer').childElementCount;
+ const newPage = 1 + Math.max(this.progress - visiblePages, 0);
+ this.setPage(newPage);
+ }
- Events.trigger(this, 'pause');
+ reloadPage() {
+ this.loadPage(this.progress + 1);
}
- replaceCanvas(canvas) {
- const old = document.getElementById('canvas');
+ setPage(pageNumber) {
+ if (pageNumber < 0) pageNumber = this.duration - pageNumber;
- canvas.id = 'canvas';
- old.parentNode.replaceChild(canvas, old);
+ let newProgress = pageNumber - 1;
+ newProgress = Math.max(newProgress, 0);
+ newProgress = Math.min(newProgress, this.duration() - 1);
+ if (newProgress === this.progress) return;
+
+ this.loadPage(newProgress + 1);
+ this.progress = newProgress;
+
+ Events.trigger(this, 'pause');
+ }
+
+ replaceCanvas(...canvas) {
+ const container = this.mediaElement.querySelector('#pdfContainer');
+ container.replaceChildren(...canvas.filter(item => item !== undefined));
}
loadPage(number) {
+ const bookMode = (window.innerWidth >= window.innerHeight && number != 1);
const prefix = 'page';
- const pad = 2;
+ const pad = 3;
+
+ // correctly show double pages in bookmode
+ if (bookMode) number = Math.floor(number / 2) * 2;
// generate list of cached pages by padding the requested page on both sides
const pages = [prefix + number];
@@ -274,12 +313,13 @@ export class PdfPlayer {
for (const page of pages) {
if (!this.pages[page]) {
this.pages[page] = document.createElement('canvas');
- this.renderPage(this.pages[page], parseInt(page.slice(4), 10));
+ this.renderPage(this.pages[page], parseInt(page.slice(4), 10), bookMode);
}
}
// show the requested page
- this.replaceCanvas(this.pages[prefix + number], number);
+ if (bookMode) this.replaceCanvas(this.pages[prefix + (number)], this.pages[prefix + (number + 1)]);
+ else this.replaceCanvas(this.pages[prefix + number]);
// delete all pages outside the cache area
for (const page in this.pages) {
@@ -289,23 +329,17 @@ export class PdfPlayer {
}
}
- renderPage(canvas, number) {
+ renderPage(canvas, number, bookMode) {
+ const devicePixelRatio = window.devicePixelRatio || 1;
this.book.getPage(number).then(page => {
- const width = dom.getWindowSize().innerWidth;
- const height = dom.getWindowSize().innerHeight;
- const scale = Math.ceil(window.devicePixelRatio || 1);
+ const original = page.getViewport({ scale: 1 });
+ const widthFactor = (bookMode) ? 0.5 : 1;
+ const scale = Math.max((window.screen.height / original.height), (window.screen.width * widthFactor / original.width)) * devicePixelRatio;
const viewport = page.getViewport({ scale });
- const context = canvas.getContext('2d');
+
canvas.width = viewport.width;
canvas.height = viewport.height;
-
- if (width < height) {
- canvas.style.width = '100%';
- canvas.style.height = 'auto';
- } else {
- canvas.style.height = '100%';
- canvas.style.width = 'auto';
- }
+ const context = canvas.getContext('2d');
const renderContext = {
canvasContext: context,
diff --git a/src/plugins/pdfPlayer/style.scss b/src/plugins/pdfPlayer/style.scss
index 29c5c7d5437..e537601cb26 100644
--- a/src/plugins/pdfPlayer/style.scss
+++ b/src/plugins/pdfPlayer/style.scss
@@ -6,16 +6,56 @@
z-index: 100;
background: #fff;
- #canvas {
+ #pdfContainer {
display: block;
- margin: auto;
+ white-space: nowrap;
+ height: 100vh;
+ width: 100vw;
+ overflow: scroll;
+
+ // stylelint has a problem with the selector order
+ // but grouping it this way simply makes the most sense
+ // so we turn it off for this block:
+ /* stylelint-disable no-descending-specificity */
+ &.fullPage {
+ display: flex !important;
+ align-items: center;
+ justify-content: center;
+ overflow: hidden;
+
+ canvas {
+ max-height: 100%;
+ max-width: 50%;
+ }
+
+ canvas:only-child {
+ max-width: 100% !important;
+ }
+ }
+
+ &:not(.fullPage) {
+ canvas {
+ max-height: 150vmax;
+ max-width: 75vmax;
+ }
+
+ canvas:only-child {
+ max-width: 150vmax !important;
+ }
+ }
+ /* stylelint-enable no-descending-specificity */
}
.actionButtons {
- right: 0.5vh;
- top: 0.5vh;
+ width: 100%;
+ left: 0;
+ top: 0;
z-index: 1002;
position: absolute;
+
+ .btnExit {
+ float: right;
+ }
}
.actionButtonIcon {
diff --git a/src/scripts/keyboardNavigation.js b/src/scripts/keyboardNavigation.js
index 949c7b68a48..b0942f3f9b4 100644
--- a/src/scripts/keyboardNavigation.js
+++ b/src/scripts/keyboardNavigation.js
@@ -16,6 +16,8 @@ const KeyNames = {
19: 'Pause',
27: 'Escape',
32: 'Space',
+ 35: 'End',
+ 36: 'Home',
37: 'ArrowLeft',
38: 'ArrowUp',
39: 'ArrowRight',
diff --git a/src/themes/dark/theme.css b/src/themes/dark/theme.css
index f7447c4c86a..ff81fd473c9 100644
--- a/src/themes/dark/theme.css
+++ b/src/themes/dark/theme.css
@@ -499,6 +499,7 @@ html {
#comicsPlayer .actionButtonIcon,
#pdfPlayer .actionButtonIcon {
color: #fff;
+ text-shadow: #000 0 0 5px;
}
#dialogToc {