Misc Fixes (#2155)
* Fixed default token key not being long enough and Kavita auto-generating * When scheduling nightly backup job, make it run at 2am to ensure everything else has ran. * Made the overlay system work better on mobile. In order to do this, had to implement my own copy button. * Tweaked the code to ensure we clear the selection doing anything and clicking off the overlay clears more reliably. * Cleaned up the overlay code * Added the ability to view the series that a rating is representing. Requires Kavita+ deployment. * When calculating overall average rating of server, if only review is yours, don't include it. When calculating overall average rating of server, scale to percentage (* 20) to match all other rating scales. * Fixed side nav on mobile without donate link not fully covering the height of the screen * Only trigger the task conversion warning on Media screen if you've touched the appropriate control. * Fixed a bug where bookmark directory wasn't able to be changed. * Fixed a bug where see More wouldn't show if there were just characters due to missing that check. * Fixed a typo in documentation * If a chapter has a range 1-6 and is fully read, when calculating highest chapter for Scrobbling, use the 6.
This commit is contained in:
parent
9e04276dfd
commit
52d19642f9
17 changed files with 121 additions and 52 deletions
|
|
@ -5,10 +5,25 @@
|
|||
<ng-container [ngSwitch]="mode">
|
||||
<ng-container *ngSwitchCase="BookLineOverlayMode.None">
|
||||
<div class="row g-0">
|
||||
<button class="btn btn-icon" (click)="switchMode(BookLineOverlayMode.Bookmark)">
|
||||
<i class="fa-solid fa-book-bookmark" aria-hidden="true"></i>
|
||||
<span class="visually-hidden">Create Bookmark</span>
|
||||
</button>
|
||||
<div class="col-auto">
|
||||
<button class="btn btn-icon btn-sm" (click)="copy()">
|
||||
<i class="fa-solid fa-copy" aria-hidden="true"></i>
|
||||
<div>Copy</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button class="btn btn-icon btn-sm" (click)="switchMode(BookLineOverlayMode.Bookmark)">
|
||||
<i class="fa-solid fa-book-bookmark" aria-hidden="true"></i>
|
||||
<div>Bookmark</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="col-auto">
|
||||
<button class="btn btn-icon btn-sm" (click)="reset()">
|
||||
<i class="fa-solid fa-times-circle" aria-hidden="true"></i>
|
||||
<span class="visually-hidden">Close</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="BookLineOverlayMode.Bookmark">
|
||||
|
|
|
|||
|
|
@ -8,12 +8,13 @@ import {
|
|||
OnInit, Output,
|
||||
} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {fromEvent, of} from "rxjs";
|
||||
import {fromEvent, merge, of} from "rxjs";
|
||||
import {catchError, filter, tap} from "rxjs/operators";
|
||||
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||
import getBoundingClientRect from "@popperjs/core/lib/dom-utils/getBoundingClientRect";
|
||||
import {FormControl, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms";
|
||||
import {ReaderService} from "../../../_services/reader.service";
|
||||
import {ToastrService} from "ngx-toastr";
|
||||
|
||||
enum BookLineOverlayMode {
|
||||
None = 0,
|
||||
|
|
@ -39,6 +40,7 @@ export class BookLineOverlayComponent implements OnInit {
|
|||
|
||||
xPath: string = '';
|
||||
selectedText: string = '';
|
||||
previousSelection: string = '';
|
||||
overlayPosition: { top: number; left: number } = { top: 0, left: 0 };
|
||||
mode: BookLineOverlayMode = BookLineOverlayMode.None;
|
||||
bookmarkForm: FormGroup = new FormGroup({
|
||||
|
|
@ -50,47 +52,56 @@ export class BookLineOverlayComponent implements OnInit {
|
|||
private readonly readerService = inject(ReaderService);
|
||||
|
||||
get BookLineOverlayMode() { return BookLineOverlayMode; }
|
||||
constructor(private elementRef: ElementRef) {}
|
||||
constructor(private elementRef: ElementRef, private toastr: ToastrService) {}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
if (this.parent) {
|
||||
fromEvent<MouseEvent>(this.parent.nativeElement, 'mouseup')
|
||||
.pipe(takeUntilDestroyed(this.destroyRef),
|
||||
tap((event: MouseEvent) => {
|
||||
const selection = window.getSelection();
|
||||
if (!event.target) return;
|
||||
|
||||
if (this.mode !== BookLineOverlayMode.None && (!selection || selection.toString().trim() === '')) {
|
||||
this.reset();
|
||||
return;
|
||||
}
|
||||
const mouseUp$ = fromEvent<MouseEvent>(this.parent.nativeElement, 'mouseup');
|
||||
const touchEnd$ = fromEvent<TouchEvent>(this.parent.nativeElement, 'touchend');
|
||||
|
||||
this.selectedText = selection ? selection.toString().trim() : '';
|
||||
|
||||
if (this.selectedText.length > 0 && this.mode === BookLineOverlayMode.None) {
|
||||
// Get x,y coord so we can position overlay
|
||||
if (event.target) {
|
||||
const range = selection!.getRangeAt(0)
|
||||
const rect = range.getBoundingClientRect();
|
||||
const box = getBoundingClientRect(event.target as Element);
|
||||
this.xPath = this.readerService.getXPathTo(event.target);
|
||||
if (this.xPath !== '') {
|
||||
this.xPath = '//' + this.xPath;
|
||||
}
|
||||
|
||||
this.overlayPosition = {
|
||||
top: rect.top + window.scrollY - 64 - rect.height, // 64px is the top menu area
|
||||
left: rect.left + window.scrollX + 30 // Adjust 10 to center the overlay box horizontally
|
||||
};
|
||||
}
|
||||
}
|
||||
this.cdRef.markForCheck();
|
||||
}))
|
||||
.subscribe();
|
||||
merge(mouseUp$, touchEnd$)
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((event: MouseEvent | TouchEvent) => {
|
||||
this.handleEvent(event);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleEvent(event: MouseEvent | TouchEvent) {
|
||||
const selection = window.getSelection();
|
||||
if (!event.target) return;
|
||||
|
||||
if ((!selection || selection.toString().trim() === '' || selection.toString().trim() === this.selectedText)) {
|
||||
this.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectedText = selection ? selection.toString().trim() : '';
|
||||
|
||||
if (this.selectedText.length > 0 && this.mode === BookLineOverlayMode.None) {
|
||||
// Get x,y coord so we can position overlay
|
||||
if (event.target) {
|
||||
const range = selection!.getRangeAt(0)
|
||||
const rect = range.getBoundingClientRect();
|
||||
const box = getBoundingClientRect(event.target as Element);
|
||||
this.xPath = this.readerService.getXPathTo(event.target);
|
||||
if (this.xPath !== '') {
|
||||
this.xPath = '//' + this.xPath;
|
||||
}
|
||||
|
||||
this.overlayPosition = {
|
||||
top: rect.top + window.scrollY - 64 - rect.height, // 64px is the top menu area
|
||||
left: rect.left + window.scrollX + 30 // Adjust 10 to center the overlay box horizontally
|
||||
};
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
switchMode(mode: BookLineOverlayMode) {
|
||||
this.mode = mode;
|
||||
this.cdRef.markForCheck();
|
||||
|
|
@ -122,7 +133,21 @@ export class BookLineOverlayComponent implements OnInit {
|
|||
this.mode = BookLineOverlayMode.None;
|
||||
this.xPath = '';
|
||||
this.selectedText = '';
|
||||
const selection = window.getSelection();
|
||||
if (selection) {
|
||||
selection.removeAllRanges();
|
||||
}
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
async copy() {
|
||||
const selection = window.getSelection();
|
||||
if (selection) {
|
||||
await navigator.clipboard.writeText(selection.toString());
|
||||
this.toastr.info('Copied to clipboard');
|
||||
}
|
||||
this.reset();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue