diff --git a/projects/common/components/text/remote-control/remote-control.component.ts b/projects/common/components/text/remote-control/remote-control.component.ts index 4beea8d2c307020f5b9129f6853e03637320011a..a12dbe539c2655ce052b190485f983df7b231305 100644 --- a/projects/common/components/text/remote-control/remote-control.component.ts +++ b/projects/common/components/text/remote-control/remote-control.component.ts @@ -15,16 +15,18 @@ import { RemoteMarkingData } from 'common/models/marking-data'; template: ` <aspect-text-marking-bar [elementModel]="elementModel" [selectedColor]="selectedColor || 'none'" - (markingDataChanged)="remoteMarkingDataChanged - .emit({ id: elementModel.id, markingData: $event })"> + [hasDeleteButton]="hasDeleteButton" + (markingDataChanged)="remoteMarkingDataChanged.emit( + { id: elementModel.id, markingData: $event } + )"> </aspect-text-marking-bar> - <div>{{selectedColor}}</div> `, styles: [] }) export class RemoteControlComponent extends ElementComponent { @Input() elementModel!: RemoteControlElement; @Input() selectedColor!: string | undefined; + @Input() hasDeleteButton!: boolean; @Output() remoteMarkingDataChanged: EventEmitter<RemoteMarkingData> = new EventEmitter<RemoteMarkingData>(); protected readonly setTimeout = setTimeout; } diff --git a/projects/common/components/text/text-marking-bar/text-marking-bar.component.ts b/projects/common/components/text/text-marking-bar/text-marking-bar.component.ts index 045f5ee0c858cfaf9a4c34098cdf117ef67fa694..335e4a1bfa98854396a0252422d05bd26ecdf81d 100644 --- a/projects/common/components/text/text-marking-bar/text-marking-bar.component.ts +++ b/projects/common/components/text/text-marking-bar/text-marking-bar.component.ts @@ -27,7 +27,7 @@ import { MarkingData } from 'common/models/marking-data'; mode="mark" (selectedMarkingChanged)="changeMarkingData($event)"> </aspect-text-marking-button> - <aspect-text-marking-button *ngIf="elementModel.markingMode === 'selection'" + <aspect-text-marking-button *ngIf="hasDeleteButton" [color]="selectionColors.delete" [isMarkingSelected]="selectionColors[selectedColor] === selectionColors.delete" mode="delete" @@ -40,6 +40,7 @@ import { MarkingData } from 'common/models/marking-data'; }) export class TextMarkingBarComponent { @Input() elementModel!: TextElement | RemoteControlElement; + @Input() hasDeleteButton!: boolean; @Output() markingDataChanged = new EventEmitter<MarkingData>(); @Input() selectedColor!: string; diff --git a/projects/common/components/text/text.component.ts b/projects/common/components/text/text.component.ts index 5dfef47afaad4ee8c6e6bf0e1e31d4ec04540660..ab75cf5805c5e9914895b3c4bcf5cb0964bbf8c3 100644 --- a/projects/common/components/text/text.component.ts +++ b/projects/common/components/text/text.component.ts @@ -1,5 +1,5 @@ import { - AfterViewInit, Component, ElementRef, EventEmitter, Input, OnDestroy, Output, ViewChild + AfterViewInit, Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; import { TextElement } from 'common/models/elements/text/text'; import { ValueChangeElement } from 'common/models/elements/element'; @@ -17,6 +17,7 @@ import { ElementComponent } from '../../directives/element-component.directive'; elementModel.highlightableTurquoise || elementModel.highlightableOrange" [selectedColor]="selectedColor.value || 'none'" + [hasDeleteButton]="elementModel.markingMode === 'selection'" [elementModel]="elementModel" (markingDataChanged)="selectedColor.next($event.colorName); markingDataChanged.emit($event)"> </aspect-text-marking-bar> @@ -58,9 +59,10 @@ import { ElementComponent } from '../../directives/element-component.directive'; '::ng-deep sub {line-height: 0;}' ] }) -export class TextComponent extends ElementComponent implements AfterViewInit, OnDestroy { +export class TextComponent extends ElementComponent implements OnInit, AfterViewInit, OnDestroy { @Input() elementModel!: TextElement; @Input() savedText!: string; + @Output() selectedColorChanged = new EventEmitter<string | undefined>(); @Output() elementValueChanged = new EventEmitter<ValueChangeElement>(); @Output() textSelectionStart = new EventEmitter<PointerEvent>(); @Output() markingDataChanged = new EventEmitter<{ @@ -78,6 +80,10 @@ export class TextComponent extends ElementComponent implements AfterViewInit, On @ViewChild('textContainerRef') textContainerRef!: ElementRef; + ngOnInit(): void { + this.selectedColor.subscribe(color => this.selectedColorChanged.emit(color)); + } + startTextSelection(event: PointerEvent): void { if (this.elementModel.markingMode === 'selection' && (this.elementModel.highlightableYellow || diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/highlight-properties.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/highlight-properties.component.ts index 3ca6748620bfb66b58997cabd1cd71723c29908b..733ca0fff64d59fc5070a8f8ee9f7ef908b9fca7 100644 --- a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/highlight-properties.component.ts +++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/highlight-properties.component.ts @@ -3,11 +3,9 @@ import { } from '@angular/core'; import { CombinedProperties } from 'editor/src/app/components/properties-panel/element-properties-panel.component'; import { MatCheckboxModule } from '@angular/material/checkbox'; -import { NgForOf, NgIf } from '@angular/common'; +import { NgIf } from '@angular/common'; import { TranslateModule } from '@ngx-translate/core'; import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatOptionModule } from '@angular/material/core'; -import { MatSelectModule } from '@angular/material/select'; @Component({ selector: 'aspect-highlight-properties', @@ -16,34 +14,27 @@ import { MatSelectModule } from '@angular/material/select'; MatCheckboxModule, NgIf, TranslateModule, - MatFormFieldModule, - MatOptionModule, - MatSelectModule, - NgForOf + MatFormFieldModule ], template: ` - <div class="fx-column-start-stretch"> - <div> - <mat-checkbox *ngIf="combinedProperties.highlightableYellow !== undefined" - [disabled]="disabled" - [checked]="$any(combinedProperties.highlightableYellow)" - (change)="updateModel.emit({ property: 'highlightableYellow', value: $event.checked })"> - {{'propertiesPanel.highlightableYellow' | translate }} - </mat-checkbox> - <mat-checkbox *ngIf="combinedProperties.highlightableTurquoise !== undefined" - [disabled]="disabled" - [checked]="$any(combinedProperties.highlightableTurquoise)" - (change)="updateModel.emit({ property: 'highlightableTurquoise', value: $event.checked })"> - {{'propertiesPanel.highlightableTurquoise' | translate }} - </mat-checkbox> - <mat-checkbox *ngIf="combinedProperties.highlightableOrange !== undefined" - [disabled]="disabled" - [checked]="$any(combinedProperties.highlightableOrange)" - (change)="updateModel.emit({ property: 'highlightableOrange', value: $event.checked })"> - {{'propertiesPanel.highlightableOrange' | translate }} - </mat-checkbox> - </div> - </div> + <mat-checkbox *ngIf="combinedProperties.highlightableYellow !== undefined" + [disabled]="disabled" + [checked]="$any(combinedProperties.highlightableYellow)" + (change)="updateModel.emit({ property: 'highlightableYellow', value: $event.checked })"> + {{'propertiesPanel.highlightableYellow' | translate }} + </mat-checkbox> + <mat-checkbox *ngIf="combinedProperties.highlightableTurquoise !== undefined" + [disabled]="disabled" + [checked]="$any(combinedProperties.highlightableTurquoise)" + (change)="updateModel.emit({ property: 'highlightableTurquoise', value: $event.checked })"> + {{'propertiesPanel.highlightableTurquoise' | translate }} + </mat-checkbox> + <mat-checkbox *ngIf="combinedProperties.highlightableOrange !== undefined" + [disabled]="disabled" + [checked]="$any(combinedProperties.highlightableOrange)" + (change)="updateModel.emit({ property: 'highlightableOrange', value: $event.checked })"> + {{'propertiesPanel.highlightableOrange' | translate }} + </mat-checkbox> ` }) diff --git a/projects/player/src/app/classes/text-marking-support.ts b/projects/player/src/app/classes/text-marking-support.ts index 827aa49bc5e5392f8947ae1a3e2bd5be9360e95d..fea4c29eddc0560ffb0015effe3bbe48a9684017 100644 --- a/projects/player/src/app/classes/text-marking-support.ts +++ b/projects/player/src/app/classes/text-marking-support.ts @@ -4,6 +4,7 @@ import { NativeEventService } from 'player/src/app/services/native-event.service import { AnchorService } from 'player/src/app/services/anchor.service'; import { Subject } from 'rxjs'; import { TextComponent } from 'common/components/text/text.component'; +import { MarkingData } from 'common/models/marking-data'; export class TextMarkingSupport { isMarkingBarOpen: boolean = false; @@ -20,13 +21,13 @@ export class TextMarkingSupport { } applyMarkingData( - selection: { active: boolean; mode: 'mark' | 'delete'; color: string; colorName: string | undefined }, + markingData: MarkingData, elementComponent: TextComponent ): void { - if (selection.active) { - this.selectedColor = selection.color; - this.selectedMode = selection.mode; - this.applyMarkingDataToText(selection.mode, selection.color, elementComponent); + if (markingData.active) { + this.selectedColor = markingData.color; + this.selectedMode = markingData.mode; + this.applyMarkingDataToText(markingData.mode, markingData.color, elementComponent); } else { this.selectedColor = null; this.selectedMode = null; diff --git a/projects/player/src/app/components/elements/interactive-group-element/interactive-group-element.component.html b/projects/player/src/app/components/elements/interactive-group-element/interactive-group-element.component.html index dd50c5781693d8991419a0e3b12649719dbad1e2..8f0abbb68d1e59c9dbe8326dfc8a69c8e8556409 100644 --- a/projects/player/src/app/components/elements/interactive-group-element/interactive-group-element.component.html +++ b/projects/player/src/app/components/elements/interactive-group-element/interactive-group-element.component.html @@ -33,6 +33,7 @@ <aspect-remote-control *ngIf="elementModel.type === 'remote-control'" #elementComponent + [hasDeleteButton]="hasDeleteButton" [selectedColor]="selectedColor" [elementModel]="elementModel | cast: RemoteControlElement" (remoteMarkingDataChanged)="remoteControlService.broadcastMarkingData($event)"> diff --git a/projects/player/src/app/components/elements/interactive-group-element/interactive-group-element.component.ts b/projects/player/src/app/components/elements/interactive-group-element/interactive-group-element.component.ts index 8bf54ae5acc9f8c7a4b5f2f53ff3fc33d2673b36..bd79ff12161f56286cc3924e354e055f650de3cb 100644 --- a/projects/player/src/app/components/elements/interactive-group-element/interactive-group-element.component.ts +++ b/projects/player/src/app/components/elements/interactive-group-element/interactive-group-element.component.ts @@ -14,9 +14,10 @@ import { MathTableCell, MathTableElement, MathTableRow } from 'common/models/ele import { KeypadService } from 'player/src/app/services/keypad.service'; import { KeyboardService } from 'player/src/app/services/keyboard.service'; import { DeviceService } from 'player/src/app/services/device.service'; -import { Subscription } from 'rxjs'; +import { Subject, Subscription } from 'rxjs'; import { MathTableComponent } from 'common/components/input-elements/math-table.component'; import { RemoteControlService } from 'player/src/app/services/remote-control.service'; +import { takeUntil } from 'rxjs/operators'; import { UnitStateService } from '../../../services/unit-state.service'; import { ElementGroupDirective } from '../../../directives/element-group.directive'; import { ElementModelElementCodeMappingService } from '../../../services/element-model-element-code-mapping.service'; @@ -47,6 +48,8 @@ export class InteractiveGroupElementComponent keyboardDeleteCharactersSubscription!: Subscription; selectedColor: string | undefined; + hasDeleteButton: boolean = false; + private ngUnsubscribe: Subject<void> = new Subject(); constructor( public unitStateService: UnitStateService, @@ -61,7 +64,7 @@ export class InteractiveGroupElementComponent public remoteControlService: RemoteControlService ) { super(); - this.subscribeTomarkingColorChanged(); + this.subscribeToMarkingColorChanged(); } ngOnInit(): void { @@ -93,11 +96,13 @@ export class InteractiveGroupElementComponent this.pageIndex); } - private subscribeTomarkingColorChanged() { + private subscribeToMarkingColorChanged() { this.remoteControlService.markingColorChanged + .pipe(takeUntil(this.ngUnsubscribe)) .subscribe(markingColor => { if (markingColor.markingBars.includes(this.elementModel.id)) { this.selectedColor = markingColor.color; + this.hasDeleteButton = (markingColor.markingMode === 'selection'); } }); } @@ -239,6 +244,8 @@ export class InteractiveGroupElementComponent } ngOnDestroy(): void { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); this.unsubscribeFromKeypadEvents(); this.unsubscribeFromKeyboardEvents(); } diff --git a/projects/player/src/app/components/elements/text-group-element/text-group-element.component.html b/projects/player/src/app/components/elements/text-group-element/text-group-element.component.html index 50502b6c6b9c673143f78602088744d208664619..4a8018acb5a338920679b0d844ca109ece6acdbd 100644 --- a/projects/player/src/app/components/elements/text-group-element/text-group-element.component.html +++ b/projects/player/src/app/components/elements/text-group-element/text-group-element.component.html @@ -4,6 +4,7 @@ [savedText]="savedText" (markingDataChanged)="textMarkingSupport.applyMarkingData($event, elementComponent)" (textSelectionStart)="textMarkingSupport.startTextSelection($event, elementComponent)" + (selectedColorChanged)="broadcastMarkingColorChange($event)" (elementValueChanged)="changeElementCodeValue($event)"> </aspect-text> diff --git a/projects/player/src/app/components/elements/text-group-element/text-group-element.component.ts b/projects/player/src/app/components/elements/text-group-element/text-group-element.component.ts index da71b5f867a61c9468b36bad1f7fe3c98d9f4807..ffee467f1c83e8ef3235a54f33abca74506d2cfa 100644 --- a/projects/player/src/app/components/elements/text-group-element/text-group-element.component.ts +++ b/projects/player/src/app/components/elements/text-group-element/text-group-element.component.ts @@ -15,6 +15,8 @@ import { TextMarkingSupport } from 'player/src/app/classes/text-marking-support' import { MarkableSupport } from 'player/src/app/classes/markable-support'; import { RemoteControlService } from 'player/src/app/services/remote-control.service'; import { MarkingData, RemoteMarkingData } from 'common/models/marking-data'; +import { takeUntil } from 'rxjs/operators'; +import { Subject, take } from 'rxjs'; import { NativeEventService } from '../../../services/native-event.service'; import { UnitStateService } from '../../../services/unit-state.service'; import { ElementGroupDirective } from '../../../directives/element-group.directive'; @@ -32,6 +34,7 @@ export class TextGroupElementComponent extends ElementGroupDirective implements markableSupport: MarkableSupport; savedText: string = ''; savedMarks: string[] = []; + private ngUnsubscribe = new Subject<void>(); constructor( nativeEventService: NativeEventService, @@ -71,27 +74,39 @@ export class TextGroupElementComponent extends ElementGroupDirective implements }), this.elementComponent, this.pageIndex); - this.elementComponent.selectedColor - .subscribe(color => this.remoteControlService - .broadcastMarkingColorChange({ - color: color, - id: this.elementModel.id, - markingBars: (this.elementModel as TextElement).markingBars - })); + // timeout is needed to give remote controls on other pages time to initialize + setTimeout(() => this.broadcastMarkingColorChange(undefined)); + } + + broadcastMarkingColorChange(color: string | undefined): void { + this.remoteControlService + .broadcastMarkingColorChange({ + color: color, + id: this.elementModel.id, + markingMode: (this.elementModel as TextElement).markingMode, + markingBars: (this.elementModel as TextElement).markingBars + }); } private subscribeToMarkingDataChanged() { this.remoteControlService.remoteMarkingDataChanged + .pipe(takeUntil(this.ngUnsubscribe)) .subscribe((data: RemoteMarkingData) => { if ((this.elementModel as TextElement).markingBars.includes(data.id)) { this.elementComponent.selectedColor .next(TextGroupElementComponent.getSelectedColorValue(data.markingData)); + this.textMarkingSupport.applyMarkingData(data.markingData, this.elementComponent); + this.elementComponent.textSelectionStart + .pipe(takeUntil(this.ngUnsubscribe), take(1)) + .subscribe(pointerEvent => { + this.textMarkingSupport.startTextSelection(pointerEvent, this.elementComponent); + }); } }); } private static getSelectedColorValue(markingData: MarkingData): string | undefined { - if (!markingData.active || markingData.mode !== 'mark') return undefined; + if (!markingData.active) return undefined; return markingData.colorName; } @@ -114,6 +129,8 @@ export class TextGroupElementComponent extends ElementGroupDirective implements } ngOnDestroy(): void { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); this.textMarkingSupport.destroy(); } } diff --git a/projects/player/src/app/models/markable.interface.ts b/projects/player/src/app/models/markable.interface.ts index f05f9ee6430eebab6b9a1c90e184628ccc8a1e19..77a30cfb063ec6608991b47a53e4c70354ebaa64 100644 --- a/projects/player/src/app/models/markable.interface.ts +++ b/projects/player/src/app/models/markable.interface.ts @@ -15,5 +15,6 @@ export interface Markable { export interface MarkingColor { id: string, color: string | undefined, + markingMode: 'selection' | 'word' | 'range', markingBars: string[] }