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 303d7cfc06b20a6450dacc5dca2932c56aa352ef..34ca219d329e26b947de15faf344da27774ce3b7 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 @@ -25,7 +25,8 @@ import { TextElement } from 'common/models/elements/text/text'; mode="mark" (selectedMarkingChanged)="changeMarkingData($event)"> </aspect-text-marking-button> - <aspect-text-marking-button [color]="selectionColors.delete" + <aspect-text-marking-button *ngIf="elementModel.markingMode === 'default'" + [color]="selectionColors.delete" [isMarkingSelected]="selectedColor === selectionColors.delete" mode="delete" (selectedMarkingChanged)="changeMarkingData($event)"> diff --git a/projects/common/components/text/text.component.ts b/projects/common/components/text/text.component.ts index 8d2f2cfe6991030723c64504d15e49ffb6998c78..7cb52732c288bc01d20711755854becc975f3560 100644 --- a/projects/common/components/text/text.component.ts +++ b/projects/common/components/text/text.component.ts @@ -4,6 +4,7 @@ import { import { TextElement } from 'common/models/elements/text/text'; import { ValueChangeElement } from 'common/models/elements/element'; import { ImageFullscreenDirective } from 'common/directives/image-fullscreen.directive'; +import { BehaviorSubject } from 'rxjs'; import { ElementComponent } from '../../directives/element-component.directive'; @Component({ @@ -12,18 +13,18 @@ import { ElementComponent } from '../../directives/element-component.directive'; <div [style.width.%]="100" [style.height.%]="100"> <aspect-text-marking-bar - *ngIf="elementModel.markingMode === 'default' && ( + *ngIf="elementModel.markingMode !== 'none' && ( elementModel.highlightableYellow || elementModel.highlightableTurquoise || elementModel.highlightableOrange)" [elementModel]="elementModel" - (markingDataChanged)="selectedColor=$event.colorName; markingDataChanged.emit($event)"> + (markingDataChanged)="selectedColor.next($event.colorName); markingDataChanged.emit($event)"> </aspect-text-marking-bar> <div #textContainerRef class="text-container" - [class.orange-selection]="selectedColor === 'orange'" - [class.yellow-selection]="selectedColor === 'yellow'" - [class.turquoise-selection]="selectedColor === 'turquoise'" - [class.delete-selection]="selectedColor === 'delete'" + [class.orange-selection]="selectedColor.value === 'orange'" + [class.yellow-selection]="selectedColor.value === 'yellow'" + [class.turquoise-selection]="selectedColor.value === 'turquoise'" + [class.delete-selection]="selectedColor.value === 'delete'" [style.background-color]="elementModel.styling.backgroundColor" [style.color]="elementModel.styling.fontColor" [style.font-size.px]="elementModel.styling.fontSize" @@ -71,7 +72,7 @@ export class TextComponent extends ElementComponent implements AfterViewInit, On @ViewChild(ImageFullscreenDirective) imageFullScreenDirective!: ImageFullscreenDirective; - selectedColor!: string | undefined; + selectedColor: BehaviorSubject<string | undefined> = new BehaviorSubject<string | undefined>(undefined); static textComponents: { [id: string]: TextComponent } = {}; diff --git a/projects/common/models/elements/text/text.ts b/projects/common/models/elements/text/text.ts index 10e3c4c55bc17172debbbd5d852e2dae33402d31..5beeb03b9b07fd760161712652d40bef8dc73529 100644 --- a/projects/common/models/elements/text/text.ts +++ b/projects/common/models/elements/text/text.ts @@ -12,7 +12,7 @@ import { InstantiationEror } from 'common/util/errors'; export class TextElement extends UIElement implements TextProperties { type: UIElementType = 'text'; text: string = 'Lorem ipsum dolor sit amet'; - markingMode: 'none' | 'default' | 'word' | 'range' = 'word'; + markingMode: 'none' | 'default' | 'word' | 'range' = 'none'; highlightableOrange: boolean = false; highlightableTurquoise: boolean = false; highlightableYellow: boolean = false; diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/ele-specific/text-properties-field-set.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/ele-specific/text-properties-field-set.component.ts index 37bb69e6efb9d912585e26ebf54673fd2147915f..64b0123146142ac8f020b2e31636f27ccb680e82 100644 --- a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/ele-specific/text-properties-field-set.component.ts +++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/ele-specific/text-properties-field-set.component.ts @@ -6,9 +6,11 @@ import { MatInputModule } from '@angular/material/input'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { SharedModule } from 'common/shared.module'; import { TextElement } from 'common/models/elements/text/text'; -import { DialogService } from '../../../../../services/dialog.service'; -import { SelectionService } from '../../../../../services/selection.service'; import { UnitService } from 'editor/src/app/services/unit-services/unit.service'; +import { MatOptionModule } from '@angular/material/core'; +import { MatSelectModule } from '@angular/material/select'; +import { SelectionService } from '../../../../../services/selection.service'; +import { DialogService } from '../../../../../services/dialog.service'; @Component({ selector: 'aspect-text-props', @@ -17,7 +19,9 @@ import { UnitService } from 'editor/src/app/services/unit-services/unit.service' NgIf, SharedModule, MatInputModule, - MatCheckboxModule + MatCheckboxModule, + MatOptionModule, + MatSelectModule ], template: ` <div *ngIf="combinedProperties.text" class="fx-column-start-stretch"> @@ -42,25 +46,42 @@ import { UnitService } from 'editor/src/app/services/unit-services/unit.service' combinedProperties.highlightableTurquoise !== undefined || combinedProperties.highlightableOrange !== undefined"> {{'propertiesPanel.highlightable' | translate }}</div> + + <mat-form-field *ngIf="combinedProperties.markingMode !== undefined" appearance="fill"> + <mat-label>{{'propertiesPanel.markingMode' | translate }}</mat-label> + <mat-select [value]="combinedProperties.markingMode" + (selectionChange)="updateModel.emit({ property: 'markingMode', value: $event.value })"> + <mat-option *ngFor="let option of ['none', 'default', 'word', 'range']" + [value]="option"> + {{ 'propertiesPanel.markingMode-'+option | translate }} + </mat-option> + </mat-select> + </mat-form-field> + + <mat-checkbox *ngIf="combinedProperties.highlightableYellow !== undefined" + [disabled]="combinedProperties.markingMode === 'none'" [checked]="$any(combinedProperties.highlightableYellow)" (change)="updateModel.emit({ property: 'highlightableYellow', value: $event.checked })"> {{'propertiesPanel.highlightableYellow' | translate }} </mat-checkbox> <mat-checkbox *ngIf="combinedProperties.highlightableTurquoise !== undefined" + [disabled]="combinedProperties.markingMode === 'none'" [checked]="$any(combinedProperties.highlightableTurquoise)" (change)="updateModel.emit({ property: 'highlightableTurquoise', value: $event.checked })"> {{'propertiesPanel.highlightableTurquoise' | translate }} </mat-checkbox> <mat-checkbox *ngIf="combinedProperties.highlightableOrange !== undefined" + [disabled]="combinedProperties.markingMode === 'none'" [checked]="$any(combinedProperties.highlightableOrange)" (change)="updateModel.emit({ property: 'highlightableOrange', value: $event.checked })"> {{'propertiesPanel.highlightableOrange' | translate }} </mat-checkbox> <mat-checkbox *ngIf="unitService.expertMode && combinedProperties.hasSelectionPopup !== undefined" - [disabled]="!combinedProperties.highlightableYellow && + [disabled]="combinedProperties.markingMode !== 'default' || + (!combinedProperties.highlightableYellow && !combinedProperties.highlightableTurquoise && - !combinedProperties.highlightableOrange" + !combinedProperties.highlightableOrange)" [style.margin-top.px]="5" [checked]="$any(combinedProperties.hasSelectionPopup)" (change)="updateModel.emit({ property: 'hasSelectionPopup', value: $event.checked })"> diff --git a/projects/editor/src/assets/i18n/de.json b/projects/editor/src/assets/i18n/de.json index 285cbdeee923255736112f1ce87ea7bf5f508f68..45723e4ca17a0a7461e7e490a41ee1b040b4154f 100644 --- a/projects/editor/src/assets/i18n/de.json +++ b/projects/editor/src/assets/i18n/de.json @@ -119,6 +119,11 @@ "text": "Text", "borderRadius": "Radius", "highlightable": "Markieren erlauben", + "markingMode": "Markierungsmodus", + "markingMode-none": "Keine Markierung", + "markingMode-default": "Freie Markierung", + "markingMode-word": "Wort", + "markingMode-range": "Bereich", "highlightableYellow": "Gelb", "highlightableTurquoise": "Türkis", "highlightableOrange": "Orange", diff --git a/projects/player/src/app/classes/markable-support.ts b/projects/player/src/app/classes/markable-support.ts index 280009927470d8c242df6a55ff50075f8b305b2a..ca6649826b4ade75c68bfd495923fe894bc4d190 100644 --- a/projects/player/src/app/classes/markable-support.ts +++ b/projects/player/src/app/classes/markable-support.ts @@ -37,6 +37,7 @@ export class MarkableSupport { hostElement: markableContainerElement }); componentRef.instance.markables = markablesContainer.markables; + componentRef.instance.selectedColor = elementComponent.selectedColor; componentRef.instance.markablesChange.subscribe(() => { elementComponent.elementValueChanged.emit( { @@ -75,7 +76,7 @@ export class MarkableSupport { const word = wordWithWhitespace.match(/\S+/); const suffix = wordWithWhitespace.match(/[^\S]\s*$/); const id = startIndex + index; - const markedWord = MarkableSupport.getMarkedValueById(id, savedMarks); + const markedWord = MarkableSupport.getColorValueById(id, savedMarks); markables.push( { id: id, @@ -83,7 +84,7 @@ export class MarkableSupport { word: word ? word[0] : '', suffix: suffix ? suffix[0] : '', isActive: !!(word && word[0].length), - marked: markedWord + color: markedWord } ); }); @@ -107,7 +108,9 @@ export class MarkableSupport { return nodes; } - private static getMarkedValueById(id: number, savedMarks: string[]): boolean { - return savedMarks.map((mark: string) => mark.split('-')[0]).includes(id.toString()); + private static getColorValueById(id: number, savedMarks: string[]): string | null { + const savedMarkById = savedMarks.map(savedMark => savedMark.split('-')) + .find(mark => mark[0] === id.toString()); + return savedMarkById ? savedMarkById[2] : null; } } diff --git a/projects/player/src/app/components/elements/compound-group-element/compound-group-element.component.ts b/projects/player/src/app/components/elements/compound-group-element/compound-group-element.component.ts index 6fb17e9df49140a92a1f53f8f1a6f3f1e37d64eb..1d791b3e6980c5950cc3429a8a72f77e4fe6c3ab 100644 --- a/projects/player/src/app/components/elements/compound-group-element/compound-group-element.component.ts +++ b/projects/player/src/app/components/elements/compound-group-element/compound-group-element.component.ts @@ -171,8 +171,7 @@ export class CompoundGroupElementComponent extends TextInputGroupDirective imple this.getTextChildModelValue(childModel as TextElement), childModel.type, { - markingMode: (childModel as TextElement).markingMode, - color: 'yellow' + markingMode: (childModel as TextElement).markingMode }); break; default: @@ -208,7 +207,7 @@ export class CompoundGroupElementComponent extends TextInputGroupDirective imple this.addElementCodeValueSubscription( child as TextComponent, childModel, - { markingMode: 'word', color: 'yellow' } + { markingMode: 'word' } ); } if (childModel.type === 'image') { diff --git a/projects/player/src/app/components/elements/markable-word/markable-word.component.html b/projects/player/src/app/components/elements/markable-word/markable-word.component.html index 673090844330dc52fdf593463fd96de71f0a0d36..7804896676b8999c3d412500709b3879c4a2db22 100644 --- a/projects/player/src/app/components/elements/markable-word/markable-word.component.html +++ b/projects/player/src/app/components/elements/markable-word/markable-word.component.html @@ -1,3 +1,4 @@ -<span class="prevent-select" - [style.background-color]="marked ? selectionColors.yellow : 'transparent'" +<span class="prevent-select is-active" + [class.is-active]="!!(markColor && markColor !== 'none')" + [style.background-color]="color ? color : 'transparent'" (click)="toggleMarked()">{{text}}</span> diff --git a/projects/player/src/app/components/elements/markable-word/markable-word.component.scss b/projects/player/src/app/components/elements/markable-word/markable-word.component.scss index 29acef0c1d7e06cf0a6efed161b655b625b388ae..328c754305f6494d089e435456fae127a6a246d1 100644 --- a/projects/player/src/app/components/elements/markable-word/markable-word.component.scss +++ b/projects/player/src/app/components/elements/markable-word/markable-word.component.scss @@ -1,5 +1,5 @@ -.marked { - background-color: red; +.is-active { + cursor: pointer; } .prevent-select { diff --git a/projects/player/src/app/components/elements/markable-word/markable-word.component.ts b/projects/player/src/app/components/elements/markable-word/markable-word.component.ts index 79235e474b7d998ff3b8909d5d6751319d48b233..4d926c6ef640d6d1ff1d55b59199883e6a505d41 100644 --- a/projects/player/src/app/components/elements/markable-word/markable-word.component.ts +++ b/projects/player/src/app/components/elements/markable-word/markable-word.component.ts @@ -12,13 +12,21 @@ import { TextElement } from 'common/models/elements/text/text'; }) export class MarkableWordComponent { @Input() text = ''; - @Input() marked!: boolean; - @Output() markedChange = new EventEmitter<boolean>(); + @Input() color!: string | null; + @Input() markColor!: string | undefined; + @Output() colorChange = new EventEmitter<string | null>(); selectionColors: Record<string, string> = TextElement.selectionColors; toggleMarked(): void { - this.marked = !this.marked; - this.markedChange.emit(this.marked); + if (!this.markColor || this.markColor === 'none') { + return; + } + if (this.color && this.color === TextElement.selectionColors[this.markColor]) { + this.color = null; + } else { + this.color = TextElement.selectionColors[this.markColor]; + } + this.colorChange.emit(this.color); } } diff --git a/projects/player/src/app/components/elements/markables-container/markables-container.component.html b/projects/player/src/app/components/elements/markables-container/markables-container.component.html index 21c1f8aa8a117ebb6096948c4c9d990dc99a43c6..c93f99f76a784cd83313e7a7a4471430eeab4501 100644 --- a/projects/player/src/app/components/elements/markables-container/markables-container.component.html +++ b/projects/player/src/app/components/elements/markables-container/markables-container.component.html @@ -4,8 +4,9 @@ } @if (markable.word) { <aspect-markable-word [text]="markable.word" - [(marked)]="markable.marked" - (markedChange)="onMarkedChange()"> + [markColor]="selectedColor.value" + [(color)]="markable.color" + (colorChange)="onColorChange()"> </aspect-markable-word> } @if (markable.suffix) { @@ -13,4 +14,3 @@ } } - diff --git a/projects/player/src/app/components/elements/markables-container/markables-container.component.ts b/projects/player/src/app/components/elements/markables-container/markables-container.component.ts index f048d5e2e96ed034d293e8a8988737784ceae13f..1516f4cbbc55bb883ce4083350bfff2e3eae52c8 100644 --- a/projects/player/src/app/components/elements/markables-container/markables-container.component.ts +++ b/projects/player/src/app/components/elements/markables-container/markables-container.component.ts @@ -3,6 +3,7 @@ import { } from '@angular/core'; import { MarkableWordComponent } from 'player/src/app/components/elements/markable-word/markable-word.component'; import { Markable } from 'player/src/app/models/markable.interface'; +import { BehaviorSubject } from 'rxjs'; @Component({ selector: 'aspect-markables-container', @@ -14,10 +15,11 @@ import { Markable } from 'player/src/app/models/markable.interface'; styleUrl: './markables-container.component.scss' }) export class MarkablesContainerComponent { + @Input() selectedColor!: BehaviorSubject<string | undefined>; @Input() markables!: Markable[]; @Input() markablesChange: EventEmitter<void> = new EventEmitter<void>(); - onMarkedChange() { + onColorChange() { this.markablesChange.emit(); } } 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 ff8a0323ac103b9afed1a4b5dc73debcbb28fcfe..4bc413da37cb2063ece2938b49f38556f05fb76e 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 @@ -66,8 +66,7 @@ export class TextGroupElementComponent extends ElementGroupDirective implements this.getElementModelValue(), this.elementModel.type, { - markingMode: (this.elementModel as TextElement).markingMode, - color: 'yellow' + markingMode: (this.elementModel as TextElement).markingMode }), this.elementComponent, this.pageIndex); @@ -86,8 +85,7 @@ export class TextGroupElementComponent extends ElementGroupDirective implements value.value, this.elementModel.type, { - markingMode: (this.elementModel as TextElement).markingMode, - color: 'yellow' + markingMode: (this.elementModel as TextElement).markingMode }) }); } diff --git a/projects/player/src/app/models/markable.interface.ts b/projects/player/src/app/models/markable.interface.ts index 19ffad1c63aea5b387b8e597fe57d4ecc7c053b2..bf104d1a743a4b81a25a46bd43f672735e4dfbd0 100644 --- a/projects/player/src/app/models/markable.interface.ts +++ b/projects/player/src/app/models/markable.interface.ts @@ -9,5 +9,5 @@ export interface Markable { word: string; suffix: string; isActive: boolean; - marked: boolean; + color: string | null; } diff --git a/projects/player/src/app/services/element-model-element-code-mapping.service.ts b/projects/player/src/app/services/element-model-element-code-mapping.service.ts index f962396b44cf65a17c8934ce1b4952ffba35ddbb..12e1b5f0e8aaa95a51fe1f3870bb6f89ec00470b 100644 --- a/projects/player/src/app/services/element-model-element-code-mapping.service.ts +++ b/projects/player/src/app/services/element-model-element-code-mapping.service.ts @@ -100,7 +100,7 @@ export class ElementModelElementCodeMappingService { } if (options && options.markingMode !== 'none') { return ElementModelElementCodeMappingService - .getMarkedMarkables(elementModelValue as Markable[], options.color); + .getMarkedMarkables(elementModelValue as Markable[]); } return []; case 'radio': @@ -114,15 +114,15 @@ export class ElementModelElementCodeMappingService { } } - private static getMarkedMarkables(markables: Markable[], color: string): string[] { + private static getMarkedMarkables(markables: Markable[]): string[] { return markables - .filter((markable: Markable) => markable.marked) - .map((markable: Markable) => ElementModelElementCodeMappingService.mapToTextSelectionFormat(markable, color)); + .filter((markable: Markable) => !!markable.color) + .map((markable: Markable) => ElementModelElementCodeMappingService + .mapToTextSelectionFormat(markable, markable.color)); } - private static mapToTextSelectionFormat(markable: Markable, color: string): string { - const hexColor = TextElement.selectionColors[color]; - return `${markable.id}-${markable.id}-${hexColor}`; + private static mapToTextSelectionFormat(markable: Markable, color: string | null): string { + return `${markable.id}-${markable.id}-${color}`; } private getDragNDropValueObjectById(id: string): DragNDropValueObject | undefined {