Angular 16 (#2007)

* Removed adv, which isn't needed.

* Updated zone

* Updated to angular 16

* Updated to angular 16 (partially)

* Updated to angular 16

* Package update for Angular 16 (and other dependencies) is complete.

* Replaced all takeUntil(this.onDestroy) with new takeUntilDestroyed()

* Updated all inputs that have ! to be required and deleted all unit tests.

* Corrected how takeUntilDestroyed() is supposed to be implemented.
This commit is contained in:
Joe Milazzo 2023-05-21 12:30:32 -05:00 committed by GitHub
parent 9bc8361381
commit 9c06cccd35
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
87 changed files with 3964 additions and 20426 deletions

View file

@ -1,5 +1,20 @@
import { DOCUMENT } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, Inject, Input, OnChanges, OnDestroy, OnInit, Output, Renderer2, SimpleChanges } from '@angular/core';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component, DestroyRef,
ElementRef,
EventEmitter,
inject,
Inject,
Input,
OnChanges,
OnDestroy,
OnInit,
Output,
Renderer2,
SimpleChanges
} from '@angular/core';
import { BehaviorSubject, fromEvent, ReplaySubject, Subject } from 'rxjs';
import { debounceTime, takeUntil } from 'rxjs/operators';
import { ScrollService } from 'src/app/_services/scroll.service';
@ -7,6 +22,7 @@ import { ReaderService } from '../../../_services/reader.service';
import { PAGING_DIRECTION } from '../../_models/reader-enums';
import { WebtoonImage } from '../../_models/webtoon-image';
import { ManagaReaderService } from '../../_series/managa-reader.service';
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
/**
* How much additional space should pass, past the original bottom of the document height before we trigger the next chapter load
@ -58,7 +74,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
/**
* Method to generate the src for Image loading
*/
@Input() urlProvider!: (page: number) => string;
@Input({required: true}) urlProvider!: (page: number) => string;
@Output() pageNumberChange: EventEmitter<number> = new EventEmitter<number>();
@Output() loadNextChapter: EventEmitter<void> = new EventEmitter<void>();
@Output() loadPrevChapter: EventEmitter<void> = new EventEmitter<void>();
@ -66,6 +82,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
@Input() goToPage: BehaviorSubject<number> | undefined;
@Input() bookmarkPage: ReplaySubject<number> = new ReplaySubject<number>();
@Input() fullscreenToggled: ReplaySubject<boolean> = new ReplaySubject<boolean>();
private readonly destroyRef = inject(DestroyRef);
readerElemRef!: ElementRef<HTMLDivElement>;
@ -110,7 +127,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
/**
* If the user has scrolled all the way to the bottom. This is used solely for continuous reading
*/
atBottom: boolean = false;
atBottom: boolean = false;
/**
* If the user has scrolled all the way to the top. This is used solely for continuous reading
*/
@ -149,10 +166,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
return this.webtoonImageWidth > (innerWidth || document.body.clientWidth);
}
private readonly onDestroy = new Subject<void>();
constructor(private readerService: ReaderService, private renderer: Renderer2,
constructor(private readerService: ReaderService, private renderer: Renderer2,
@Inject(DOCUMENT) private document: Document, private scrollService: ScrollService,
private readonly cdRef: ChangeDetectorRef, private mangaReaderService: ManagaReaderService) {
// This will always exist at this point in time since this is used within manga reader
@ -172,18 +186,16 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
ngOnDestroy(): void {
this.intersectionObserver.disconnect();
this.onDestroy.next();
this.onDestroy.complete();
}
/**
* Responsible for binding the scroll handler to the correct event. On non-fullscreen, body is correct. However, on fullscreen, we must use the reader as that is what
* Responsible for binding the scroll handler to the correct event. On non-fullscreen, body is correct. However, on fullscreen, we must use the reader as that is what
* gets promoted to fullscreen.
*/
initScrollHandler() {
console.log('Setting up Scroll handler on ', this.isFullscreenMode ? this.readerElemRef.nativeElement : this.document.body);
fromEvent(this.isFullscreenMode ? this.readerElemRef.nativeElement : this.document.body, 'scroll')
.pipe(debounceTime(20), takeUntil(this.onDestroy))
.pipe(debounceTime(20), takeUntilDestroyed(this.destroyRef))
.subscribe((event) => this.handleScrollEvent(event));
}
@ -193,7 +205,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
this.recalculateImageWidth();
if (this.goToPage) {
this.goToPage.pipe(takeUntil(this.onDestroy)).subscribe(page => {
this.goToPage.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(page => {
const isSamePage = this.pageNum === page;
if (isSamePage) { return; }
this.debugLog('[GoToPage] jump has occured from ' + this.pageNum + ' to ' + page);
@ -209,11 +221,11 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
}
if (this.bookmarkPage) {
this.bookmarkPage.pipe(takeUntil(this.onDestroy)).subscribe(page => {
this.bookmarkPage.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(page => {
const image = document.querySelector('img[id^="page-' + page + '"]');
if (image) {
this.renderer.addClass(image, 'bookmark-effect');
setTimeout(() => {
this.renderer.removeClass(image, 'bookmark-effect');
}, 1000);
@ -222,7 +234,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
}
if (this.fullscreenToggled) {
this.fullscreenToggled.pipe(takeUntil(this.onDestroy)).subscribe(isFullscreen => {
this.fullscreenToggled.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(isFullscreen => {
this.debugLog('[FullScreen] Fullscreen mode: ', isFullscreen);
this.isFullscreenMode = isFullscreen;
this.cdRef.markForCheck();
@ -251,13 +263,13 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
}
return (offset
|| document.body.scrollTop
|| document.documentElement.scrollTop
|| document.body.scrollTop
|| document.documentElement.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,
* 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
*/
@ -279,7 +291,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
if (!this.isScrolling) {
// Use offset of the image against the scroll container to test if the most of the image is visible on the screen. We can use this
// to mark the current page and separate the prefetching code.
// to mark the current page and separate the prefetching code.
const midlineImages = Array.from(document.querySelectorAll('img[id^="page-"]'))
.filter(entry => this.shouldElementCountAsCurrentPage(entry));
@ -336,7 +348,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
document.body.scrollTop = this.previousScrollHeightMinusTop + (SPACER_SCROLL_INTO_PX / 2);
this.cdRef.markForCheck();
});
} else if (totalScroll >= totalHeight + SPACER_SCROLL_INTO_PX && this.atBottom) {
} else if (totalScroll >= totalHeight + SPACER_SCROLL_INTO_PX && this.atBottom) {
// This if statement will fire once we scroll into the spacer at all
this.loadNextChapter.emit();
this.cdRef.markForCheck();
@ -345,12 +357,12 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
// < 5 because debug mode and FF (mobile) can report non 0, despite being at 0
if (this.getScrollTop() < 5 && this.pageNum === 0 && !this.atTop) {
this.atBottom = false;
this.atTop = true;
this.atTop = true;
this.cdRef.markForCheck();
// Scroll user back to original location
this.previousScrollHeightMinusTop = document.body.scrollHeight - document.body.scrollTop;
const reader = this.isFullscreenMode ? this.readerElemRef.nativeElement : this.document.body;
requestAnimationFrame(() => this.scrollService.scrollTo((SPACER_SCROLL_INTO_PX / 2), reader));
} else if (this.getScrollTop() < 5 && this.pageNum === 0 && this.atTop) {
@ -362,7 +374,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
}
/**
*
*
* @returns Height, Width
*/
getInnerDimensions() {
@ -377,10 +389,10 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
}
/**
* Is any part of the element visible in the scrollport. Does not take into account
* style properites, just scroll port visibility.
* @param elem
* @returns
* Is any part of the element visible in the scrollport. Does not take into account
* style properites, just scroll port visibility.
* @param elem
* @returns
*/
isElementVisible(elem: Element) {
if (elem === null || elem === undefined) { return false; }
@ -391,8 +403,8 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
const [innerHeight, innerWidth] = this.getInnerDimensions();
return (rect.bottom >= 0 &&
rect.right >= 0 &&
return (rect.bottom >= 0 &&
rect.right >= 0 &&
rect.top <= (innerHeight || document.body.clientHeight) &&
rect.left <= (innerWidth || document.body.clientWidth)
);
@ -400,7 +412,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
/**
* Is any part of the element visible in the scrollport and is it above the midline trigger.
* The midline trigger does not mean it is half of the screen. It may be top 25%.
* The midline trigger does not mean it is half of the screen. It may be top 25%.
* @param elem HTML Element
* @returns If above midline
*/
@ -412,8 +424,8 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
const [innerHeight, innerWidth] = this.getInnerDimensions();
if (rect.bottom >= 0 &&
rect.right >= 0 &&
if (rect.bottom >= 0 &&
rect.right >= 0 &&
rect.top <= (innerHeight || document.body.clientHeight) &&
rect.left <= (innerWidth || document.body.clientWidth)
) {
@ -444,7 +456,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
/**
* Callback for an image onLoad. At this point the image is already rendered in DOM (may not be visible)
* This will be used to scroll to current page for intial load
* @param event
* @param event
*/
onImageLoad(event: any) {
const imagePage = this.readerService.imageUrlToPageNum(event.target.src);
@ -468,13 +480,13 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
this.debugLog('[Image Load] ! Loaded current page !', this.pageNum);
this.currentPageElem = this.document.querySelector('img#page-' + this.pageNum);
// There needs to be a bit of time before we scroll
if (this.currentPageElem && !this.isElementVisible(this.currentPageElem)) {
if (this.currentPageElem && !this.isElementVisible(this.currentPageElem)) {
this.scrollToCurrentPage();
} else {
this.initFinished = true;
this.cdRef.markForCheck();
}
this.allImagesLoaded = true;
this.cdRef.markForCheck();
});
@ -530,7 +542,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
this.currentPageElem = document.querySelector('img#page-' + this.pageNum);
if (!this.currentPageElem) { return; }
this.debugLog('[GoToPage] Scrolling to page', this.pageNum);
// Update prevScrollPosition, so the next scroll event properly calculates direction
this.prevScrollPosition = this.currentPageElem.getBoundingClientRect().top;
this.isScrolling = true;
@ -553,7 +565,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
}
this.debugLog('\t[PREFETCH] Prefetching ', page);
const data = this.webtoonImages.value.concat({src: this.urlProvider(page), page});
data.sort((a: WebtoonImage, b: WebtoonImage) => {
@ -582,9 +594,9 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
/**
* Finds the ranges of indecies to load from backend. totalPages - 1 is due to backend will automatically return last page for any page number
* above totalPages. Webtoon reader might ask for that which results in duplicate last pages.
* @param pageNum
* @returns
* above totalPages. Webtoon reader might ask for that which results in duplicate last pages.
* @param pageNum
* @returns
*/
calculatePrefetchIndecies(pageNum: number = -1) {
if (pageNum == -1) {
@ -646,7 +658,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
if (this.debugLogFilter.filter(str => message.replace('\t', '').startsWith(str)).length > 0) return;
if (extraData !== undefined) {
console.log(message, extraData);
console.log(message, extraData);
} else {
console.log(message);
}