Untitled

 avatar
unknown
typescript
a year ago
5.4 kB
6
Indexable
import { ElementRef, Injectable, Renderer2, RendererFactory2 } from '@angular/core';
import { fromEvent } from 'rxjs';
import { debounceTime } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class ResponsivityService {
  private initState: boolean = false;
  private renderer: Renderer2;
  originalElement: ElementRef;
  children: ElementRef[] = [];
  savedChildren: ElementRef[] = [];
  savedBurgerChildren: ElementRef[] = [];
  noResponsiveElements: ElementRef[] = [];
  burgerChildren: ElementRef[] = [];
  burgerElement: ElementRef = null;
  burgerWidth: number = 0;
  burgerHidden: boolean = true;
  reserveConstant: number = 15;

  constructor(rendererFactory: RendererFactory2) {
    this.renderer = rendererFactory.createRenderer(null, null);
  }

  initResponsivity(headerElement: ElementRef, children: ElementRef[], burgerChildren: ElementRef[], noResponsiveElements: ElementRef[], burgerElement: ElementRef): void {
    if (!this.initState) {
      this.settingInitialValues(headerElement, children, burgerChildren, noResponsiveElements, burgerElement);
      this.saveChildrenReferences();
      this.checkElementVisibility();
      this.checkWindowResize();
      this.initState = true;
    }
  }

  checkElementVisibility(): void {
    this.showAllChildren();
    this.hideAllBurgerChildren();
    const childrenToHide = this.getChildrenToHide();
    this.hideChildren(childrenToHide);
    this.showBurgerChildren(childrenToHide);
  }

  private settingInitialValues(headerElement: ElementRef, children: ElementRef[], burgerChildren: ElementRef[], noResponsiveElements: ElementRef[], burgerElement: ElementRef): void {
    this.originalElement = headerElement;
    this.children = children;
    this.burgerChildren = burgerChildren;
    this.noResponsiveElements = noResponsiveElements;
    this.burgerElement = burgerElement;
  }

  private checkWindowResize(): void {
    fromEvent(window, 'resize').pipe(
      debounceTime(300)
    ).subscribe((event: Event) => {
      this.checkElementVisibility();
    });
  }

  private cloneElement(element: ElementRef): ElementRef {
    const clonedElement = element.nativeElement.cloneNode(true);
    return new ElementRef(clonedElement);
  }

  private saveChildrenReferences(): void {
    this.children.forEach((child: ElementRef) => {
      this.savedChildren.push(this.cloneElement(child));
    });
    this.burgerChildren.forEach((child: ElementRef) => {
      this.savedBurgerChildren.push(this.cloneElement(child));
    });
  }

  private getParentWidth(): number {
    this.burgerWidth = this.burgerElement.nativeElement.offsetWidth;
    let noResponsiveChildrenWidth = 0;
    this.noResponsiveElements.forEach((noResponsiveElement: ElementRef) => {
      noResponsiveChildrenWidth += noResponsiveElement.nativeElement.offsetWidth;
    });
    return this.originalElement.nativeElement.getBoundingClientRect().width - noResponsiveChildrenWidth - this.burgerWidth - this.reserveConstant;
  }

  private getChildrenToHide(): ElementRef[] {
    const elementsToHide = [];
    const parentWidth = this.getParentWidth();
    let totalChildrenWidth = 0;

    for (let i = 0; i < this.children.length; i++) {
      const child = this.children[i];
      totalChildrenWidth += child.nativeElement.offsetWidth;
      if (totalChildrenWidth > parentWidth) {
        elementsToHide.push(child.nativeElement.nodeName.toLowerCase());
      }
    }
    return elementsToHide;
  }

  private hideChildren(elementsToHide: ElementRef[]): void {
    if (elementsToHide.length > 0) {
      elementsToHide.forEach(elementId => {
        const element = this.children.find(child => child.nativeElement.nodeName.toLowerCase() === elementId);
        if (element) {
          element.nativeElement.style.display = 'none';
        }
      });
      this.setVisibilityOfBurger(true);
    } else {
      this.setVisibilityOfBurger(false);
    }
  }

  private showAllChildren(): void {
    this.children.forEach((element: ElementRef) => {
      const savedElement = this.savedChildren.find(child => child.nativeElement.nodeName.toLowerCase() === element.nativeElement.nodeName.toLowerCase());
      if (element) {
        element.nativeElement.style.display = savedElement.nativeElement.style.display;
      }
    });
  }

  private hideAllBurgerChildren(): void {
    this.burgerChildren.forEach((element: ElementRef) => {
      if (element) {
        element.nativeElement.style.display = 'none';
      }
    });
  }

  private showBurgerChildren(elementsToShow: ElementRef[]): void {
    if (elementsToShow.length > 0) {
      elementsToShow.forEach(elementId => {
        const element = this.burgerChildren.find(child => child.nativeElement.nodeName.toLowerCase() === elementId);
        const savedElement = this.savedBurgerChildren.find(child => child.nativeElement.nodeName.toLowerCase() === elementId);
        if (element) {
          element.nativeElement.style.display = savedElement.nativeElement.style.display;
        }
      });
    }
  }

  private setVisibilityOfBurger(show: boolean): void {
    if (show) {
      this.burgerElement.nativeElement.style.setProperty('display', 'flex', 'important');
      this.burgerHidden = false;
    } else {
      this.burgerElement.nativeElement.style.setProperty('display', 'none', 'important');
      this.burgerHidden = true;
    }
  }
}
Editor is loading...
Leave a Comment