Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { SFProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/
import { SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role';
import { TextAnchor } from 'realtime-server/lib/esm/scriptureforge/models/text-anchor';
import { StringMap } from 'rich-text';
import { fromEvent, Subject, Subscription, timer } from 'rxjs';
import { fromEvent, ReplaySubject, Subject, Subscription, timer } from 'rxjs';
import { takeUntil, tap } from 'rxjs/operators';
import { LocalPresence, Presence } from 'sharedb/lib/sharedb';
import tinyColor from 'tinycolor2';
Expand Down Expand Up @@ -112,7 +112,7 @@ export class TextComponent implements AfterViewInit, OnDestroy {
@Output() loaded = new EventEmitter<boolean>(true);
@Output() focused = new EventEmitter<boolean>(true);
@Output() presenceChange = new EventEmitter<RemotePresences | undefined>(true);
@Output() editorCreated = new EventEmitter<void>();
@Output() readonly editorCreated = new ReplaySubject<void>(1);

lang: string = '';

Expand Down Expand Up @@ -686,7 +686,7 @@ export class TextComponent implements AfterViewInit, OnDestroy {
this.viewModel.editor = editor;
void this.bindQuill(); // not awaited
editor.container.addEventListener('beforeinput', (ev: Event) => this.onBeforeinput(ev));
this.editorCreated.emit();
this.editorCreated.next();
}

focus(): void {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Location } from '@angular/common';
import { AfterViewInit, Component, DestroyRef, EventEmitter, ViewChild } from '@angular/core';
import { AfterViewInit, Component, DestroyRef, ViewChild } from '@angular/core';
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatButton } from '@angular/material/button';
import { MatCard, MatCardContent, MatCardHeader, MatCardTitle } from '@angular/material/card';
Expand Down Expand Up @@ -151,7 +151,7 @@ export class DraftUsfmFormatComponent extends DataLoadingComponent implements Af
}

ngAfterViewInit(): void {
combineLatest([this.activatedRoute.params, this.draftText.editorCreated as EventEmitter<void>])
combineLatest([this.activatedRoute.params, this.draftText.editorCreated])
.pipe(first(), quietTakeUntilDestroyed(this.destroyRef))
.subscribe(async ([params]) => {
const projectDoc = this.activatedProjectService.projectDoc;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
hideSingleSelectionIndicator
>
<mat-select-trigger>
{{ selectedRevision ?? "" | revisionFormat }}
{{ selectedRevision ?? "" | revisionFormat: (locale$ | async) }}
</mat-select-trigger>
@for (r of draftRevisions; track r) {
<mat-option [value]="r">
<div class="option-content">
<span>{{ r | revisionFormat }}</span>
<span>{{ r | revisionFormat: (locale$ | async) }}</span>
</div>
</mat-option>
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AsyncPipe, NgClass } from '@angular/common';
import { AfterViewInit, Component, DestroyRef, EventEmitter, Input, OnChanges, ViewChild } from '@angular/core';
import { AfterViewInit, Component, DestroyRef, Input, OnChanges, ViewChild } from '@angular/core';
import { MatOption } from '@angular/material/autocomplete';
import { MatButton } from '@angular/material/button';
import { MatFormField } from '@angular/material/form-field';
Expand Down Expand Up @@ -39,6 +39,7 @@ import { DialogService } from 'xforge-common/dialog.service';
import { ErrorReportingService } from 'xforge-common/error-reporting.service';
import { FontService } from 'xforge-common/font.service';
import { I18nService } from 'xforge-common/i18n.service';
import { Locale } from 'xforge-common/models/i18n-locale';
import { NoticeService } from 'xforge-common/notice.service';
import { OnlineStatusService } from 'xforge-common/online-status.service';
import { filterNullish, quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util';
Expand Down Expand Up @@ -120,6 +121,8 @@ export class EditorDraftComponent implements AfterViewInit, OnChanges {
map(build => this.draftOptionsService.areFormattingOptionsSupportedForBuild(build))
);

locale$: Observable<Locale> = this.i18n.locale$;

private draftDelta?: Delta;
private targetDelta?: Delta;
private _latestPreTranslationBuild: BuildDto | undefined;
Expand Down Expand Up @@ -228,7 +231,7 @@ export class EditorDraftComponent implements AfterViewInit, OnChanges {
this.onlineStatusService.onlineStatus$,
this.draftGenerationService.pollBuildProgress(this.textDocId!.projectId),
this.inputChanged$.pipe(filterNullish()),
this.draftText.editorCreated as EventEmitter<any>
this.draftText.editorCreated
])
.pipe(
quietTakeUntilDestroyed(this.destroyRef),
Expand Down Expand Up @@ -310,7 +313,7 @@ export class EditorDraftComponent implements AfterViewInit, OnChanges {
combineLatest([
this.onlineStatusService.onlineStatus$,
this.activatedProjectService.projectDoc$,
this.draftText.editorCreated as EventEmitter<any>,
this.draftText.editorCreated,
this.inputChanged$
])
.pipe(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core';
import { EventEmitter } from '@angular/core';
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import Quill from 'quill';
import { createTestProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-test-data';
import { TextData } from 'realtime-server/lib/esm/scriptureforge/models/text-data';
import { Subject } from 'rxjs';
import { ReplaySubject, Subject } from 'rxjs';
import { anything, mock, when } from 'ts-mockito';
import { I18nService } from 'xforge-common/i18n.service';
import { FileType } from 'xforge-common/models/file-offline-data';
Expand All @@ -12,7 +12,7 @@ import { OnlineStatusService } from 'xforge-common/online-status.service';
import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers';
import { TestOnlineStatusService } from 'xforge-common/test-online-status.service';
import { provideTestRealtime } from 'xforge-common/test-realtime-providers';
import { configureTestingModule } from 'xforge-common/test-utils';
import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils';
import { TypeRegistry } from 'xforge-common/type-registry';
import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc';
import { TextDoc, TextDocId } from '../../../core/models/text-doc';
Expand All @@ -35,16 +35,15 @@ describe('EditorHistoryComponent', () => {
const showDiffChange$ = new Subject<boolean>();

configureTestingModule(() => ({
imports: [EditorHistoryComponent],
schemas: [NO_ERRORS_SCHEMA], // Ignore undeclared child components
providers: [
provideTestRealtime(new TypeRegistry([TextDoc], [FileType.Audio], [])),
provideTestOnlineStatus(),
{ provide: OnlineStatusService, useClass: TestOnlineStatusService },
{ provide: ProjectNotificationService, useMock: mockProjectNotificationService },
{ provide: SFProjectService, useMock: mockSFProjectService },
{ provide: I18nService, useMock: mockI18nService }
]
],
imports: [getTestTranslocoModule()]
}));

beforeEach(() => {
Expand Down Expand Up @@ -101,14 +100,16 @@ describe('EditorHistoryComponent', () => {
const mockEditor = jasmine.createSpyObj<Quill>(['updateContents']);
const mockTextComponent = jasmine.createSpyObj<TextComponent>(['applyEditorStyles', 'setContents'], {
id: {} as TextDocId,
editor: mockEditor
editor: mockEditor,
editorCreated: new ReplaySubject<void>(1)
});

when(mockSFProjectService.getText(anything())).thenResolve(textDoc);

component.historyChooser = mockHistoryChooserComponent;
component.snapshotText = mockTextComponent;
component.diffText = mockTextComponent;
mockTextComponent.editorCreated.next();
component.ngAfterViewInit();

revisionSelect$.next({ revision, snapshot });
Expand All @@ -132,14 +133,16 @@ describe('EditorHistoryComponent', () => {
const mockEditor = jasmine.createSpyObj<Quill>(['updateContents']);
const mockTextComponent = jasmine.createSpyObj<TextComponent>(['applyEditorStyles', 'setContents'], {
id: {} as TextDocId,
editor: mockEditor
editor: mockEditor,
editorCreated: new ReplaySubject<void>(1)
});

when(mockSFProjectService.getText(anything())).thenResolve(textDoc);

component.historyChooser = mockHistoryChooserComponent;
component.snapshotText = mockTextComponent;
component.diffText = mockTextComponent;
mockTextComponent.editorCreated.next();
component.ngAfterViewInit();

revisionSelect$.next({ revision, snapshot });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { MatProgressBar } from '@angular/material/progress-bar';
import { TranslocoModule } from '@ngneat/transloco';
import { Delta } from 'quill';
import { combineLatest, startWith, tap } from 'rxjs';
import { FontService } from 'xforge-common/font.service';
import { I18nService } from 'xforge-common/i18n.service';
import { OnlineStatusService } from 'xforge-common/online-status.service';
import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util';
Expand Down Expand Up @@ -66,7 +65,6 @@ export class EditorHistoryComponent implements OnChanges, OnInit, AfterViewInit
constructor(
private readonly destroyRef: DestroyRef,
private readonly editorHistoryService: EditorHistoryService,
readonly fontService: FontService,
private readonly i18nService: I18nService,
readonly onlineStatusService: OnlineStatusService,
private readonly projectService: SFProjectService
Expand Down Expand Up @@ -95,11 +93,12 @@ export class EditorHistoryComponent implements OnChanges, OnInit, AfterViewInit
}

private loadHistory(): void {
if (this.historyChooser == null) {
if (this.historyChooser == null || this.snapshotText == null) {
return;
}

combineLatest([
this.snapshotText.editorCreated,
this.historyChooser.revisionSelect.pipe(
tap((e: RevisionSelectEvent) => {
this.revisionSelect.emit(e.revision);
Expand All @@ -108,10 +107,10 @@ export class EditorHistoryComponent implements OnChanges, OnInit, AfterViewInit
this.historyChooser.showDiffChange.pipe(startWith(this.historyChooser.showDiff))
])
.pipe(quietTakeUntilDestroyed(this.destroyRef))
.subscribe(async ([e, showDiff]: [RevisionSelectEvent, boolean]) => {
const snapshotContents: Delta = new Delta(e.snapshot?.data.ops);
.subscribe(async ([, revisionEvent, showDiff]) => {
const snapshotContents: Delta = new Delta(revisionEvent.snapshot?.data.ops);
this.snapshotText?.setContents(snapshotContents, 'api');
this.loadedRevision = e.revision;
this.loadedRevision = revisionEvent.revision;

// Show the diff, if requested
if (showDiff && this.diffText?.id != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
hideSingleSelectionIndicator
>
<mat-select-trigger>
{{ selectedRevision ?? "" | revisionFormat }}
{{ selectedRevision ?? "" | revisionFormat: (locale$ | async) }}
</mat-select-trigger>
@for (r of historyRevisions; track r) {
<mat-option [value]="r">
<div class="option-content">
<span>{{ r | revisionFormat }}</span>
<span>{{ r | revisionFormat: (locale$ | async) }}</span>
<mat-icon>{{
r.source === "Draft" ? "auto_awesome" : r.source === "History" ? "history" : ""
}}</mat-icon>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { isNetworkError } from 'xforge-common/command.service';
import { DialogService } from 'xforge-common/dialog.service';
import { ErrorReportingService } from 'xforge-common/error-reporting.service';
import { I18nService } from 'xforge-common/i18n.service';
import { Locale } from 'xforge-common/models/i18n-locale';
import { Snapshot } from 'xforge-common/models/snapshot';
import { TextSnapshot } from 'xforge-common/models/textsnapshot';
import { NoticeService } from 'xforge-common/notice.service';
Expand Down Expand Up @@ -98,6 +99,7 @@ export class HistoryChooserComponent implements AfterViewInit, OnChanges {
@Output() revisionSelect = new EventEmitter<RevisionSelectEvent>();

historyRevisions: Revision[] = [];
locale$: Observable<Locale> = this.i18n.locale$;
selectedRevision: Revision | undefined;
selectedSnapshot: TextSnapshot | undefined;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import { Pipe, PipeTransform } from '@angular/core';
import { I18nService } from 'xforge-common/i18n.service';
import { Locale } from 'xforge-common/models/i18n-locale';
import { Revision } from '../../../../core/paratext.service';

@Pipe({
name: 'revisionFormat',
pure: false
pure: true
})
export class HistoryRevisionFormatPipe implements PipeTransform {
constructor(private readonly i18n: I18nService) {}

transform(revision: Revision | string): string {
/**
* Performs the transformation.
*
* @param revision The revision to display the date of.
* @param _locale This parameter is so that the pipe will re-evaluate on locale changes. It is not used directly.
* @returns The date string formatted using the user's current locale.
*/
transform(revision: Revision | string, _locale: Locale | null): string {
const revisionKey = typeof revision === 'string' ? revision : revision.timestamp;
return this.i18n.formatDate(new Date(revisionKey));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { createTestProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-test-data';
import { Subject } from 'rxjs';
import { ReplaySubject } from 'rxjs';
import { anything, mock, verify, when } from 'ts-mockito';
import { DialogService } from 'xforge-common/dialog.service';
import { FontService } from 'xforge-common/font.service';
Expand Down Expand Up @@ -33,7 +33,7 @@ describe('EditorResourceComponent', () => {
beforeEach(async () => {
fixture = TestBed.createComponent(EditorResourceComponent);
component = fixture.componentInstance;
component.resourceText = { editorCreated: new Subject<void>() } as any;
component.resourceText = { editorCreated: new ReplaySubject<void>(1) } as any;
});

afterEach(() => {
Expand Down
Loading