From 12612a02de0cd90264d3d2f6788ba90de0e8a8d3 Mon Sep 17 00:00:00 2001 From: rhenck <richard.henck@iqb.hu-berlin.de> Date: Thu, 16 Sep 2021 14:30:33 +0200 Subject: [PATCH] [editor] Add move page buttons functionality Also rework selected page index to be managed by the selection service. There is a bug in Angular and as a result Material tab elements brake when the underlying array is changed. To circumvent that we temporarily remove the tab element and add it again, which should re-initialize it. --- .../properties/page-properties.component.ts | 10 +++++-- .../unit-view/unit-view.component.html | 5 ++-- .../unit-view/unit-view.component.ts | 29 +++++++++++++------ projects/editor/src/app/selection.service.ts | 13 +++++++-- projects/editor/src/app/unit.service.ts | 15 ++++++++++ 5 files changed, 56 insertions(+), 16 deletions(-) diff --git a/projects/editor/src/app/components/unit-view/page-view/properties/page-properties.component.ts b/projects/editor/src/app/components/unit-view/page-view/properties/page-properties.component.ts index a93387685..2bacd6d70 100644 --- a/projects/editor/src/app/components/unit-view/page-view/properties/page-properties.component.ts +++ b/projects/editor/src/app/components/unit-view/page-view/properties/page-properties.component.ts @@ -15,11 +15,13 @@ import { MessageService } from '../../../../../../../common/message.service'; <div class="input-group" fxLayoutAlign="space-between center"> Reihenfolge <button mat-icon-button matSuffix color="accent" - [style.margin-left.px]="50"> + [style.margin-left.px]="50" + (click)="movePage('up')"> <mat-icon>north</mat-icon> </button> <button mat-icon-button color="accent" - [style.margin-right.px]="20"> + [style.margin-right.px]="20" + (click)="movePage('down')"> <mat-icon>south</mat-icon> </button> </div> @@ -85,6 +87,10 @@ export class PagePropertiesComponent implements OnInit, OnDestroy { }); } + movePage(direction: 'up' | 'down'): void { + this.unitService.movePage(this.selectedPage, direction); + } + updateModel(property: string, value: number | boolean, isInputValid: boolean | null = true): void { if (isInputValid && value != null) { this.unitService.updatePageProperty(this.selectedPage, property, value); diff --git a/projects/editor/src/app/components/unit-view/unit-view.component.html b/projects/editor/src/app/components/unit-view/unit-view.component.html index e2ca3d85b..97776e377 100644 --- a/projects/editor/src/app/components/unit-view/unit-view.component.html +++ b/projects/editor/src/app/components/unit-view/unit-view.component.html @@ -11,8 +11,9 @@ </mat-drawer> <mat-drawer-content> - <mat-tab-group [style.height.%]="100" mat-align-tabs="start" - [selectedIndex]="selectedPageIndex" + <mat-tab-group *ngIf="pagesLoaded" + [style.height.%]="100" mat-align-tabs="start" + [selectedIndex]="selectionService.selectedPageIndex | async" (selectedIndexChange)="selectPage($event)"> <mat-tab *ngFor="let page of unit.pages; let i = index"> <ng-template mat-tab-label> diff --git a/projects/editor/src/app/components/unit-view/unit-view.component.ts b/projects/editor/src/app/components/unit-view/unit-view.component.ts index ad011b981..b4822387a 100644 --- a/projects/editor/src/app/components/unit-view/unit-view.component.ts +++ b/projects/editor/src/app/components/unit-view/unit-view.component.ts @@ -1,6 +1,6 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { Observable, Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { take, takeUntil } from 'rxjs/operators'; import { UnitService } from '../../unit.service'; import { DialogService } from '../../dialog.service'; import { SelectionService } from '../../selection.service'; @@ -24,8 +24,8 @@ import { Unit } from '../../../../../common/unit'; }) export class UnitViewComponent implements OnInit, OnDestroy { unit!: Unit; - selectedPageIndex: number = 0; private ngUnsubscribe = new Subject<void>(); + pagesLoaded = true; constructor(public selectionService: SelectionService, public unitService: UnitService, @@ -37,25 +37,36 @@ export class UnitViewComponent implements OnInit, OnDestroy { .subscribe((unit: Unit) => { this.unit = unit; }); + // The following is a hack. The tab element gets bugged when changing the underlying array. + // With this we can temporarily remove it from the DOM and then add it again, re-initializing it. + this.unitService.pageMoved + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe(() => { + this.pagesLoaded = false; + setTimeout(() => { + this.pagesLoaded = true; + }); + }); } selectPage(newIndex: number): void { - this.selectedPageIndex = newIndex; - this.selectionService.selectPage(this.unit.pages[this.selectedPageIndex]); + this.selectionService.selectPageIndex(newIndex); } addPage(): void { this.unitService.addPage(); - this.selectionService.selectPage(this.unit.pages[this.unit.pages.length - 1]); - this.selectedPageIndex = this.unit.pages.length - 1; + this.selectionService.selectPageIndex(this.unit.pages.length - 1); } deletePage(): void { this.showConfirmDialog().pipe(takeUntil(this.ngUnsubscribe)).subscribe((result: boolean) => { if (result) { - this.unitService.deletePage(this.selectedPageIndex); - this.selectedPageIndex -= 1; - this.selectionService.selectPage(this.unit.pages[this.selectedPageIndex]); + this.selectionService.selectedPageIndex + .pipe(take(1)) + .subscribe(index => { + this.unitService.deletePage(index); + this.selectionService.selectPageIndex(index - 1); + }).unsubscribe(); } }); } diff --git a/projects/editor/src/app/selection.service.ts b/projects/editor/src/app/selection.service.ts index 576164a54..e2e176d0c 100644 --- a/projects/editor/src/app/selection.service.ts +++ b/projects/editor/src/app/selection.service.ts @@ -12,6 +12,7 @@ export class SelectionService { private unit!: Unit; private _selectedPage!: Subject<UnitPage>; + private _selectedPageIndex: BehaviorSubject<number>; private _selectedPageSection!: BehaviorSubject<UnitPageSection>; private selectedPageSectionComponent!: any; @@ -26,19 +27,25 @@ export class SelectionService { this.unit = unit; }); this._selectedPage = new BehaviorSubject(this.unit.pages[0]); + this._selectedPageIndex = new BehaviorSubject(0); this._selectedPageSection = new BehaviorSubject(this.unit.pages[0].sections[0]); this._selectedElements = new BehaviorSubject([] as UnitUIElement[]); } // === PAGE ======= - selectPage(page: UnitPage): void { - this._selectedPage.next(page); - this._selectedPageSection.next(page.sections[0]); + selectPageIndex(index: number): void { + this._selectedPage.next(this.unit.pages[index]); + this._selectedPageSection.next(this.unit.pages[index].sections[0]); + this._selectedPageIndex.next(index); } get selectedPage(): Observable<UnitPage> { return this._selectedPage.asObservable(); } + + get selectedPageIndex(): Observable<number> { + return this._selectedPageIndex.asObservable(); + } // ### PAGE ###### // === SECTION ===== diff --git a/projects/editor/src/app/unit.service.ts b/projects/editor/src/app/unit.service.ts index 91d6710dc..9506367e2 100644 --- a/projects/editor/src/app/unit.service.ts +++ b/projects/editor/src/app/unit.service.ts @@ -17,6 +17,7 @@ export class UnitService { private _unit: BehaviorSubject<Unit>; elementPropertyUpdated: Subject<void> = new Subject<void>(); + pageMoved: Subject<void> = new Subject<void>(); selectedPageIndex: number = 0; // TODO weg refactorn constructor(private veronaApiService: VeronaAPIService, @@ -57,6 +58,20 @@ export class UnitService { this.veronaApiService.sendVoeDefinitionChangedNotification(); } + /* reorder page in page array */ + movePage(selectedPage: UnitPage, direction: 'up' | 'down'): void { + const oldPageIndex = this._unit.value.pages.indexOf(selectedPage); + if ((this._unit.value.pages.length > 1) && + !(direction === 'down' && oldPageIndex + 1 === this._unit.value.pages.length) && + !(direction === 'up' && oldPageIndex === 0)) { + const newPageIndex = direction === 'up' ? oldPageIndex - 1 : oldPageIndex + 1; + const page = this._unit.value.pages.splice(oldPageIndex, 1); + this._unit.value.pages.splice(newPageIndex, 0, page[0]); + this._unit.next(this._unit.value); + this.pageMoved.next(); + } + } + updatePageProperty(page: UnitPage, property: string, value: number | boolean): void { if (property === 'alwaysVisible' && value === true && !this.isSetPageAlwaysVisibleAllowed()) { this.messageService.showError('Kann nur für eine Seite gesetzt werden'); -- GitLab