Skip to main content
diff --git a/UI/Web/src/app/book-reader/book-reader/book-reader.component.scss b/UI/Web/src/app/book-reader/book-reader/book-reader.component.scss
index 65de3db54..12823f996 100644
--- a/UI/Web/src/app/book-reader/book-reader/book-reader.component.scss
+++ b/UI/Web/src/app/book-reader/book-reader/book-reader.component.scss
@@ -161,6 +161,7 @@ $primary-color: #0062cc;
.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;
}
.book-content {
diff --git a/UI/Web/src/app/book-reader/book-reader/book-reader.component.ts b/UI/Web/src/app/book-reader/book-reader/book-reader.component.ts
index 39e0cc637..74120972e 100644
--- a/UI/Web/src/app/book-reader/book-reader/book-reader.component.ts
+++ b/UI/Web/src/app/book-reader/book-reader/book-reader.component.ts
@@ -748,11 +748,8 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
this.scrollService.scrollTo(0, this.reader.nativeElement);
}
- // On fullscreen we need to click the document before arrow keys will scroll down.
- if (this.isFullscreen) {
- this.renderer.setAttribute(this.reader.nativeElement, 'tabIndex', '0');
- this.reader.nativeElement.focus();
- }
+ // we need to click the document before arrow keys will scroll down.
+ this.reader.nativeElement.focus();
}
setPageNum(pageNum: number) {
@@ -888,6 +885,20 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
}
this.renderer.setStyle(this.readingHtml.nativeElement, item[0], item[1], RendererStyleFlags2.Important);
});
+
+ for(let i = 0; i < this.readingHtml.nativeElement.children.length; i++) {
+ const elem = this.readingHtml.nativeElement.children.item(i);
+ if (elem?.tagName === 'STYLE') continue;
+ Object.entries(this.pageStyles).forEach(item => {
+ if (item[1] == '100%' || item[1] == '0px' || item[1] == 'inherit') {
+ // Remove the style or skip
+ this.renderer.removeStyle(elem, item[0]);
+ return;
+ }
+ this.renderer.setStyle(elem, item[0], item[1], RendererStyleFlags2.Important);
+ });
+
+ }
}
}
diff --git a/UI/Web/src/app/collections/collection-detail/collection-detail.component.ts b/UI/Web/src/app/collections/collection-detail/collection-detail.component.ts
index b32cfc6fe..02f897451 100644
--- a/UI/Web/src/app/collections/collection-detail/collection-detail.component.ts
+++ b/UI/Web/src/app/collections/collection-detail/collection-detail.component.ts
@@ -151,7 +151,6 @@ export class CollectionDetailComponent implements OnInit, OnDestroy {
this.collectionTag = matchingTags[0];
this.tagImage = this.imageService.randomize(this.imageService.getCollectionCoverImage(this.collectionTag.id));
this.titleService.setTitle('Kavita - ' + this.collectionTag.title + ' Collection');
- this.loadPage();
});
}
diff --git a/UI/Web/src/app/library-detail/library-detail.component.ts b/UI/Web/src/app/library-detail/library-detail.component.ts
index 103cf2ecb..13fc0e885 100644
--- a/UI/Web/src/app/library-detail/library-detail.component.ts
+++ b/UI/Web/src/app/library-detail/library-detail.component.ts
@@ -93,7 +93,7 @@ export class LibraryDetailComponent implements OnInit, OnDestroy {
[this.filterSettings.presets, this.filterSettings.openByDefault] = this.utilityService.filterPresetsFromUrl(this.route.snapshot, this.seriesService.createSeriesFilter());
this.filterSettings.presets.libraries = [this.libraryId];
- this.loadPage();
+ //this.loadPage();
}
ngOnInit(): void {
@@ -140,7 +140,6 @@ export class LibraryDetailComponent implements OnInit, OnDestroy {
updateFilter(data: SeriesFilter) {
this.filter = data;
- console.log('filter: ', this.filter);
if (this.pagination !== undefined && this.pagination !== null) {
this.pagination.currentPage = 1;
this.onPageChange(this.pagination);
@@ -171,7 +170,7 @@ export class LibraryDetailComponent implements OnInit, OnDestroy {
}
onPageChange(pagination: Pagination) {
- window.history.replaceState(window.location.href, '', window.location.href.split('?')[0] + '?page=' + this.pagination.currentPage);
+ window.history.replaceState(window.location.href, '', window.location.href.split('?')[0] + '?' + 'page=' + this.pagination.currentPage);
this.loadPage();
}
diff --git a/UI/Web/src/app/manga-reader/infinite-scroller/infinite-scroller.component.html b/UI/Web/src/app/manga-reader/infinite-scroller/infinite-scroller.component.html
index 6bc608c11..a2c1f61e1 100644
--- a/UI/Web/src/app/manga-reader/infinite-scroller/infinite-scroller.component.html
+++ b/UI/Web/src/app/manga-reader/infinite-scroller/infinite-scroller.component.html
@@ -26,7 +26,10 @@
diff --git a/UI/Web/src/app/manga-reader/infinite-scroller/infinite-scroller.component.ts b/UI/Web/src/app/manga-reader/infinite-scroller/infinite-scroller.component.ts
index e2ecb7f40..fd9d01106 100644
--- a/UI/Web/src/app/manga-reader/infinite-scroller/infinite-scroller.component.ts
+++ b/UI/Web/src/app/manga-reader/infinite-scroller/infinite-scroller.component.ts
@@ -1,6 +1,6 @@
-import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, Renderer2, SimpleChanges } from '@angular/core';
-import { BehaviorSubject, fromEvent, ReplaySubject, Subject } from 'rxjs';
-import { debounceTime, takeUntil } from 'rxjs/operators';
+import { Component, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, Renderer2, SimpleChanges } from '@angular/core';
+import { BehaviorSubject, fromEvent, merge, ReplaySubject, Subject } from 'rxjs';
+import { debounceTime, take, takeUntil } from 'rxjs/operators';
import { ReaderService } from '../../_services/reader.service';
import { PAGING_DIRECTION } from '../_models/reader-enums';
import { WebtoonImage } from '../_models/webtoon-image';
@@ -64,7 +64,9 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
@Input() goToPage: ReplaySubject = new ReplaySubject();
@Input() bookmarkPage: ReplaySubject = new ReplaySubject();
@Input() fullscreenToggled: ReplaySubject = new ReplaySubject();
-
+
+ readerElemRef!: ElementRef;
+
/**
* Stores and emits all the src urls
*/
@@ -111,6 +113,10 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
* If the user has scrolled all the way to the top. This is used solely for continuous reading
*/
atTop: boolean = false;
+ /**
+ * If the manga reader is in fullscreen. Some math changes based on this value.
+ */
+ isFullscreenMode: boolean = false;
/**
* Keeps track of the previous scrolling height for restoring scroll position after we inject spacer block
*/
@@ -129,7 +135,8 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
}
get areImagesWiderThanWindow() {
- return this.webtoonImageWidth > (window.innerWidth || document.documentElement.clientWidth);
+ let [innerWidth, _] = this.getInnerDimensions();
+ return this.webtoonImageWidth > (innerWidth || document.documentElement.clientWidth);
}
@@ -137,7 +144,13 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
private readonly onDestroy = new Subject();
- constructor(private readerService: ReaderService, private renderer: Renderer2) {}
+ constructor(private readerService: ReaderService, private renderer: Renderer2) {
+ // This will always exist at this point in time since this is used within manga reader
+ const reader = document.querySelector('.reader');
+ if (reader !== null) {
+ this.readerElemRef = new ElementRef(reader as HTMLDivElement);
+ }
+ }
ngOnChanges(changes: SimpleChanges): void {
if (changes.hasOwnProperty('totalPages') && changes['totalPages'].previousValue != changes['totalPages'].currentValue) {
@@ -152,12 +165,21 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
this.onDestroy.complete();
}
- ngOnInit(): void {
- const reader = document.querySelector('.reader') || window;
- fromEvent(reader, 'scroll')
- .pipe(debounceTime(20), takeUntil(this.onDestroy))
+ /**
+ * Responsible for binding the scroll handler to the correct event. On non-fullscreen, window is correct. However, on fullscreen, we must use the reader as that is what
+ * gets promoted to fullscreen.
+ */
+ initScrollHandler() {
+ fromEvent(this.isFullscreenMode ? this.readerElemRef.nativeElement : window, 'scroll')
+ .pipe(debounceTime(20), takeUntil(this.onDestroy))
.subscribe((event) => this.handleScrollEvent(event));
+
+ }
+
+ ngOnInit(): void {
+ this.initScrollHandler();
+
if (this.goToPage) {
this.goToPage.pipe(takeUntil(this.onDestroy)).subscribe(page => {
this.debugLog('[GoToPage] jump has occured from ' + this.pageNum + ' to ' + page);
@@ -189,20 +211,39 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
if (this.fullscreenToggled) {
this.fullscreenToggled.pipe(takeUntil(this.onDestroy)).subscribe(isFullscreen => {
this.debugLog('[FullScreen] Fullscreen mode: ', isFullscreen);
+ this.isFullscreenMode = isFullscreen;
+ const [innerWidth, _] = this.getInnerDimensions();
+ this.webtoonImageWidth = innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
+ this.initScrollHandler();
this.setPageNum(this.pageNum, true);
});
}
}
+ getVerticalOffset() {
+ const reader = this.isFullscreenMode ? this.readerElemRef.nativeElement : window;
+
+ let offset = 0;
+ if (reader instanceof Window) {
+ offset = reader.scrollY;
+ } else {
+ offset = reader.scrollTop;
+ }
+
+ return (offset
+ || document.documentElement.scrollTop
+ || document.body.scrollTop || 0);
+ }
+
/**
* On scroll in document, calculate if the user/javascript has scrolled to the current image element (and it's visible), update that scrolling has ended completely,
* and calculate the direction the scrolling is occuring. This is not used for prefetching.
* @param event Scroll Event
*/
handleScrollEvent(event?: any) {
- const verticalOffset = (window.pageYOffset
- || document.documentElement.scrollTop
- || document.body.scrollTop || 0);
+ // Need a fullscreen handler here too
+ let verticalOffset = this.getVerticalOffset();
+
if (verticalOffset > this.prevScrollPosition) {
this.scrollingDirection = PAGING_DIRECTION.FORWARD;
@@ -211,6 +252,10 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
}
this.prevScrollPosition = verticalOffset;
+ console.log('CurrentPageElem: ', this.currentPageElem);
+ if (this.currentPageElem != null) {
+ console.log('Element Visible: ', this.isElementVisible(this.currentPageElem));
+ }
if (this.isScrolling && this.currentPageElem != null && this.isElementVisible(this.currentPageElem)) {
this.debugLog('[Scroll] Image is visible from scroll, isScrolling is now false');
this.isScrolling = false;
@@ -239,9 +284,15 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
return totalHeight;
}
getTotalScroll() {
+ if (this.isFullscreenMode) {
+ return this.readerElemRef.nativeElement.offsetHeight + this.readerElemRef.nativeElement.scrollTop;
+ }
return document.documentElement.offsetHeight + document.documentElement.scrollTop;
}
getScrollTop() {
+ if (this.isFullscreenMode) {
+ return this.readerElemRef.nativeElement.scrollTop;
+ }
return document.documentElement.scrollTop;
}
@@ -276,7 +327,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
this.atTop = true;
// Scroll user back to original location
this.previousScrollHeightMinusTop = document.documentElement.scrollHeight - document.documentElement.scrollTop;
- requestAnimationFrame(() => window.scrollTo(0, SPACER_SCROLL_INTO_PX));
+ requestAnimationFrame(() => window.scrollTo(0, SPACER_SCROLL_INTO_PX)); // TODO: does this need to be fullscreen protected?
} else if (this.getScrollTop() < 5 && this.pageNum === 0 && this.atTop) {
// If already at top, then we moving on
this.loadPrevChapter.emit();
@@ -285,6 +336,17 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
}
+ getInnerDimensions() {
+ let innerHeight = window.innerHeight;
+ let innerWidth = window.innerWidth;
+
+ if (this.isFullscreenMode) {
+ innerHeight = this.readerElemRef.nativeElement.clientHeight;
+ innerWidth = this.readerElemRef.nativeElement.clientWidth;
+ }
+ return [innerHeight, innerWidth];
+ }
+
/**
* Is any part of the element visible in the scrollport. Does not take into account
* style properites, just scroll port visibility.
@@ -297,10 +359,16 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
// NOTE: This will say an element is visible if it is 1 px offscreen on top
var rect = elem.getBoundingClientRect();
+ let [innerHeight, innerWidth] = this.getInnerDimensions();
+
+
+ console.log('innerHeight: ', innerHeight);
+ console.log('innerWidth: ', innerWidth);
+
return (rect.bottom >= 0 &&
rect.right >= 0 &&
- rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
- rect.left <= (window.innerWidth || document.documentElement.clientWidth)
+ rect.top <= (innerHeight || document.documentElement.clientHeight) &&
+ rect.left <= (innerWidth || document.documentElement.clientWidth)
);
}
@@ -315,12 +383,15 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
var rect = elem.getBoundingClientRect();
+ let [innerHeight, innerWidth] = this.getInnerDimensions();
+
+
if (rect.bottom >= 0 &&
rect.right >= 0 &&
- rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
- rect.left <= (window.innerWidth || document.documentElement.clientWidth)
+ rect.top <= (innerHeight || document.documentElement.clientHeight) &&
+ rect.left <= (innerWidth || document.documentElement.clientWidth)
) {
- const topX = (window.innerHeight || document.documentElement.clientHeight);
+ const topX = (innerHeight || document.documentElement.clientHeight);
return Math.abs(rect.top / topX) <= 0.25;
}
return false;
@@ -328,6 +399,8 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
initWebtoonReader() {
+ const [innerWidth, _] = this.getInnerDimensions();
+ this.webtoonImageWidth = innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
this.imagesLoaded = {};
this.webtoonImages.next([]);
this.atBottom = false;
@@ -424,7 +497,6 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
* Performs the scroll for the current page element. Updates any state variables needed.
*/
scrollToCurrentPage() {
- this.debugLog('Scrolling to ', this.pageNum);
this.currentPageElem = document.querySelector('img#page-' + this.pageNum);
if (!this.currentPageElem) { return; }
diff --git a/UI/Web/src/app/nav-events-toggle/nav-events-toggle.component.ts b/UI/Web/src/app/nav-events-toggle/nav-events-toggle.component.ts
index 26de71660..294f1a9b0 100644
--- a/UI/Web/src/app/nav-events-toggle/nav-events-toggle.component.ts
+++ b/UI/Web/src/app/nav-events-toggle/nav-events-toggle.component.ts
@@ -103,7 +103,7 @@ export class NavEventsToggleComponent implements OnInit, OnDestroy {
prettyPrintEvent(eventType: string, event: any) {
switch(eventType) {
case (EVENTS.ScanLibraryProgress): return 'Scanning ';
- case (EVENTS.RefreshMetadataProgress): return 'Refreshing ';
+ case (EVENTS.RefreshMetadataProgress): return 'Refreshing Covers for ';
case (EVENTS.CleanupProgress): return 'Clearing Cache';
case (EVENTS.BackupDatabaseProgress): return 'Backing up Database';
case (EVENTS.DownloadProgress): return event.rawBody.userName.charAt(0).toUpperCase() + event.rawBody.userName.substr(1) + ' is downloading ' + event.rawBody.downloadName;
diff --git a/UI/Web/src/app/publication-status.pipe.ts b/UI/Web/src/app/publication-status.pipe.ts
index d3beecacd..6aa7516ca 100644
--- a/UI/Web/src/app/publication-status.pipe.ts
+++ b/UI/Web/src/app/publication-status.pipe.ts
@@ -8,7 +8,7 @@ export class PublicationStatusPipe implements PipeTransform {
transform(value: PublicationStatus): string {
switch (value) {
- case PublicationStatus.OnGoing: return 'Ongoing';
+ case PublicationStatus.OnGoing: return 'On Going';
case PublicationStatus.Hiatus: return 'Hiatus';
case PublicationStatus.Completed: return 'Completed';
diff --git a/UI/Web/src/app/reading-list/reading-list-detail/reading-list-detail.component.ts b/UI/Web/src/app/reading-list/reading-list-detail/reading-list-detail.component.ts
index c9716bac7..dd96914cd 100644
--- a/UI/Web/src/app/reading-list/reading-list-detail/reading-list-detail.component.ts
+++ b/UI/Web/src/app/reading-list/reading-list-detail/reading-list-detail.component.ts
@@ -157,7 +157,11 @@ export class ReadingListDetailComponent implements OnInit {
removeRead() {
this.isLoading = true;
- this.readingListService.removeRead(this.readingList.id).subscribe(() => {
+ this.readingListService.removeRead(this.readingList.id).subscribe((resp) => {
+ if (resp === 'Nothing to remove') {
+ this.toastr.info(resp);
+ return;
+ }
this.getListItems();
});
}