From 585c42247d8976daa9d9e9b15c589d407fb5764f Mon Sep 17 00:00:00 2001 From: jojohoch <joachim.hoch@iqb.hu-berlin.de> Date: Thu, 11 Nov 2021 13:01:34 +0100 Subject: [PATCH] [player] Move code from ElementContainerComponent to MarkingService The MarkingService now takes care of the selection and its validation. The text component sends its change via elementValueChanged. --- .../element-components/text.component.ts | 2 ++ .../element-container.component.ts | 32 ++--------------- .../src/app/services/marking.service.ts | 34 ++++++++++++++++++- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/projects/common/element-components/text.component.ts b/projects/common/element-components/text.component.ts index c7b229a88..e0484ea4f 100644 --- a/projects/common/element-components/text.component.ts +++ b/projects/common/element-components/text.component.ts @@ -3,6 +3,7 @@ import { } from '@angular/core'; import { ElementComponent } from '../element-component.directive'; import { TextElement } from '../models/text-element'; +import { ValueChangeElement } from '../models/uI-element'; @Component({ selector: 'app-text', @@ -62,6 +63,7 @@ import { TextElement } from '../models/text-element'; }) export class TextComponent extends ElementComponent { elementModel!: TextElement; + @Output() elementValueChanged = new EventEmitter<ValueChangeElement>(); @Output() startSelection = new EventEmitter<MouseEvent>(); @Output() applySelection = new EventEmitter <{ mode: 'mark' | 'underline' | 'delete', diff --git a/projects/player/src/app/components/element-container/element-container.component.ts b/projects/player/src/app/components/element-container/element-container.component.ts index 4d9a7a746..76a10e817 100644 --- a/projects/player/src/app/components/element-container/element-container.component.ts +++ b/projects/player/src/app/components/element-container/element-container.component.ts @@ -30,6 +30,7 @@ import { ImageElement } from '../../../../../common/models/image-element'; import { VeronaPostService } from '../../services/verona-post.service'; import { MediaPlayerElementComponent } from '../../../../../common/media-player-element-component.directive'; import { MediaPlayerService } from '../../services/media-player.service'; +import { TextComponent } from '../../../../../common/element-components/text.component'; @Component({ selector: 'app-element-container', @@ -122,7 +123,8 @@ export class ElementContainerComponent implements OnInit { .pipe(takeUntil(this.ngUnsubscribe)) .subscribe((selection: { mode: 'mark' | 'underline' | 'delete', color: string; element: HTMLElement; clear: boolean }) => { - this.applySelection(selection.mode, selection.color, selection.element); + this.markingService + .applySelection(selection.mode, selection.color, selection.element, elementComponent as TextComponent); }); } @@ -251,34 +253,6 @@ export class ElementContainerComponent implements OnInit { }); } - private applySelection(mode: 'mark' | 'underline' | 'delete', color: string, element: HTMLElement): void { - const selection = window.getSelection(); - if (selection && selection.rangeCount > 0) { - const range = selection.getRangeAt(0); - if (this.isDescendantOf(range.startContainer, element) && - this.isDescendantOf(range.endContainer, element)) { - const markMode = mode === 'mark' ? 'marked' : 'underlined'; - this.markingService.applySelection(range, selection, mode === 'delete', color, markMode); - this.unitStateService.changeElementValue({ - id: this.elementModel.id, - values: [this.elementModel.text as string, element.innerHTML] - }); - this.elementModel.text = element.innerHTML; - } - selection.removeAllRanges(); - } // nothing to do! - } - - private isDescendantOf(node: Node | null, element: HTMLElement): boolean { - if (!node || node === document) { - return false; - } - if (node.parentElement === element) { - return true; - } - return this.isDescendantOf(node.parentNode, element); - } - ngOnDestroy(): void { this.ngUnsubscribe.next(); this.ngUnsubscribe.complete(); diff --git a/projects/player/src/app/services/marking.service.ts b/projects/player/src/app/services/marking.service.ts index bd75193e6..1bdeb46b8 100644 --- a/projects/player/src/app/services/marking.service.ts +++ b/projects/player/src/app/services/marking.service.ts @@ -1,4 +1,5 @@ import { Injectable } from '@angular/core'; +import { TextComponent } from '../../../../common/element-components/text.component'; @Injectable({ providedIn: 'root' @@ -7,7 +8,38 @@ export class MarkingService { private static readonly MARKING_TAG = 'MARKED'; private static readonly UNDERLINE_TAG = 'UNDERLINED'; - applySelection( + applySelection(mode: 'mark' | 'underline' | 'delete', + color: string, + element: HTMLElement, + textComponent: TextComponent): void { + const selection = window.getSelection(); + if (selection && selection.rangeCount > 0) { + const range = selection.getRangeAt(0); + if (this.isDescendantOf(range.startContainer, element) && + this.isDescendantOf(range.endContainer, element)) { + const markMode = mode === 'mark' ? 'marked' : 'underlined'; + this.applyRange(range, selection, mode === 'delete', color, markMode); + textComponent.elementValueChanged.emit({ + id: textComponent.elementModel.id, + values: [textComponent.elementModel.text as string, element.innerHTML] + }); + textComponent.elementModel.text = element.innerHTML; + } + selection.removeAllRanges(); + } // nothing to do! + } + + private isDescendantOf(node: Node | null, element: HTMLElement): boolean { + if (!node || node === document) { + return false; + } + if (node.parentElement === element) { + return true; + } + return this.isDescendantOf(node.parentNode, element); + } + + private applyRange( range: Range, selection: Selection, clear: boolean, color: string, markMode: 'marked' | 'underlined' ): void { if (range.startContainer === range.endContainer) { -- GitLab