From f6668bddd2516c4cafe09895605658cf7cd8a33c Mon Sep 17 00:00:00 2001
From: jojohoch <joachim.hoch@iqb.hu-berlin.de>
Date: Wed, 2 Mar 2022 09:29:25 +0100
Subject: [PATCH] [player] Implement page navigation action for buttons

---
 .../ui-elements/button.component.ts           | 28 ++++++++++++++-----
 projects/common/interfaces/elements.ts        |  3 +-
 projects/common/util/element.factory.ts       |  1 +
 .../element-interactive-group.component.html  |  4 ++-
 .../element-interactive-group.component.ts    |  4 ++-
 .../player-state/player-state.component.ts    | 20 ++++++-------
 6 files changed, 40 insertions(+), 20 deletions(-)

diff --git a/projects/common/components/ui-elements/button.component.ts b/projects/common/components/ui-elements/button.component.ts
index 6f8ff3c8e..6102e11f3 100644
--- a/projects/common/components/ui-elements/button.component.ts
+++ b/projects/common/components/ui-elements/button.component.ts
@@ -19,15 +19,26 @@ import { ButtonElement } from '../../interfaces/elements';
             [style.font-style]="elementModel.styles.italic ? 'italic' : ''"
             [style.text-decoration]="elementModel.styles.underline ? 'underline' : ''"
             [style.border-radius.px]="elementModel.styles.borderRadius"
-            (click)="elementModel.action ? navigationRequested.emit(elementModel.action) : false">
+            (click)="elementModel.action && elementModel.actionParam !== null ?
+               navigateTo.emit({
+                  action: elementModel.action,
+                  param: elementModel.actionParam
+               }) :
+               false">
       {{elementModel.label}}
     </button>
-    <input *ngIf="elementModel.imageSrc" type="image"
-           [src]="elementModel.imageSrc | safeResourceUrl"
-           [class]="elementModel.positionProps.dynamicPositioning &&
+    <input
+        *ngIf="elementModel.imageSrc" type="image"
+        [src]="elementModel.imageSrc | safeResourceUrl"
+        [class]="elementModel.positionProps.dynamicPositioning &&
                     !elementModel.positionProps.fixedSize ? 'dynamic-image' : 'static-image'"
-           [alt]="'imageNotFound' | translate"
-           (click)="elementModel.action ? navigationRequested.emit(elementModel.action) : false">
+        [alt]="'imageNotFound' | translate"
+        (click)="elementModel.action && elementModel.actionParam !== null?
+           navigateTo.emit({
+              action: elementModel.action,
+              param: elementModel.actionParam
+           }) :
+           false">
   `,
   styles: [
     '.dynamic-image {width: 100%; height: fit-content;}',
@@ -37,5 +48,8 @@ import { ButtonElement } from '../../interfaces/elements';
 })
 export class ButtonComponent extends ElementComponent {
   @Input() elementModel!: ButtonElement;
-  @Output() navigationRequested = new EventEmitter<'previous' | 'next' | 'first' | 'last' | 'end'>();
+  @Output() navigateTo = new EventEmitter<{
+    action: 'unitNav' | 'pageNav';
+    param: 'previous' | 'next' | 'first' | 'last' | 'end' | number
+  }>();
 }
diff --git a/projects/common/interfaces/elements.ts b/projects/common/interfaces/elements.ts
index 70d645c79..f1c1e218c 100644
--- a/projects/common/interfaces/elements.ts
+++ b/projects/common/interfaces/elements.ts
@@ -123,7 +123,8 @@ export interface ButtonElement extends UIElement {
   type: 'button';
   label: string;
   imageSrc: string | null;
-  action: null | 'previous' | 'next' | 'first' | 'last' | 'end';
+  action: null | 'unitNav' | 'pageNav'
+  actionParam: null | 'previous' | 'next' | 'first' | 'last' | 'end' | number;
   positionProps: PositionProperties;
   styles: BasicStyles & {
     borderRadius: number;
diff --git a/projects/common/util/element.factory.ts b/projects/common/util/element.factory.ts
index a76aa9595..6c44380d8 100644
--- a/projects/common/util/element.factory.ts
+++ b/projects/common/util/element.factory.ts
@@ -210,6 +210,7 @@ export abstract class ElementFactory {
       label: 'Knopf',
       imageSrc: null,
       action: null,
+      actionParam: null,
       positionProps: ElementFactory.initPositionProps(defaults.positionProps),
       styles: {
         ...ElementFactory.initBasicStyles(defaults),
diff --git a/projects/player/src/app/components/element-interactive-group/element-interactive-group.component.html b/projects/player/src/app/components/element-interactive-group/element-interactive-group.component.html
index 98b770294..1a6e963b1 100644
--- a/projects/player/src/app/components/element-interactive-group/element-interactive-group.component.html
+++ b/projects/player/src/app/components/element-interactive-group/element-interactive-group.component.html
@@ -2,7 +2,9 @@
     *ngIf="elementModel.type === 'button'"
     #elementComponent
     [elementModel]="elementModel | cast: ButtonElement"
-    (navigationRequested)="veronaPostService.sendVopUnitNavigationRequestedNotification($event)">
+    (navigateTo)="($event.action === 'unitNav') ?
+      veronaPostService.sendVopUnitNavigationRequestedNotification($any($event.param)) :
+      navigationService.setPage($any($event.param))">
 </aspect-button>
 <aspect-frame
     *ngIf="elementModel.type === 'frame'"
diff --git a/projects/player/src/app/components/element-interactive-group/element-interactive-group.component.ts b/projects/player/src/app/components/element-interactive-group/element-interactive-group.component.ts
index 2967bf4ad..21944dfab 100644
--- a/projects/player/src/app/components/element-interactive-group/element-interactive-group.component.ts
+++ b/projects/player/src/app/components/element-interactive-group/element-interactive-group.component.ts
@@ -8,6 +8,7 @@ import { VeronaPostService } from '../../services/verona-post.service';
 import { UnitStateService } from '../../services/unit-state.service';
 import { ElementGroupDirective } from '../../directives/element-group.directive';
 import { ElementComponent } from '../../../../../common/directives/element-component.directive';
+import { NavigationService } from '../../services/navigation.service';
 
 @Component({
   selector: 'aspect-element-interactive-group',
@@ -21,8 +22,9 @@ export class ElementInteractiveGroupComponent extends ElementGroupDirective impl
   ImageElement!: ImageElement;
 
   constructor(
+    public unitStateService: UnitStateService,
     public veronaPostService: VeronaPostService,
-    public unitStateService: UnitStateService
+    public navigationService: NavigationService
   ) {
     super();
   }
diff --git a/projects/player/src/app/components/player-state/player-state.component.ts b/projects/player/src/app/components/player-state/player-state.component.ts
index 71b6ed19b..091ae7a07 100644
--- a/projects/player/src/app/components/player-state/player-state.component.ts
+++ b/projects/player/src/app/components/player-state/player-state.component.ts
@@ -10,6 +10,7 @@ import {
 } from '../../models/verona';
 import { VeronaPostService } from '../../services/verona-post.service';
 import { Page } from '../../../../../common/interfaces/unit';
+import { NavigationService } from '../../services/navigation.service';
 
 @Component({
   selector: 'aspect-player-state',
@@ -27,18 +28,23 @@ export class PlayerStateComponent implements OnInit, OnDestroy {
 
   private ngUnsubscribe = new Subject<void>();
 
-  constructor(private veronaSubscriptionService: VeronaSubscriptionService,
-              private veronaPostService: VeronaPostService) {
-  }
+  constructor(
+    private veronaSubscriptionService: VeronaSubscriptionService,
+    private veronaPostService: VeronaPostService,
+    private navigationService: NavigationService
+  ) {}
 
   ngOnInit(): void {
     this.initSubscriptions();
   }
 
   private initSubscriptions(): void {
+    this.navigationService.pageIndex
+      .pipe(takeUntil(this.ngUnsubscribe))
+      .subscribe((pageIndex: number): void => this.selectIndex.next(pageIndex));
     this.veronaSubscriptionService.vopPageNavigationCommand
       .pipe(takeUntil(this.ngUnsubscribe))
-      .subscribe((message: VopPageNavigationCommand): void => this.onPageNavigation(message));
+      .subscribe((message: VopPageNavigationCommand): void => this.selectIndex.next(Number(message.target)));
     this.veronaSubscriptionService.vopContinueCommand
       .pipe(takeUntil(this.ngUnsubscribe))
       .subscribe((message: VopContinueCommand): void => this.onContinue(message));
@@ -86,12 +92,6 @@ export class PlayerStateComponent implements OnInit, OnDestroy {
     this.sendVopStateChangedNotification(true);
   }
 
-  private onPageNavigation(message: VopPageNavigationCommand): void {
-    // eslint-disable-next-line no-console
-    console.log('player: onPageNavigation', message);
-    this.selectIndex.next(parseInt(message.target, 10));
-  }
-
   private sendVopStateChangedNotification(requested:boolean = false): void {
     const playerState: PlayerState = {
       state: this.state,
-- 
GitLab