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 d96a91168664e07d0a5a3bb0dfb1bab24fdaf701..663c7e22bb591e1f7883707519b185ae2ed2068e 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 @@ -8,27 +8,27 @@ import { TextElement } from 'common/models/elements/text/text'; template: ` <div class="marking-bar"> <aspect-text-marking-button *ngIf="elementModel.highlightableYellow" - [color]="selectionColors.yellow" - [selected]="selectedColor === selectionColors.yellow" - mode="mark" - (selectedChanged)="onSelectionChange($event)"> + [color]="selectionColors.yellow" + [isMarkingSelected]="selectedColor === selectionColors.yellow" + mode="mark" + (selectedMarkingChanged)="changeMarkingData($event)"> </aspect-text-marking-button> <aspect-text-marking-button *ngIf="elementModel.highlightableTurquoise" - [color]="selectionColors.turquoise" - [selected]="selectedColor === selectionColors.turquoise" - mode="mark" - (selectedChanged)="onSelectionChange($event)"> + [color]="selectionColors.turquoise" + [isMarkingSelected]="selectedColor === selectionColors.turquoise" + mode="mark" + (selectedMarkingChanged)="changeMarkingData($event)"> </aspect-text-marking-button> <aspect-text-marking-button *ngIf="elementModel.highlightableOrange" - [color]="selectionColors.orange" - [selected]="selectedColor === selectionColors.orange" - mode="mark" - (selectedChanged)="onSelectionChange($event)"> + [color]="selectionColors.orange" + [isMarkingSelected]="selectedColor === selectionColors.orange" + mode="mark" + (selectedMarkingChanged)="changeMarkingData($event)"> </aspect-text-marking-button> <aspect-text-marking-button [color]="selectionColors.delete" - [selected]="selectedColor === selectionColors.delete" - mode="delete" - (selectedChanged)="onSelectionChange($event)"> + [isMarkingSelected]="selectedColor === selectionColors.delete" + mode="delete" + (selectedMarkingChanged)="changeMarkingData($event)"> </aspect-text-marking-button> </div>`, styles: [ @@ -37,7 +37,7 @@ import { TextElement } from 'common/models/elements/text/text'; }) export class TextMarkingBarComponent { @Input() elementModel!: TextElement; - @Output() selectionChanged = new EventEmitter<{ + @Output() markingDataChanged = new EventEmitter<{ active: boolean, mode: 'mark' | 'delete', color: string, @@ -49,14 +49,14 @@ export class TextMarkingBarComponent { yellow: '#f9f871', turquoise: '#9de8eb', orange: '#ffa06a', delete: 'lightgrey' }; - onSelectionChange(selection: { selected: boolean, color: string, mode: 'mark' | 'delete' }): void { - this.selectedColor = selection.selected ? selection.color : 'none'; - this.selectionChanged + changeMarkingData(selection: { isSelected: boolean, color: string, mode: 'mark' | 'delete' }): void { + this.selectedColor = selection.isSelected ? selection.color : 'none'; + this.markingDataChanged .emit({ - active: selection.selected, + active: selection.isSelected, mode: selection.mode, color: selection.color, - colorName: selection.selected ? + colorName: selection.isSelected ? Object.keys(this.selectionColors).find(key => this.selectionColors[key] === selection.color) : 'none' }); } diff --git a/projects/common/components/text/text-marking-bar/text-marking-button.component.ts b/projects/common/components/text/text-marking-bar/text-marking-button.component.ts index 30150c1020e6a31ebd820dcd99035022a21aa540..ff457cae6f8e45594208438428b2f84fca86accc 100644 --- a/projects/common/components/text/text-marking-bar/text-marking-button.component.ts +++ b/projects/common/components/text/text-marking-bar/text-marking-button.component.ts @@ -7,10 +7,10 @@ import { template: ` <button type="button" class="marking-button" - [style.border-color]="selected ? 'black' : color" + [style.border-color]="isMarkingSelected ? 'black' : color" mat-mini-fab [style.background-color]="color" - (pointerdown)="emitSelectedChanged()"> + (pointerdown)="selectMarking()"> <mat-icon *ngIf="mode === 'mark'" class="marking-icon">border_color </mat-icon> @@ -25,18 +25,18 @@ import { ] }) export class TextMarkingButtonComponent { - @Input() selected!: boolean; + @Input() isMarkingSelected!: boolean; @Input() color!: string; @Input() mode!: 'mark' | 'delete'; @Input() element!: HTMLElement; - @Output() selectedChanged = new EventEmitter<{ - selected: boolean, + @Output() selectedMarkingChanged = new EventEmitter<{ + isSelected: boolean, mode: 'mark' | 'delete', color: string, }>(); - emitSelectedChanged(): void { - this.selected = !this.selected; - this.selectedChanged.emit({ selected: this.selected, mode: this.mode, color: this.color }); + selectMarking(): void { + this.isMarkingSelected = !this.isMarkingSelected; + this.selectedMarkingChanged.emit({ isSelected: this.isMarkingSelected, mode: this.mode, color: this.color }); } } diff --git a/projects/common/components/text/text.component.ts b/projects/common/components/text/text.component.ts index 41f839ecc9cbe351e83f457a252f3b4ce41ff1e8..13523a54d37b752835ad0554b40fbf7a906e66c0 100644 --- a/projects/common/components/text/text.component.ts +++ b/projects/common/components/text/text.component.ts @@ -10,30 +10,30 @@ import { ValueChangeElement } from 'common/models/elements/element'; template: ` <div [style.width.%]="100" [style.height.%]="100"> - <aspect-text-marking-bar - *ngIf="elementModel.highlightableYellow || + <aspect-text-marking-bar + *ngIf="elementModel.highlightableYellow || elementModel.highlightableTurquoise || elementModel.highlightableOrange" - [elementModel]="elementModel" - (selectionChanged)="onSelectionChanged($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'" - [style.background-color]="elementModel.styling.backgroundColor" - [style.color]="elementModel.styling.fontColor" - [style.font-family]="elementModel.styling.font" - [style.font-size.px]="elementModel.styling.fontSize" - [style.line-height.%]="elementModel.styling.lineHeight" - [style.font-weight]="elementModel.styling.bold ? 'bold' : ''" - [style.font-style]="elementModel.styling.italic ? 'italic' : ''" - [style.text-decoration]="elementModel.styling.underline ? 'underline' : ''" - [style.column-count]="elementModel.columnCount" - [innerHTML]="savedText || elementModel.text | safeResourceHTML" - (pointerdown)="emitStartSelection($event)"> - </div> + [elementModel]="elementModel" + (markingDataChanged)="selectedColor=$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'" + [style.background-color]="elementModel.styling.backgroundColor" + [style.color]="elementModel.styling.fontColor" + [style.font-family]="elementModel.styling.font" + [style.font-size.px]="elementModel.styling.fontSize" + [style.line-height.%]="elementModel.styling.lineHeight" + [style.font-weight]="elementModel.styling.bold ? 'bold' : ''" + [style.font-style]="elementModel.styling.italic ? 'italic' : ''" + [style.text-decoration]="elementModel.styling.underline ? 'underline' : ''" + [style.column-count]="elementModel.columnCount" + [innerHTML]="savedText || elementModel.text | safeResourceHTML" + (pointerdown)="startTextSelection($event)"> + </div> </div> `, styles: [ @@ -56,8 +56,8 @@ export class TextComponent extends ElementComponent { @Input() elementModel!: TextElement; @Input() savedText!: string; @Output() elementValueChanged = new EventEmitter<ValueChangeElement>(); - @Output() startSelection = new EventEmitter<PointerEvent>(); - @Output() applySelection = new EventEmitter<{ + @Output() textSelectionStart = new EventEmitter<PointerEvent>(); + @Output() markingDataChanged = new EventEmitter<{ active: boolean, mode: 'mark' | 'delete', color: string, @@ -68,21 +68,11 @@ export class TextComponent extends ElementComponent { @ViewChild('textContainerRef') textContainerRef!: ElementRef; - emitStartSelection(event: PointerEvent): void { + startTextSelection(event: PointerEvent): void { if (this.elementModel.highlightableYellow || this.elementModel.highlightableTurquoise || this.elementModel.highlightableOrange) { - this.startSelection.emit(event); + this.textSelectionStart.emit(event); } } - - onSelectionChanged(selection: { - active: boolean, - mode: 'mark' | 'delete', - color: string, - colorName: string | undefined - }): void { - this.selectedColor = selection.colorName; - this.applySelection.emit(selection); - } } 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 07946d484cf08e3fd24404e764d9f897cf08c2ca..d4d6b37bacdcdfec46fa7eb104c97430383ba7f4 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 @@ -2,8 +2,8 @@ #elementComponent [elementModel]="elementModel | cast: TextElement" [savedText]="initialValue" - (applySelection)="applySelection($event, elementComponent)" - (startSelection)="startSelection($event, elementComponent)" + (markingDataChanged)="applyMarkingData($event, elementComponent)" + (textSelectionStart)="startTextSelection($event, elementComponent)" (elementValueChanged)="unitStateService.changeElementCodeValue($event)"> </aspect-text> <aspect-floating-marking-bar @@ -12,5 +12,5 @@ [textComponentRect]="textComponentRect" [textComponentContainerScrollTop]="textComponentContainerScrollTop" [position]="markingBarPosition" - (applySelection)="applySelectionToText($event.mode, $event.color, elementComponent)"> + (markingDataChanged)="applyMarkingDataToText($event.mode, $event.color, elementComponent)"> </aspect-floating-marking-bar> 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 81a4b1adc3a1694473aaa13fb1ccd149fa109e6b..dc55959f411a505048bb5ae2954ae8349af45ef0 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 @@ -54,37 +54,37 @@ export class TextGroupElementComponent extends ElementGroupDirective implements this.pageIndex); } - applySelection( + applyMarkingData( selection: { active: boolean; mode: 'mark' | 'delete'; color: string; colorName: string | undefined }, elementComponent: TextComponent ): void { if (selection.active) { this.selectedColor = selection.color; this.selectedMode = selection.mode; - this.applySelectionToText(selection.mode, selection.color, elementComponent); + this.applyMarkingDataToText(selection.mode, selection.color, elementComponent); } else { this.selectedColor = null; this.selectedMode = null; } } - startSelection(pointerDown: PointerEvent, elementComponent: TextComponent): void { + startTextSelection(pointerDown: PointerEvent, elementComponent: TextComponent): void { this.isMarkingBarOpen = false; this.nativeEventService.pointerUp .pipe(takeUntil(this.ngUnsubscribe), first()) .subscribe((pointerUp: PointerEvent) => { - this.stopSelection( - this.getClientPointFromEvent(pointerUp), + this.stopTextSelection( + { clientX: pointerUp.clientX, clientY: pointerUp.clientY }, pointerUp.ctrlKey, - this.getClientPointFromEvent(pointerDown), + { clientX: pointerDown.clientX, clientY: pointerDown.clientY }, elementComponent ); }); } - applySelectionToText(mode: 'mark' | 'delete', color: string, elementComponent: TextComponent): void { + applyMarkingDataToText(mode: 'mark' | 'delete', color: string, elementComponent: TextComponent): void { TextMarkingService - .applySelection( + .applyMarkingDataToText( mode, color, elementComponent @@ -92,30 +92,25 @@ export class TextGroupElementComponent extends ElementGroupDirective implements this.isMarkingBarOpen = false; } - private stopSelection( - mouseUp: { clientX: number, clientY: number }, + private stopTextSelection( + pointerUpPoint: { clientX: number, clientY: number }, ctrlKey: boolean, - downPosition: { clientX: number, clientY: number }, + pointerDownPoint: { clientX: number, clientY: number }, elementComponent: TextComponent ) { const selection = window.getSelection(); if (selection && TextMarkingService.isSelectionValid(selection) && selection.rangeCount > 0) { - if (!TextMarkingService.isRangeInside(selection.getRangeAt(0), elementComponent.textContainerRef.nativeElement) || - (ctrlKey)) { + if (!TextMarkingService + .isRangeInside(selection.getRangeAt(0), elementComponent.textContainerRef.nativeElement) || (ctrlKey)) { selection.removeAllRanges(); } else if (this.selectedMode && this.selectedColor) { - this.applySelectionToText(this.selectedMode, this.selectedColor, elementComponent); + this.applyMarkingDataToText(this.selectedMode, this.selectedColor, elementComponent); } else if (!this.isMarkingBarOpen) { - this.openMarkingBar(mouseUp, downPosition, elementComponent); + this.openMarkingBar(pointerUpPoint, pointerDownPoint, elementComponent); } } } - private getClientPointFromEvent = (event: PointerEvent): { clientX: number, clientY: number } => ({ - clientX: event.clientX, - clientY: event.clientY - }); - private openMarkingBar( mouseUp: { clientX: number, clientY: number }, downPosition: { clientX: number, clientY: number }, diff --git a/projects/player/src/app/components/floating-marking-bar/floating-marking-bar.component.html b/projects/player/src/app/components/floating-marking-bar/floating-marking-bar.component.html index aeeac4bc1960c497ccd56aa2409f0a02cabeb6e7..f373bc45e2c96d2a031c0784b3b17ec386c002e6 100644 --- a/projects/player/src/app/components/floating-marking-bar/floating-marking-bar.component.html +++ b/projects/player/src/app/components/floating-marking-bar/floating-marking-bar.component.html @@ -11,7 +11,7 @@ cdkDrag> <aspect-text-marking-bar [elementModel]="elementModel" - (selectionChanged)="applySelection.emit($event)"> + (markingDataChanged)="markingDataChanged.emit($event)"> </aspect-text-marking-bar> </div> </ng-template> diff --git a/projects/player/src/app/components/floating-marking-bar/floating-marking-bar.component.ts b/projects/player/src/app/components/floating-marking-bar/floating-marking-bar.component.ts index 1da04b987490e59a95c2a1ac715e47784faf71bb..d2e5f8983ecd752a7f696739fb0e1796510c6d1e 100644 --- a/projects/player/src/app/components/floating-marking-bar/floating-marking-bar.component.ts +++ b/projects/player/src/app/components/floating-marking-bar/floating-marking-bar.component.ts @@ -18,7 +18,7 @@ export class FloatingMarkingBarComponent implements OnInit, OnChanges { @Input() textComponentRect!: DOMRect; @Input() textComponentContainerScrollTop!: number; - @Output() applySelection = new EventEmitter<{ + @Output() markingDataChanged = new EventEmitter<{ active: boolean, mode: 'mark' | 'delete', color: string 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 53c88e362018d21148b4f247962cf191ac1dd953..9091677130cbbc145540ec274e8b13a779982459 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 @@ -30,7 +30,8 @@ export class ElementModelElementCodeMappingService { (elementModel as InputElement).value; case 'text': return (elementCodeValue !== undefined) ? - TextMarkingService.restoreMarkings(elementCodeValue as string[], (elementModel as TextElement).text) : + TextMarkingService + .restoreMarkedTextIndices(elementCodeValue as string[], (elementModel as TextElement).text) : (elementModel as TextElement).text; case 'audio': return elementCodeValue !== undefined ? @@ -61,7 +62,7 @@ export class ElementModelElementCodeMappingService { case 'drop-list-simple': return (elementModelValue as DragNDropValueObject[]).map(object => object.id); case 'text': - return TextMarkingService.getMarkingData(elementModelValue as string); + return TextMarkingService.getMarkedTextIndices(elementModelValue as string); case 'radio': case 'radio-group-images': case 'dropdown': diff --git a/projects/player/src/app/services/text-marking.service.spec.ts b/projects/player/src/app/services/text-marking.service.spec.ts index 3dce83180424da640de664250d1cb5b150124290..641c75187487321909abc1ed24f6c93a8a2fc4eb 100644 --- a/projects/player/src/app/services/text-marking.service.spec.ts +++ b/projects/player/src/app/services/text-marking.service.spec.ts @@ -16,7 +16,7 @@ describe('TextMarkingService', () => { const text = 'Lorem <aspect-marked style="background-color: rgb(249, 248, 113);">ipsum</aspect-marked> dolor sit amet'; const expectedArray = ['6-11-#f9f871']; - expect(TextMarkingService.getMarkingData(text)).toEqual(expectedArray); + expect(TextMarkingService.getMarkedTextIndices(text)).toEqual(expectedArray); }); it('should mark a text with given selections ', () => { @@ -24,7 +24,7 @@ describe('TextMarkingService', () => { const expectedText = 'Lorem <aspect-marked style="background-color: rgb(249, 248, 113);">ipsum</aspect-marked> dolor sit amet'; const markings = ['6-11-#f9f871']; - expect(TextMarkingService.restoreMarkings(markings, text)).toEqual(expectedText); + expect(TextMarkingService.restoreMarkedTextIndices(markings, text)).toEqual(expectedText); }); }); diff --git a/projects/player/src/app/services/text-marking.service.ts b/projects/player/src/app/services/text-marking.service.ts index 453f176f3e1f656a94efedff8c7e4791ad392650..7ffc81a616d52b595c87aeb5960597705a8379f3 100644 --- a/projects/player/src/app/services/text-marking.service.ts +++ b/projects/player/src/app/services/text-marking.service.ts @@ -10,7 +10,7 @@ export class TextMarkingService { private static readonly MARKING_TAG = 'ASPECT-MARKED'; - static applySelection( + static applyMarkingDataToText( mode: 'mark' | 'delete', color: string, textComponent: TextComponent @@ -23,7 +23,7 @@ export class TextMarkingService { TextMarkingService.applyRange(range, selection, mode === 'delete', color); textComponent.elementValueChanged.emit({ id: textComponent.elementModel.id, - value: TextMarkingService.getMarkingData(element.innerHTML) + value: TextMarkingService.getMarkedTextIndices(element.innerHTML) }); textComponent.savedText = element.innerHTML; } else { @@ -40,7 +40,7 @@ export class TextMarkingService { TextMarkingService.isDescendantOf(range.endContainer, element)); } - static getMarkingData = (htmlText: string): string[] => { + static getMarkedTextIndices = (htmlText: string): string[] => { const markingStartPattern = new RegExp(`<${TextMarkingService.MARKING_TAG.toLowerCase()} [a-z]+="[\\w\\d()-;:, #]+">`); const markingClosingTag = `</${TextMarkingService.MARKING_TAG.toLowerCase()}>`; @@ -66,7 +66,7 @@ export class TextMarkingService { return markCollection; }; - static restoreMarkings(markings: string[], htmlText: string): string { + static restoreMarkedTextIndices(markings: string[], htmlText: string): string { let newHtmlText = htmlText; if (markings.length) { const markCollectionReversed = [...markings].reverse();