mirror of
https://github.com/Kareadita/Kavita.git
synced 2026-01-06 12:10:20 -05:00
Shakeout from the Annotation System (#4011)
Co-authored-by: Amelia <77553571+Fesaa@users.noreply.github.com>
This commit is contained in:
parent
6b5b27198a
commit
ce91b056b3
@ -28,63 +28,80 @@ public static class ManualMigrateBookReadingProgress
|
||||
|
||||
public static async Task Migrate(DataContext context, IUnitOfWork unitOfWork, ILogger<Program> logger)
|
||||
{
|
||||
|
||||
if (await context.ManualMigrationHistory.AnyAsync(m => m.Name == "ManualMigrateBookReadingProgress"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
logger.LogCritical("Running ManualMigrateBookReadingProgress migration - Please be patient, this may take some time. This is not an error");
|
||||
|
||||
var bookProgress = await context.AppUserProgresses
|
||||
.Where(p => p.BookScrollId != null && (p.BookScrollId.StartsWith(OldScope) || p.BookScrollId.StartsWith(NewScope)))
|
||||
// Disable change tracking so that LastUpdated isn't updated breaking stats
|
||||
var originalAutoDetectChanges = context.ChangeTracker.AutoDetectChangesEnabled;
|
||||
context.ChangeTracker.AutoDetectChangesEnabled = false;
|
||||
|
||||
try
|
||||
{
|
||||
var bookProgress = await context.AppUserProgresses
|
||||
.Where(p => p.BookScrollId != null &&
|
||||
(p.BookScrollId.StartsWith(OldScope) || p.BookScrollId.StartsWith(NewScope)))
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
|
||||
|
||||
foreach (var progress in bookProgress)
|
||||
{
|
||||
if (string.IsNullOrEmpty(progress.BookScrollId)) continue;
|
||||
foreach (var progress in bookProgress)
|
||||
{
|
||||
if (string.IsNullOrEmpty(progress.BookScrollId)) continue;
|
||||
|
||||
if (progress.BookScrollId.StartsWith(OldScope))
|
||||
if (progress.BookScrollId.StartsWith(OldScope))
|
||||
{
|
||||
progress.BookScrollId = progress.BookScrollId.Replace(OldScope, ReplacementScope);
|
||||
context.AppUserProgresses.Update(progress);
|
||||
}
|
||||
else if (progress.BookScrollId.StartsWith(NewScope))
|
||||
{
|
||||
progress.BookScrollId = progress.BookScrollId.Replace(NewScope, ReplacementScope);
|
||||
context.AppUserProgresses.Update(progress);
|
||||
}
|
||||
}
|
||||
|
||||
if (unitOfWork.HasChanges())
|
||||
{
|
||||
progress.BookScrollId = progress.BookScrollId.Replace(OldScope, ReplacementScope);
|
||||
context.AppUserProgresses.Update(progress);
|
||||
} else if (progress.BookScrollId.StartsWith(NewScope))
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
var ptocEntries = await context.AppUserTableOfContent
|
||||
.Where(p => p.BookScrollId != null &&
|
||||
(p.BookScrollId.StartsWith(OldScope) || p.BookScrollId.StartsWith(NewScope)))
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var ptoc in ptocEntries)
|
||||
{
|
||||
progress.BookScrollId = progress.BookScrollId.Replace(NewScope, ReplacementScope);
|
||||
context.AppUserProgresses.Update(progress);
|
||||
if (string.IsNullOrEmpty(ptoc.BookScrollId)) continue;
|
||||
|
||||
if (ptoc.BookScrollId.StartsWith("id", StringComparison.InvariantCultureIgnoreCase)) continue;
|
||||
|
||||
if (ptoc.BookScrollId.StartsWith(OldScope))
|
||||
{
|
||||
ptoc.BookScrollId = ptoc.BookScrollId.Replace(OldScope, ReplacementScope);
|
||||
context.AppUserTableOfContent.Update(ptoc);
|
||||
}
|
||||
else if (ptoc.BookScrollId.StartsWith(NewScope))
|
||||
{
|
||||
ptoc.BookScrollId = ptoc.BookScrollId.Replace(NewScope, ReplacementScope);
|
||||
context.AppUserTableOfContent.Update(ptoc);
|
||||
}
|
||||
}
|
||||
|
||||
if (unitOfWork.HasChanges())
|
||||
{
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
if (unitOfWork.HasChanges())
|
||||
finally
|
||||
{
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
var ptocEntries = await context.AppUserTableOfContent
|
||||
.Where(p => p.BookScrollId != null && (p.BookScrollId.StartsWith(OldScope) || p.BookScrollId.StartsWith(NewScope)))
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var ptoc in ptocEntries)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ptoc.BookScrollId)) continue;
|
||||
|
||||
if (ptoc.BookScrollId.StartsWith(OldScope))
|
||||
{
|
||||
ptoc.BookScrollId = ptoc.BookScrollId.Replace(OldScope, ReplacementScope);
|
||||
context.AppUserTableOfContent.Update(ptoc);
|
||||
} else if (ptoc.BookScrollId.StartsWith(NewScope))
|
||||
{
|
||||
ptoc.BookScrollId = ptoc.BookScrollId.Replace(NewScope, ReplacementScope);
|
||||
context.AppUserTableOfContent.Update(ptoc);
|
||||
}
|
||||
}
|
||||
|
||||
if (unitOfWork.HasChanges())
|
||||
{
|
||||
await context.SaveChangesAsync();
|
||||
// Restore original setting
|
||||
context.ChangeTracker.AutoDetectChangesEnabled = originalAutoDetectChanges;
|
||||
}
|
||||
|
||||
await context.ManualMigrationHistory.AddAsync(new ManualMigrationHistory()
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
namespace API.Entities.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Color of the highlight
|
||||
/// </summary>
|
||||
/// <remarks>Color may not match exactly due to theming</remarks>
|
||||
public enum HightlightColor
|
||||
{
|
||||
Blue = 1,
|
||||
Green = 2,
|
||||
}
|
||||
@ -321,9 +321,22 @@ public partial class BookService : IBookService
|
||||
|
||||
foreach (var bookmark in ptocBookmarks.Where(b => !string.IsNullOrEmpty(b.BookScrollId)))
|
||||
{
|
||||
var unscopedSelector = bookmark.BookScrollId!.Replace("//BODY/APP-ROOT[1]/DIV[1]/DIV[1]/DIV[1]/APP-BOOK-READER[1]/DIV[1]/DIV[2]/DIV[1]/DIV[1]/DIV[1]", "//BODY").ToLowerInvariant();
|
||||
var elem = doc.DocumentNode.SelectSingleNode(unscopedSelector);
|
||||
elem?.PrependChild(HtmlNode.CreateNode($"<i class='fa-solid fa-bookmark ps-1 pe-1' role='button' id='ptoc-{bookmark.Id}' title='{bookmark.Title}'></i>"));
|
||||
try
|
||||
{
|
||||
var unscopedSelector = bookmark.BookScrollId!
|
||||
.Replace(
|
||||
"//BODY/APP-ROOT[1]/DIV[1]/DIV[1]/DIV[1]/APP-BOOK-READER[1]/DIV[1]/DIV[2]/DIV[1]/DIV[1]/DIV[1]",
|
||||
"//BODY").ToLowerInvariant();
|
||||
var elem = doc.DocumentNode.SelectSingleNode(unscopedSelector);
|
||||
if (elem == null) continue;
|
||||
|
||||
elem.PrependChild(HtmlNode.CreateNode(
|
||||
$"<i class='fa-solid fa-bookmark ps-1 pe-1' role='button' id='ptoc-{bookmark.Id}' title='{bookmark.Title}'></i>"));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Swallow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
import {Pipe, PipeTransform} from '@angular/core';
|
||||
import {HighlightColor} from "../book-reader/_models/annotations/annotation";
|
||||
|
||||
@Pipe({
|
||||
name: 'highlightColor'
|
||||
})
|
||||
export class HighlightColorPipe implements PipeTransform {
|
||||
|
||||
transform(value: HighlightColor): string {
|
||||
switch (value) {
|
||||
case HighlightColor.Blue:
|
||||
return 'blue';
|
||||
case HighlightColor.Green:
|
||||
return 'green';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -218,7 +218,7 @@ export class EpubReaderSettingsService {
|
||||
this._currentSeriesId.set(seriesId);
|
||||
this._currentReadingProfile.set(readingProfile);
|
||||
|
||||
// Load parent profile if needed
|
||||
// Load parent profile if needed, otherwise profile is its own parent
|
||||
if (readingProfile.kind === ReadingProfileKind.Implicit) {
|
||||
try {
|
||||
const parent = await firstValueFrom(this.readingProfileService.getForSeries(seriesId, true));
|
||||
@ -226,6 +226,8 @@ export class EpubReaderSettingsService {
|
||||
} catch (error) {
|
||||
console.error('Failed to load parent reading profile:', error);
|
||||
}
|
||||
} else {
|
||||
this._parentReadingProfile.set(readingProfile);
|
||||
}
|
||||
|
||||
// Setup defaults and update signals
|
||||
@ -575,7 +577,6 @@ export class EpubReaderSettingsService {
|
||||
this.settingsForm.valueChanges.pipe(
|
||||
debounceTime(500),
|
||||
distinctUntilChanged(),
|
||||
skip(1), // Skip initial form creation
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
filter(() => !this.isUpdatingFromForm),
|
||||
tap(() => this.updateImplicitProfile()),
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<ng-container *transloco="let t; prefix: 'annotation-card'">
|
||||
<div class="card border-0 shadow-sm mb-3">
|
||||
<div class="card annotation-card border-0 shadow-sm mb-3">
|
||||
<div #username class="card-header d-flex justify-content-between align-items-center py-2 px-3 clickable" [ngStyle]="{'background-color': titleColor()}" (click)="viewAnnotation()">
|
||||
<div class="d-flex align-items-center">
|
||||
<strong [style.color]="colorscapeService.getContrastingTextColor(username)">{{ annotation().ownerUsername }}</strong>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
.card {
|
||||
.annotation-card {
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import {Component, computed, DestroyRef, effect, ElementRef, inject, input, model, ViewChild} from '@angular/core';
|
||||
import {Annotation, HighlightColor} from "../../../_models/annotations/annotation";
|
||||
import {Annotation} from "../../../_models/annotations/annotation";
|
||||
import {EpubReaderMenuService} from "../../../../_services/epub-reader-menu.service";
|
||||
import {AnnotationService} from "../../../../_services/annotation.service";
|
||||
import {SlotColorPipe} from "../../../../_pipes/slot-color.pipe";
|
||||
@ -21,7 +21,6 @@ export class EpubHighlightComponent {
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
showHighlight = model<boolean>(true);
|
||||
color = input<HighlightColor>(HighlightColor.Blue);
|
||||
|
||||
annotation = model.required<Annotation | null>();
|
||||
|
||||
|
||||
@ -61,7 +61,8 @@ export class ViewTocDrawerComponent {
|
||||
}
|
||||
|
||||
loadChapterPage(event: {pageNum: number, part: string}) {
|
||||
const evt = {pageNumber: event.pageNum, part: `id("${event.part}")`} as LoadPageEvent;
|
||||
const part = event.part.length === 0 ? '' : `id("${event.part}")`;
|
||||
const evt = {pageNumber: event.pageNum, part: part} as LoadPageEvent;
|
||||
this.loadPage.emit(evt);
|
||||
}
|
||||
|
||||
|
||||
@ -154,18 +154,23 @@ export class BookLineOverlayComponent implements OnInit {
|
||||
return;
|
||||
}
|
||||
|
||||
// On mobile, first selection might not match as users can select after the fact. Recalculate
|
||||
const windowText = window.getSelection();
|
||||
const selectedText = windowText?.toString() === '' ? this.selectedText : windowText?.toString() ?? this.selectedText;
|
||||
|
||||
if (this.mode === BookLineOverlayMode.Annotate) {
|
||||
|
||||
const createAnnotation = {
|
||||
id: 0,
|
||||
xPath: this.startXPath,
|
||||
endingXPath: this.endXPath,
|
||||
selectedText: this.selectedText,
|
||||
selectedText: selectedText,
|
||||
comment: '',
|
||||
containsSpoiler: false,
|
||||
pageNumber: this.pageNumber,
|
||||
selectedSlotIndex: 0,
|
||||
chapterTitle: '',
|
||||
highlightCount: this.selectedText.length,
|
||||
highlightCount: selectedText.length,
|
||||
ownerUserId: 0,
|
||||
ownerUsername: '',
|
||||
createdUtc: '',
|
||||
|
||||
@ -46,10 +46,9 @@
|
||||
[ngClass]="{'immersive': immersiveMode() && actionBarVisible}"
|
||||
[innerHtml]="page()" (click)="toggleMenu($event)" (mousedown)="mouseDown($event)" (wheel)="onWheel($event)"></div>
|
||||
|
||||
@if ((scrollbarNeeded() || layoutMode() !== BookPageLayoutMode.Default) && !(writingStyle() === WritingStyle.Vertical && layoutMode() === BookPageLayoutMode.Default)) {
|
||||
<div (click)="$event.stopPropagation();"
|
||||
[ngClass]="{'bottom-bar': layoutMode() !== BookPageLayoutMode.Default}">
|
||||
<ng-container [ngTemplateOutlet]="actionBar" [ngTemplateOutletContext]="{isTop: false}"></ng-container>
|
||||
@if (shouldShowBottomActionBar()) {
|
||||
<div class="bottom-bar" (click)="$event.stopPropagation();">
|
||||
<ng-container [ngTemplateOutlet]="bottomActionBar" [ngTemplateOutletContext]="{isTop: false}"></ng-container>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@ -116,49 +115,46 @@
|
||||
}
|
||||
</ng-template>
|
||||
|
||||
<ng-template #actionBar let-isTop>
|
||||
<ng-template #bottomActionBar>
|
||||
<div class="action-bar row g-0 justify-content-between">
|
||||
<button class="btn btn-outline-secondary btn-icon col-2 col-xs-1"
|
||||
(click)="movePage(isLeftToRight ? PAGING_DIRECTION.BACKWARDS : PAGING_DIRECTION.FORWARD)"
|
||||
[disabled]="isPrevDisabled()"
|
||||
title="{{isLeftToRight ? t('previous') : t('next')}} Page">
|
||||
<i class="fa {{(isLeftToRight ? IsPrevChapter : IsNextChapter) ? 'fa-angle-double-left' : 'fa-angle-left'}} {{isLeftToRight ? '' : 'next-page-highlight'}}" aria-hidden="true"></i>
|
||||
</button>
|
||||
|
||||
@if (!immersiveMode() || epubMenuService.isDrawerOpen() || actionBarVisible()) {
|
||||
<div class="action-bar row g-0 justify-content-between">
|
||||
<button class="btn btn-outline-secondary btn-icon col-2 col-xs-1"
|
||||
(click)="!isTop && movePage(isLeftToRight ? PAGING_DIRECTION.BACKWARDS : PAGING_DIRECTION.FORWARD)"
|
||||
[disabled]="isPrevDisabled()"
|
||||
title="{{isLeftToRight ? t('previous') : t('next')}} Page">
|
||||
<i class="fa {{(isLeftToRight ? IsPrevChapter : IsNextChapter) ? 'fa-angle-double-left' : 'fa-angle-left'}} {{isLeftToRight ? '' : 'next-page-highlight'}}" aria-hidden="true"></i>
|
||||
@if (!this.adhocPageHistory.isEmpty()) {
|
||||
<button class="btn btn-outline-secondary btn-icon col-2 col-xs-1" (click)="goBack()" [title]="t('go-back')">
|
||||
<i class="fa fa-reply" aria-hidden="true"></i>
|
||||
</button>
|
||||
|
||||
@if (!this.adhocPageHistory.isEmpty()) {
|
||||
<button class="btn btn-outline-secondary btn-icon col-2 col-xs-1" (click)="goBack()" [title]="t('go-back')">
|
||||
<i class="fa fa-reply" aria-hidden="true"></i>
|
||||
</button>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
<div class="book-title col-3 d-none d-sm-block">
|
||||
@if(!isLoading()) {
|
||||
<span class="me-1">
|
||||
<div class="book-title col-3 d-none d-sm-block">
|
||||
@if(!isLoading()) {
|
||||
<span class="me-1">
|
||||
{{t('page-num-label', {page: virtualizedPageNum()})}} / {{virtualizedMaxPages()}}
|
||||
</span>
|
||||
|
||||
<span> {{t('completion-label', {percent: (virtualizedPageNum() / virtualizedMaxPages()) | percent})}}</span>
|
||||
@if (readingTimeLeftResource.value(); as timeLeft) {
|
||||
,
|
||||
<span class="time-left">
|
||||
<span> {{t('completion-label', {percent: (virtualizedPageNum() / virtualizedMaxPages()) | percent})}}</span>
|
||||
@if (readingTimeLeftResource.value(); as timeLeft) {
|
||||
,
|
||||
<span class="time-left">
|
||||
<i class="fa-solid fa-clock" aria-hidden="true"></i>
|
||||
{{timeLeft! | readTimeLeft:true }}
|
||||
{{timeLeft! | readTimeLeft:true }}
|
||||
</span>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
<button class="btn btn-outline-secondary btn-icon col-2 col-xs-1"
|
||||
[disabled]="isNextDisabled()"
|
||||
(click)="!isTop && movePage(isLeftToRight ? PAGING_DIRECTION.FORWARD : PAGING_DIRECTION.BACKWARDS)"
|
||||
title="{{isLeftToRight ? t('next') : t('previous')}} Page">
|
||||
<i class="fa {{(isLeftToRight ? IsNextChapter : IsPrevChapter) ? 'fa-angle-double-right' : 'fa-angle-right'}} {{readingDirection() === ReadingDirection.LeftToRight ? 'next-page-highlight' : ''}}" aria-hidden="true"></i>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<button class="btn btn-outline-secondary btn-icon col-2 col-xs-1"
|
||||
[disabled]="isNextDisabled()"
|
||||
(click)="movePage(isLeftToRight ? PAGING_DIRECTION.FORWARD : PAGING_DIRECTION.BACKWARDS)"
|
||||
title="{{isLeftToRight ? t('next') : t('previous')}} Page">
|
||||
<i class="fa {{(isLeftToRight ? IsNextChapter : IsPrevChapter) ? 'fa-angle-double-right' : 'fa-angle-right'}} {{readingDirection() === ReadingDirection.LeftToRight ? 'next-page-highlight' : ''}}" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
@ -287,8 +287,8 @@ $action-bar-height: 38px;
|
||||
.bottom-bar {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
writing-mode: horizontal-tb;
|
||||
}
|
||||
|
||||
@ -374,7 +374,7 @@ $pagination-opacity: 0;
|
||||
cursor: pointer;
|
||||
|
||||
&.immersive {
|
||||
top: 0px;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
&.no-pointer-events {
|
||||
@ -397,7 +397,7 @@ $pagination-opacity: 0;
|
||||
cursor: pointer;
|
||||
|
||||
&.immersive {
|
||||
top: 0px;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -100,6 +100,12 @@ const minImageSize = {
|
||||
width: 100
|
||||
};
|
||||
|
||||
/**
|
||||
* A slight delay before scrolling, to ensure everything has rendered correctly
|
||||
* Ex. after jumping in the ToC
|
||||
*/
|
||||
const SCROLL_DELAY = 10;
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-reader',
|
||||
templateUrl: './book-reader.component.html',
|
||||
@ -208,7 +214,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
*/
|
||||
isLineOverlayOpen = model<boolean>(false);
|
||||
/**
|
||||
* If the action bar is visible
|
||||
* If the action bar (menu bars) is visible
|
||||
*/
|
||||
actionBarVisible = model<boolean>(true);
|
||||
/**
|
||||
@ -368,7 +374,6 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
protected readonly writingStyle = this.readerSettingsService.writingStyle;
|
||||
protected readonly clickToPaginate = this.readerSettingsService.clickToPaginate;
|
||||
|
||||
//protected columnWidth = this.readerSettingsService.columnWidth;
|
||||
protected columnWidth!: Signal<string>;
|
||||
protected columnHeight!: Signal<string>;
|
||||
protected verticalBookContentWidth!: Signal<string>;
|
||||
@ -416,8 +421,30 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
const isDrawerOpen = this.epubMenuService.isDrawerOpen();
|
||||
const actionBarVisible = this.actionBarVisible();
|
||||
|
||||
return !immersiveMode || isDrawerOpen || actionBarVisible;
|
||||
})
|
||||
return actionBarVisible || !immersiveMode || isDrawerOpen;
|
||||
});
|
||||
|
||||
shouldShowBottomActionBar = computed(() => {
|
||||
const layoutMode = this.layoutMode();
|
||||
const scrollbarNeeded = this.scrollbarNeeded();
|
||||
const writingStyle = this.writingStyle();
|
||||
const immersiveMode = this.immersiveMode();
|
||||
const actionBarVisible = this.actionBarVisible();
|
||||
const isDrawerOpen = this.epubMenuService.isDrawerOpen();
|
||||
|
||||
const isColumnMode = layoutMode !== BookPageLayoutMode.Default;
|
||||
const isVerticalLayout = writingStyle === WritingStyle.Vertical;
|
||||
|
||||
|
||||
const baseCondition = (scrollbarNeeded || isColumnMode)
|
||||
&& !(isVerticalLayout && !isColumnMode);
|
||||
|
||||
const showForVerticalDefault = !isColumnMode && isVerticalLayout;
|
||||
|
||||
const otherCondition = !immersiveMode || isDrawerOpen || actionBarVisible;
|
||||
|
||||
return (baseCondition || showForVerticalDefault) && otherCondition;
|
||||
});
|
||||
|
||||
|
||||
isNextPageDisabled() {
|
||||
@ -495,13 +522,18 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
this.columnWidth = computed(() => {
|
||||
switch (this.layoutMode()) {
|
||||
const layoutMode = this.layoutMode();
|
||||
const writingStyle = this.writingStyle();
|
||||
|
||||
const base = writingStyle === WritingStyle.Vertical ? this.pageHeight() : this.pageWidth();
|
||||
|
||||
switch (layoutMode) {
|
||||
case BookPageLayoutMode.Default:
|
||||
return 'unset';
|
||||
case BookPageLayoutMode.Column1:
|
||||
return ((this.pageWidth() / 2) - 4) + 'px';
|
||||
return ((base / 2) - 4) + 'px';
|
||||
case BookPageLayoutMode.Column2:
|
||||
return (this.pageWidth() / 4) + 'px'
|
||||
return (base / 4) + 'px'
|
||||
default:
|
||||
return 'unset';
|
||||
}
|
||||
@ -892,28 +924,16 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
// Attempt to restore the reading position
|
||||
this.snapScrollOnResize();
|
||||
// const resumeElement = this.getFirstVisibleElementXPath();
|
||||
// const layoutMode = this.layoutMode();
|
||||
// if (layoutMode !== BookPageLayoutMode.Default && resumeElement !== null && resumeElement !== undefined) {
|
||||
//
|
||||
// //const element = this.getElementFromXPath(resumeElement);
|
||||
// //console.log('Resuming from resize to element: ', element);
|
||||
//
|
||||
// this.scrollTo(resumeElement, 30); // This works pretty well, but not perfect
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Only applies to non BookPageLayoutMode.Default and non-WritingStyle Horizontal
|
||||
* Only applies to non BookPageLayoutMode. Default and WritingStyle Horizontal
|
||||
* @private
|
||||
*/
|
||||
private snapScrollOnResize() {
|
||||
const layoutMode = this.layoutMode();
|
||||
if (layoutMode === BookPageLayoutMode.Default) return;
|
||||
|
||||
// NOTE: Need to test on one of these books to validate
|
||||
// || this.writingStyle() === WritingStyle.Horizontal
|
||||
|
||||
|
||||
const resumeElement = this.getFirstVisibleElementXPath() ?? null;
|
||||
if (resumeElement !== null) {
|
||||
@ -1171,7 +1191,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
});
|
||||
|
||||
this.firstLoad = false;
|
||||
}, 10);
|
||||
}, SCROLL_DELAY);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1379,31 +1399,31 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
if (layoutMode === BookPageLayoutMode.Default) {
|
||||
if (writingStyle === WritingStyle.Vertical) {
|
||||
setTimeout(()=> this.scrollService.scrollToX(this.bookContentElemRef.nativeElement.clientWidth, this.reader.nativeElement));
|
||||
setTimeout(()=> this.scrollService.scrollToX(this.bookContentElemRef.nativeElement.clientWidth, this.reader.nativeElement), SCROLL_DELAY);
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => this.scrollService.scrollTo(0, this.reader.nativeElement));
|
||||
setTimeout(() => this.scrollService.scrollTo(0, this.reader.nativeElement), SCROLL_DELAY);
|
||||
return;
|
||||
}
|
||||
|
||||
if (writingStyle === WritingStyle.Vertical) {
|
||||
if (this.pagingDirection === PAGING_DIRECTION.BACKWARDS) {
|
||||
setTimeout(() => this.scrollService.scrollTo(this.bookContentElemRef.nativeElement.scrollHeight, this.bookContentElemRef.nativeElement, 'auto'));
|
||||
setTimeout(() => this.scrollService.scrollTo(this.bookContentElemRef.nativeElement.scrollHeight, this.bookContentElemRef.nativeElement, 'auto'), SCROLL_DELAY);
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => this.scrollService.scrollTo(0, this.bookContentElemRef.nativeElement,'auto' ));
|
||||
setTimeout(() => this.scrollService.scrollTo(0, this.bookContentElemRef.nativeElement,'auto' ), SCROLL_DELAY);
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to check if we are paging back, because we need to adjust the scroll
|
||||
if (this.pagingDirection === PAGING_DIRECTION.BACKWARDS) {
|
||||
setTimeout(() => this.scrollService.scrollToX(this.bookContentElemRef.nativeElement.scrollWidth, this.bookContentElemRef.nativeElement));
|
||||
setTimeout(() => this.scrollService.scrollToX(this.bookContentElemRef.nativeElement.scrollWidth, this.bookContentElemRef.nativeElement), SCROLL_DELAY);
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => this.scrollService.scrollToX(0, this.bookContentElemRef.nativeElement));
|
||||
setTimeout(() => this.scrollService.scrollToX(0, this.bookContentElemRef.nativeElement), SCROLL_DELAY);
|
||||
}
|
||||
|
||||
private setupAnnotationElements() {
|
||||
@ -1568,6 +1588,8 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
* @returns Total Page width (excluding margin)
|
||||
*/
|
||||
pageWidth = computed(() => {
|
||||
this.windowWidth(); // Ensure re-compute when windows size changes (element clientWidth isn't a signal)
|
||||
|
||||
const marginLeft = this.pageStyles()['margin-left'];
|
||||
const columnGapModifier = this.layoutMode() === BookPageLayoutMode.Default ? 0 : 1;
|
||||
if (this.readingSectionElemRef == null) return 0;
|
||||
@ -1878,12 +1900,12 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
case WritingStyle.Vertical:
|
||||
const windowWidth = window.innerWidth || document.documentElement.clientWidth;
|
||||
const scrollLeft = element.getBoundingClientRect().left + window.scrollX - (windowWidth - element.getBoundingClientRect().width);
|
||||
setTimeout(() => this.scrollService.scrollToX(scrollLeft, this.reader.nativeElement, 'smooth'), 10);
|
||||
setTimeout(() => this.scrollService.scrollToX(scrollLeft, this.reader.nativeElement, 'smooth'), SCROLL_DELAY);
|
||||
break;
|
||||
case WritingStyle.Horizontal:
|
||||
const fromTopOffset = element.getBoundingClientRect().top + window.scrollY + TOP_OFFSET;
|
||||
// We need to use a delay as webkit browsers (aka Apple devices) don't always have the document rendered by this point
|
||||
setTimeout(() => this.scrollService.scrollTo(fromTopOffset, this.reader.nativeElement), 10);
|
||||
setTimeout(() => this.scrollService.scrollTo(fromTopOffset, this.reader.nativeElement), SCROLL_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2116,7 +2138,6 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
Math.abs(this.mousePosition.y - event.clientY) <= mouseOffset
|
||||
) {
|
||||
this.actionBarVisible.update(v => !v);
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,12 +1,3 @@
|
||||
export enum HighlightColor {
|
||||
Blue = 1,
|
||||
Green = 2,
|
||||
}
|
||||
|
||||
export const allHighlightColors = [HighlightColor.Blue, HighlightColor.Green];
|
||||
|
||||
|
||||
|
||||
|
||||
export interface Annotation {
|
||||
id: number;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user