misc stuff to avoid scan loop (#1389)

* Implemented a workaround for nginx users with BlockCommonExploits enabled, which would interfere with book image escaping done by Kavita when images had ../ in their path.

* Added back to top support on all pages but those that untilize virtual scrolling without a parent scroll.

* Hide jumpbar on pages where there is no scroll

* Refactored jumbar code into a dedicated service

* Stash some jumpkey resume code as I can't get it working with the virtual scroller.

* Don't allow non-admins to see File locations on card detail drawer.

* Some cleanup on GetServerInfo

* When an error occurs in register, delete the user on exception.

* Fixed a NPE in Stat collection for brand new users

* When we catch an exception on registering a new user, delete the user as rolling back doesn't do anything.

* Don't close typeahead when we are selecting options from it

* Added shortcut key H to open shortcut modal on manga reader

* When processing progress updates on cards, for volumes, properly find the chapter to update pages read.

* Hide cover image on reading list if it's not set and fixed a missing closing div tag

* Hide collection poster when nothing is set on collection detail

* Small fix around updating state

* Sped up the bookmark image call by removing one DB call

* Fixed broken test from change in bookmark code

* Fixed an oversight where if there is no tag in ComicInfo after a chapter was updated with People or Genres, then the People/Genres would never be removed.

* Added test with TagHelper

* Fixed a bug where 2 clear buttons would show on search bar due to browser injecting their own. Search bar wont show clear button until text is typed.

* Fixed a bug where InstallID wasn't being selected correctly in converter
This commit is contained in:
Joseph Milazzo 2022-07-27 10:16:45 -05:00 committed by GitHub
parent b90c6aa76c
commit 5812588fe5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 474 additions and 249 deletions

View file

@ -15,10 +15,7 @@ export class CollectionTagService {
constructor(private httpClient: HttpClient, private imageService: ImageService) { }
allTags() {
return this.httpClient.get<CollectionTag[]>(this.baseUrl + 'collection/').pipe(map(tags => {
tags.forEach(s => s.coverImage = this.imageService.randomize(this.imageService.getCollectionCoverImage(s.id)));
return tags;
}));
return this.httpClient.get<CollectionTag[]>(this.baseUrl + 'collection/');
}
search(query: string) {

View file

@ -0,0 +1,83 @@
import { Injectable } from '@angular/core';
import { JumpKey } from '../_models/jumpbar/jump-key';
const keySize = 25; // Height of the JumpBar button
@Injectable({
providedIn: 'root'
})
export class JumpbarService {
resumeKeys: {[key: string]: string} = {};
constructor() { }
getResumeKey(key: string) {
if (this.resumeKeys.hasOwnProperty(key)) return this.resumeKeys[key];
return '';
}
saveResumeKey(key: string, value: string) {
this.resumeKeys[key] = value;
}
generateJumpBar(jumpBarKeys: Array<JumpKey>, currentSize: number) {
const fullSize = (jumpBarKeys.length * keySize);
if (currentSize >= fullSize) {
return [...jumpBarKeys];
}
const jumpBarKeysToRender: Array<JumpKey> = [];
const targetNumberOfKeys = parseInt(Math.floor(currentSize / keySize) + '', 10);
const removeCount = jumpBarKeys.length - targetNumberOfKeys - 3;
if (removeCount <= 0) return jumpBarKeysToRender;
const removalTimes = Math.ceil(removeCount / 2);
const midPoint = Math.floor(jumpBarKeys.length / 2);
jumpBarKeysToRender.push(jumpBarKeys[0]);
this.removeFirstPartOfJumpBar(midPoint, removalTimes, jumpBarKeys, jumpBarKeysToRender);
jumpBarKeysToRender.push(jumpBarKeys[midPoint]);
this.removeSecondPartOfJumpBar(midPoint, removalTimes, jumpBarKeys, jumpBarKeysToRender);
jumpBarKeysToRender.push(jumpBarKeys[jumpBarKeys.length - 1]);
return jumpBarKeysToRender;
}
removeSecondPartOfJumpBar(midPoint: number, numberOfRemovals: number = 1, jumpBarKeys: Array<JumpKey>, jumpBarKeysToRender: Array<JumpKey>) {
const removedIndexes: Array<number> = [];
for(let removal = 0; removal < numberOfRemovals; removal++) {
let min = 100000000;
let minIndex = -1;
for(let i = midPoint + 1; i < jumpBarKeys.length - 2; i++) {
if (jumpBarKeys[i].size < min && !removedIndexes.includes(i)) {
min = jumpBarKeys[i].size;
minIndex = i;
}
}
removedIndexes.push(minIndex);
}
for(let i = midPoint + 1; i < jumpBarKeys.length - 2; i++) {
if (!removedIndexes.includes(i)) jumpBarKeysToRender.push(jumpBarKeys[i]);
}
}
removeFirstPartOfJumpBar(midPoint: number, numberOfRemovals: number = 1, jumpBarKeys: Array<JumpKey>, jumpBarKeysToRender: Array<JumpKey>) {
const removedIndexes: Array<number> = [];
for(let removal = 0; removal < numberOfRemovals; removal++) {
let min = 100000000;
let minIndex = -1;
for(let i = 1; i < midPoint; i++) {
if (jumpBarKeys[i].size < min && !removedIndexes.includes(i)) {
min = jumpBarKeys[i].size;
minIndex = i;
}
}
removedIndexes.push(minIndex);
}
for(let i = 1; i < midPoint; i++) {
if (!removedIndexes.includes(i)) jumpBarKeysToRender.push(jumpBarKeys[i]);
}
}
}

View file

@ -1,11 +1,27 @@
import { Injectable } from '@angular/core';
import { ElementRef, Injectable } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { filter, ReplaySubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class ScrollService {
constructor() { }
private scrollContainerSource = new ReplaySubject<string | ElementRef<HTMLElement>>(1);
/**
* Exposes the current container on the active screen that is our primary overlay area. Defaults to 'body' and changes to 'body' on page loads
*/
public scrollContainer$ = this.scrollContainerSource.asObservable();
constructor(router: Router) {
router.events
.pipe(filter(event => event instanceof NavigationEnd))
.subscribe(() => {
this.scrollContainerSource.next('body');
});
this.scrollContainerSource.next('body');
}
get scrollPosition() {
return (window.pageYOffset
@ -26,4 +42,10 @@ export class ScrollService {
behavior: 'auto'
});
}
setScrollContainer(elem: ElementRef<HTMLElement> | undefined) {
if (elem !== undefined) {
this.scrollContainerSource.next(elem);
}
}
}