Skip to content
Snippets Groups Projects
markable-support.ts 4.52 KiB
Newer Older
  • Learn to ignore specific revisions
  • import { ApplicationRef, createComponent, Renderer2 } from '@angular/core';
    import { TextComponent } from 'common/components/text/text.component';
    import { Markable, MarkablesContainer } from 'player/src/app/models/markable.interface';
    
    jojohoch's avatar
    jojohoch committed
    import {
      MarkablesContainerComponent
    } from 'player/src/app/components/elements/markables-container/markables-container.component';
    
    
    export class MarkableSupport {
      private renderer: Renderer2;
      private applicationRef: ApplicationRef;
    
    jojohoch's avatar
    jojohoch committed
      constructor(
    
        renderer: Renderer2,
        applicationRef: ApplicationRef
      ) {
        this.renderer = renderer;
        this.applicationRef = applicationRef;
      }
    
      createMarkables(savedMarks: string[], elementComponent: TextComponent): void {
        const nodes = MarkableSupport.findNodes(elementComponent.textContainerRef.nativeElement.childNodes);
        const markablesContainers = MarkableSupport.getMarkablesContainers(nodes, savedMarks);
    
        this.markables = markablesContainers
    
    jojohoch's avatar
    jojohoch committed
          .flatMap((markablesContainer: MarkablesContainer) => markablesContainer.markables);
    
        this.createComponents(markablesContainers, elementComponent);
    
      private createComponents(markablesContainers: MarkablesContainer[], elementComponent: TextComponent): void {
    
    jojohoch's avatar
    jojohoch committed
        markablesContainers.forEach((markablesContainer: MarkablesContainer) => {
          const node = markablesContainer.node;
          const markableContainerElement = this.renderer.createElement('markable-container');
          node.parentNode?.replaceChild(markableContainerElement, node);
          const environmentInjector = this.applicationRef.injector;
          const componentRef = createComponent(MarkablesContainerComponent, {
            environmentInjector,
            hostElement: markableContainerElement
          });
          componentRef.instance.markables = markablesContainer.markables;
    
          componentRef.instance.selectedColor = elementComponent.selectedColor;
    
    jojohoch's avatar
    jojohoch committed
          componentRef.instance.markablesChange.subscribe(() => {
    
            elementComponent.elementValueChanged.emit(
    
    jojohoch's avatar
    jojohoch committed
              {
    
                id: elementComponent.elementModel.id,
    
    jojohoch's avatar
    jojohoch committed
              }
            );
          });
    
    jojohoch's avatar
    jojohoch committed
          this.applicationRef.attachView(componentRef.hostView);
        });
      }
    
    
      private static getMarkablesContainers(nodes: Node[], savedMarks: string[]): MarkablesContainer[] {
    
    jojohoch's avatar
    jojohoch committed
        const markablesContainers: MarkablesContainer[] = [];
        let wordsCount = 0;
        nodes.forEach((node: Node) => {
    
          const currentNodes = MarkableSupport.getMarkablesContainer(node, wordsCount, savedMarks);
    
    jojohoch's avatar
    jojohoch committed
          wordsCount += currentNodes.markables.length;
          markablesContainers.push(currentNodes);
        });
        return markablesContainers;
      }
    
    
      private static getMarkablesContainer(node: Node, wordsCount: number, savedMarks: string[]): MarkablesContainer {
    
    jojohoch's avatar
    jojohoch committed
        return {
          node: node,
    
          markables: MarkableSupport.getMarkables(node.textContent || '', wordsCount, savedMarks)
    
      private static getMarkables(text: string, startIndex: number, savedMarks: string[]): Markable[] {
    
    jojohoch's avatar
    jojohoch committed
        const markables: Markable[] = [];
    
    jojohoch's avatar
    jojohoch committed
        const wordsWithWhitespace = text?.match(/(\s*\S+\s*)|(s+\S*\s*)|(s*\S*\s+)/g);
    
    jojohoch's avatar
    jojohoch committed
        wordsWithWhitespace?.forEach((wordWithWhitespace: string, index: number) => {
    
    jojohoch's avatar
    jojohoch committed
          const prefix = wordWithWhitespace.match(/\s+(?=[^,]*\S*)/);
          const word = wordWithWhitespace.match(/\S+/);
          const suffix = wordWithWhitespace.match(/[^\S]\s*$/);
    
    jojohoch's avatar
    jojohoch committed
          const id = startIndex + index;
    
          const markedWord = MarkableSupport.getColorValueById(id, savedMarks);
    
    jojohoch's avatar
    jojohoch committed
          markables.push(
            {
    
    jojohoch's avatar
    jojohoch committed
              id: id,
    
    jojohoch's avatar
    jojohoch committed
              prefix: prefix ? prefix[0] : '',
              word: word ? word[0] : '',
    
    jojohoch's avatar
    jojohoch committed
              suffix: suffix ? suffix[0] : '',
    
              isActive: !!(word && word[0].length),
    
              color: markedWord
    
    jojohoch's avatar
    jojohoch committed
            }
          );
        });
        return markables;
      }
    
    
      private static findNodes(childList: Node[] | NodeListOf<ChildNode>): Node[] {
    
    jojohoch's avatar
    jojohoch committed
        const nodes: Node[] = [];
        childList.forEach((node: Node) => {
          if (node.nodeType === Node.TEXT_NODE && !nodes.includes(node)) {
            nodes.push(node);
          }
          if (node.nodeType === Node.ELEMENT_NODE) {
            if (node.childNodes.length) {
    
              nodes.push(...MarkableSupport.findNodes(node.childNodes));
    
    jojohoch's avatar
    jojohoch committed
            } else if (!nodes.includes(node)) {
              nodes.push(node);
            }
          }
        });
        return nodes;
      }
    
      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;
    
    jojohoch's avatar
    jojohoch committed
      }