mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-08-05 08:39:59 -04:00
More Reader Bugfixes (#1255)
* Added css to center images * Better scaling css * Removing vertical height css for actionbar calc * Fixed a bug where book settings couldn't be saved due to typo in model * fixing height across layouts * Fixed an issue where column mode would reset to user preference default between continuous reader loads * Fixing some more logic * Reading direction arrow keys now flip * Small code cleanup on Robbie's code Co-authored-by: Robbie Davis <robbie@therobbiedavis.com>
This commit is contained in:
parent
be5b997259
commit
d458a823ef
@ -1,4 +1,4 @@
|
||||
<div class="container-flex {{darkMode ? 'dark-mode' : ''}} reader-container" tabindex="0" #reader>
|
||||
<div class="container-flex {{darkMode ? 'dark-mode' : ''}} reader-container {{ColumnLayout}}" tabindex="0" #reader>
|
||||
<div class="fixed-top" #stickyTop>
|
||||
<a class="visually-hidden-focusable focus-visible" href="javascript:void(0);" (click)="moveFocus()">Skip to main content</a>
|
||||
<ng-container [ngTemplateOutlet]="actionBar"></ng-container>
|
||||
@ -53,7 +53,7 @@
|
||||
(clickToPaginateChanged)="showPaginationOverlay($event)"
|
||||
(fullscreen)="toggleFullscreen()"
|
||||
(layoutModeUpdate)="updateLayoutMode($event)"
|
||||
(readingDirection)="readingDirection = $event"
|
||||
(readingDirection)="updateReadingDirection($event)"
|
||||
(immersiveMode)="immersiveMode = $event"
|
||||
></app-reader-settings>
|
||||
</ng-template>
|
||||
@ -73,17 +73,19 @@
|
||||
</div>
|
||||
|
||||
<div #readingSection class="reading-section {{ColumnLayout}}" [@isLoading]="isLoading ? true : false">
|
||||
<div #readingCont class="book-container {{ColumnLayout}}">
|
||||
|
||||
<div #readingHtml class="book-content" [ngStyle]="{'max-height': ColumnHeight, 'column-width': ColumnWidth}"
|
||||
[innerHtml]="page" *ngIf="page !== undefined" (click)="toggleMenu($event)" (mousedown)="mouseDown($event)"></div>
|
||||
<div #readingHtml class="book-content {{ColumnLayout}}" [ngStyle]="{'max-height': ColumnHeight, 'column-width': ColumnWidth}"
|
||||
[innerHtml]="page" *ngIf="page !== undefined" (click)="toggleMenu($event)" (mousedown)="mouseDown($event)"></div>
|
||||
|
||||
<ng-container *ngIf="clickToPaginate">
|
||||
<div class="left {{clickOverlayClass('left')}} no-observe" (click)="movePage(readingDirection === ReadingDirection.LeftToRight ? PAGING_DIRECTION.BACKWARDS : PAGING_DIRECTION.FORWARD)" tabindex="-1"></div>
|
||||
<div class="{{scrollbarNeeded ? 'right-with-scrollbar' : 'right'}} {{clickOverlayClass('right')}} no-observe" (click)="movePage(readingDirection === ReadingDirection.LeftToRight ? PAGING_DIRECTION.FORWARD : PAGING_DIRECTION.BACKWARDS)" tabindex="-1"></div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="clickToPaginate">
|
||||
<div class="left {{clickOverlayClass('left')}} no-observe" (click)="movePage(readingDirection === ReadingDirection.LeftToRight ? PAGING_DIRECTION.BACKWARDS : PAGING_DIRECTION.FORWARD)" tabindex="-1"></div>
|
||||
<div class="{{scrollbarNeeded ? 'right-with-scrollbar' : 'right'}} {{clickOverlayClass('right')}} no-observe" (click)="movePage(readingDirection === ReadingDirection.LeftToRight ? PAGING_DIRECTION.FORWARD : PAGING_DIRECTION.BACKWARDS)" tabindex="-1"></div>
|
||||
</ng-container>
|
||||
|
||||
<div *ngIf="page !== undefined && (scrollbarNeeded || layoutMode !== BookPageLayoutMode.Default)" (click)="$event.stopPropagation();">
|
||||
<ng-container [ngTemplateOutlet]="actionBar"></ng-container>
|
||||
<div *ngIf="page !== undefined && (scrollbarNeeded || layoutMode !== BookPageLayoutMode.Default)" (click)="$event.stopPropagation();">
|
||||
<ng-container [ngTemplateOutlet]="actionBar"></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -44,6 +44,7 @@
|
||||
|
||||
$dark-form-background-no-opacity: rgb(1, 4, 9);
|
||||
$primary-color: #0062cc;
|
||||
$action-bar-height: 38px;
|
||||
|
||||
|
||||
// Drawer
|
||||
@ -92,8 +93,8 @@ $primary-color: #0062cc;
|
||||
background-color: var(--br-actionbar-bg-color);
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0 6px 0 rgb(0 0 0 / 70%);
|
||||
max-height: 38px;
|
||||
height: 38px;
|
||||
max-height: $action-bar-height;
|
||||
height: $action-bar-height;
|
||||
|
||||
.book-title-text {
|
||||
text-align: center;
|
||||
@ -122,26 +123,62 @@ $primary-color: #0062cc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.reading-section {
|
||||
max-height: 100vh;
|
||||
width: 100%;
|
||||
//overflow: auto; // This will break progress reporting
|
||||
height: calc(var(--vh, 1vh) * 100);
|
||||
padding-top: 38px;
|
||||
}
|
||||
|
||||
.reader-container {
|
||||
outline: none; // Only the reading section itself shouldn't receive any outline. We use it to shift focus in fullscreen mode
|
||||
overflow: auto;
|
||||
height: calc(var(--vh, 1vh) * 100);
|
||||
position: relative;
|
||||
|
||||
&.column-layout-1 {
|
||||
height: calc(var(--vh) * 100);
|
||||
}
|
||||
|
||||
&.column-layout-2 {
|
||||
height: calc(var(--vh) * 100);
|
||||
}
|
||||
}
|
||||
|
||||
.reading-section {
|
||||
width: 100%;
|
||||
//overflow: auto; // This will break progress reporting
|
||||
height: 100vh;
|
||||
padding-top: $action-bar-height;
|
||||
position: relative;
|
||||
|
||||
&.column-layout-1 {
|
||||
height: calc((var(--vh, 1vh) * 100) - $action-bar-height);
|
||||
}
|
||||
|
||||
&.column-layout-2 {
|
||||
height: calc((var(--vh, 1vh) * 100) - $action-bar-height);
|
||||
}
|
||||
}
|
||||
|
||||
.book-container {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
|
||||
&.column-layout-1 {
|
||||
height: calc((var(--vh, 1vh) * 100) - $action-bar-height);
|
||||
}
|
||||
|
||||
&.column-layout-2 {
|
||||
height: calc((var(--vh, 1vh) * 100) - $action-bar-height);
|
||||
}
|
||||
}
|
||||
|
||||
.book-content {
|
||||
position: relative;
|
||||
padding: 20px 0;
|
||||
margin: 0px 0px;
|
||||
height: calc(var(--vh, 1vh) * 100); // This will ensure bottom bar extends to the bottom of the screen
|
||||
|
||||
&.column-layout-1 {
|
||||
height: calc((var(--vh) * 100) - calc($action-bar-height * 2));
|
||||
}
|
||||
|
||||
&.column-layout-2 {
|
||||
height: calc((var(--vh) * 100) - calc($action-bar-height * 2));
|
||||
}
|
||||
|
||||
a, :link {
|
||||
color: var(--brtheme-link-text-color);
|
||||
@ -238,7 +275,7 @@ $primary-color: #0062cc;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
background: transparent;
|
||||
padding-top: 38px;
|
||||
padding-top: $action-bar-height;
|
||||
}
|
||||
|
||||
// This class pushes the click area to the left a bit to let users click the scrollbar
|
||||
@ -252,7 +289,7 @@ $primary-color: #0062cc;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
background: transparent;
|
||||
padding-top: 38px;
|
||||
padding-top: $action-bar-height;
|
||||
}
|
||||
|
||||
.left {
|
||||
@ -265,7 +302,7 @@ $primary-color: #0062cc;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
background: transparent;
|
||||
padding-top: 38px;
|
||||
padding-top: $action-bar-height;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
|
@ -524,8 +524,9 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.libraryType = type;
|
||||
});
|
||||
|
||||
this.updateLayoutMode(this.user.preferences.bookReaderLayoutMode || BookPageLayoutMode.Default);
|
||||
|
||||
// We need to think about if the user modified this and this function call is a continuous reader one
|
||||
//this.updateLayoutMode(this.user.preferences.bookReaderLayoutMode || BookPageLayoutMode.Default);
|
||||
this.updateImagesWithHeight();
|
||||
|
||||
|
||||
if (this.pageNum >= this.maxPages) {
|
||||
@ -586,9 +587,9 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
@HostListener('window:keydown', ['$event'])
|
||||
handleKeyPress(event: KeyboardEvent) {
|
||||
if (event.key === KEY_CODES.RIGHT_ARROW) {
|
||||
this.nextPage();
|
||||
this.movePage(this.readingDirection === ReadingDirection.LeftToRight ? PAGING_DIRECTION.FORWARD : PAGING_DIRECTION.BACKWARDS);
|
||||
} else if (event.key === KEY_CODES.LEFT_ARROW) {
|
||||
this.prevPage();
|
||||
this.movePage(this.readingDirection === ReadingDirection.LeftToRight ? PAGING_DIRECTION.BACKWARDS : PAGING_DIRECTION.FORWARD);
|
||||
} else if (event.key === KEY_CODES.ESC_KEY) {
|
||||
this.closeReader();
|
||||
} else if (event.key === KEY_CODES.SPACE) {
|
||||
@ -791,7 +792,8 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
* Applies a max-height inline css property on each image in the page if the layout mode is column-based, else it removes the property
|
||||
*/
|
||||
updateImagesWithHeight() {
|
||||
const images = this.readingSectionElemRef.nativeElement.querySelectorAll('img') || [];
|
||||
|
||||
const images = this.readingSectionElemRef?.nativeElement.querySelectorAll('img') || [];
|
||||
|
||||
if (this.layoutMode !== BookPageLayoutMode.Default) {
|
||||
const height = this.ColumnHeight;
|
||||
@ -807,7 +809,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
setupPage(part?: string | undefined, scrollTop?: number | undefined) {
|
||||
this.isLoading = false;
|
||||
this.scrollbarNeeded = this.readingHtml.nativeElement.clientHeight > this.readingSectionElemRef.nativeElement.clientHeight;
|
||||
this.scrollbarNeeded = this.readingHtml.nativeElement.clientHeight > this.reader.nativeElement.clientHeight;
|
||||
|
||||
// Virtual Paging stuff
|
||||
this.updateWidthAndHeightCalcs();
|
||||
@ -877,6 +879,10 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a direction, calls the next or prev page method
|
||||
* @param direction Direction to move
|
||||
*/
|
||||
movePage(direction: PAGING_DIRECTION) {
|
||||
if (direction === PAGING_DIRECTION.BACKWARDS) {
|
||||
this.prevPage();
|
||||
@ -896,7 +902,6 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
const [currentVirtualPage, _, pageWidth] = this.getVirtualPage();
|
||||
|
||||
if (currentVirtualPage > 1) {
|
||||
|
||||
// -2 apparently goes back 1 virtual page...
|
||||
this.scrollService.scrollToX((currentVirtualPage - 2) * pageWidth, this.readingHtml.nativeElement);
|
||||
this.handleScrollEvent();
|
||||
@ -904,11 +909,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.readingDirection === ReadingDirection.LeftToRight) {
|
||||
this.setPageNum(this.pageNum - 1);
|
||||
} else {
|
||||
this.setPageNum(this.pageNum + 1);
|
||||
}
|
||||
this.setPageNum(this.pageNum - 1);
|
||||
|
||||
if (oldPageNum === 0) {
|
||||
// Move to next volume/chapter automatically
|
||||
@ -933,7 +934,6 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
const [currentVirtualPage, totalVirtualPages, pageWidth] = this.getVirtualPage();
|
||||
|
||||
if (currentVirtualPage < totalVirtualPages) {
|
||||
//this.scrollService.scrollToX(scrollOffset + pageWidth, this.readingHtml.nativeElement);
|
||||
// +0 apparently goes forward 1 virtual page...
|
||||
this.scrollService.scrollToX((currentVirtualPage) * pageWidth, this.readingHtml.nativeElement);
|
||||
this.handleScrollEvent();
|
||||
@ -949,11 +949,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
|
||||
if (this.readingDirection === ReadingDirection.LeftToRight) {
|
||||
this.setPageNum(this.pageNum + 1);
|
||||
} else {
|
||||
this.setPageNum(this.pageNum - 1);
|
||||
}
|
||||
this.setPageNum(this.pageNum + 1);
|
||||
|
||||
if (oldPageNum === this.pageNum) { return; }
|
||||
|
||||
@ -982,23 +978,8 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
const scrollOffset = this.readingHtml.nativeElement.scrollLeft;
|
||||
const totalScroll = this.readingHtml.nativeElement.scrollWidth;
|
||||
const pageWidth = this.getPageWidth();
|
||||
|
||||
// console.log('scrollOffset: ', scrollOffset);
|
||||
// console.log('totalScroll: ', totalScroll);
|
||||
// console.log('page width: ', pageWidth);
|
||||
// console.log('delta: ', totalScroll - scrollOffset)
|
||||
|
||||
// // If everything fits on a single page
|
||||
// if (totalScroll - pageWidth === 0) {
|
||||
// return [1, 1, pageWidth];
|
||||
// }
|
||||
|
||||
// // totalVirtualPages needs to be -1 because we can't scroll to totalOffset only on page 2
|
||||
|
||||
// const currentVirtualPage = Math.max(1, (scrollOffset === 0) ? 1 : Math.round(scrollOffset / pageWidth));
|
||||
|
||||
const delta = totalScroll - scrollOffset;
|
||||
//let totalVirtualPages = Math.max(1, Math.round((totalScroll - pageWidth) / pageWidth));
|
||||
|
||||
const totalVirtualPages = Math.max(1, Math.round((totalScroll) / pageWidth));
|
||||
let currentVirtualPage = 1;
|
||||
|
||||
@ -1014,8 +995,6 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
currentVirtualPage = Math.min(Math.max(1, Math.round((scrollOffset + pageWidth) / pageWidth)), totalVirtualPages);
|
||||
}
|
||||
|
||||
console.log('currentPage: ', currentVirtualPage , ' totalPage: ', totalVirtualPages);
|
||||
|
||||
return [currentVirtualPage, totalVirtualPages, pageWidth];
|
||||
}
|
||||
|
||||
@ -1205,6 +1184,10 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.updateImagesWithHeight();
|
||||
}
|
||||
|
||||
updateReadingDirection(readingDirection: ReadingDirection) {
|
||||
this.readingDirection = readingDirection;
|
||||
}
|
||||
|
||||
// Table of Contents
|
||||
cleanIdSelector(id: string) {
|
||||
const tokens = id.split('/');
|
||||
|
@ -38,7 +38,7 @@
|
||||
ondragstart="return false;" onselectstart="return false;">
|
||||
</canvas>
|
||||
</div>
|
||||
<div class="image-container" [ngClass]="{'d-none': renderWithCanvas, 'center-double': ShouldRenderDoublePage,
|
||||
<div class="image-container {{getFittingOptionClass()}}" [ngClass]="{'d-none': renderWithCanvas, 'center-double': ShouldRenderDoublePage,
|
||||
'fit-to-width-double-offset' : this.generalSettingsForm.get('fittingOption')?.value === FITTING_OPTION.WIDTH && ShouldRenderDoublePage,
|
||||
'fit-to-height-double-offset': this.generalSettingsForm.get('fittingOption')?.value === FITTING_OPTION.HEIGHT && ShouldRenderDoublePage,
|
||||
'original-double-offset' : this.generalSettingsForm.get('fittingOption')?.value === FITTING_OPTION.ORIGINAL && ShouldRenderDoublePage,
|
||||
|
@ -18,15 +18,13 @@ img {
|
||||
}
|
||||
|
||||
.reading-area {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
height: calc(var(--vh)*100);
|
||||
}
|
||||
|
||||
.image-container {
|
||||
text-align: center;
|
||||
height: 100vh;
|
||||
|
||||
// Original
|
||||
//display: block;
|
||||
@ -35,6 +33,22 @@ img {
|
||||
//display: flex; // Leave this off as it can cutoff the image
|
||||
align-items: center;
|
||||
|
||||
&.full-width {
|
||||
width: 100vw;
|
||||
height: calc(var(--vh)*100);
|
||||
display: grid;
|
||||
}
|
||||
|
||||
&.full-height {
|
||||
height: 100vh;
|
||||
display: grid;
|
||||
}
|
||||
|
||||
&.original {
|
||||
height: 100vh;
|
||||
display: grid;
|
||||
}
|
||||
|
||||
#image-1 {
|
||||
&.double {
|
||||
margin: 0 0 0 auto;
|
||||
@ -95,17 +109,22 @@ img {
|
||||
.full-height {
|
||||
width: auto;
|
||||
margin: 0 auto;
|
||||
max-height: 100%;
|
||||
max-height: calc(var(--vh)*100);
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.original {
|
||||
align-self: center;
|
||||
align-self: center;
|
||||
width: auto;
|
||||
margin: 0 auto;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.full-width {
|
||||
max-width: 100%;
|
||||
align-self: center;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
vertical-align: top;
|
||||
max-width: fit-content;
|
||||
|
||||
&.double {
|
||||
width: 50%;
|
||||
|
@ -134,7 +134,7 @@
|
||||
<label id="immersivemode-label" class="form-label"></label>
|
||||
<div class="mb-3">
|
||||
<div class="form-check form-switch">
|
||||
<input type="checkbox" role="switch" id="immersivemode" formControlName="bookReaderImmersivemode" class="form-check-input" [value]="true" aria-labelledby="immersivemode-label">
|
||||
<input type="checkbox" role="switch" id="immersivemode" formControlName="bookReaderImmersiveMode" class="form-check-input" [value]="true" aria-labelledby="immersivemode-label">
|
||||
<label id="immersivemode" class="form-check-label">Immersive Mode</label> <i class="fa fa-info-circle" aria-hidden="true" placement="right" [ngbTooltip]="immersivemodeOptionTooltip" role="button" tabindex="0"></i>
|
||||
<ng-template #immersivemodeOptionTooltip>This will hide the menu behind a click on the reader document and turn tap to paginate on</ng-template>
|
||||
<span class="visually-hidden" id="settings-immersivemode-option-help">This will hide the menu behind a click on the reader document and turn tap to paginate on</span>
|
||||
|
Loading…
x
Reference in New Issue
Block a user