app.views.SidebarHover = class SidebarHover extends app.View {
  static itemClass = "_list-hover";

  static events = {
    focus: "onFocus",
    blur: "onBlur",
    mouseover: "onMouseover",
    mouseout: "onMouseout",
    scroll: "onScroll",
    click: "onClick",
  };

  static routes = { after: "onRoute" };

  show(el) {
    if (el !== this.cursor) {
      this.hide();
      if (this.isTarget(el) && this.isTruncated(el.lastElementChild || el)) {
        this.cursor = el;
        this.clone = this.makeClone(this.cursor);
        $.append(document.body, this.clone);
        if (this.offsetTop == null) {
          this.offsetTop = this.el.offsetTop;
        }
        this.position();
      }
    }
  }

  hide() {
    if (this.cursor) {
      $.remove(this.clone);
      this.cursor = this.clone = null;
    }
  }

  position() {
    if (this.cursor) {
      const rect = $.rect(this.cursor);
      if (rect.top >= this.offsetTop) {
        this.clone.style.top = rect.top + "px";
        this.clone.style.left = rect.left + "px";
      } else {
        this.hide();
      }
    }
  }

  makeClone(el) {
    const clone = el.cloneNode(true);
    clone.classList.add("clone");
    return clone;
  }

  isTarget(el) {
    return el.classList?.contains(this.constructor.itemClass);
  }

  isSelected(el) {
    return el.classList.contains("active");
  }

  isTruncated(el) {
    return el.scrollWidth > el.offsetWidth;
  }

  onFocus(event) {
    this.focusTime = Date.now();
    this.show(event.target);
  }

  onBlur() {
    this.hide();
  }

  onMouseover(event) {
    if (
      this.isTarget(event.target) &&
      !this.isSelected(event.target) &&
      this.mouseActivated()
    ) {
      this.show(event.target);
    }
  }

  onMouseout(event) {
    if (this.isTarget(event.target) && this.mouseActivated()) {
      this.hide();
    }
  }

  mouseActivated() {
    // Skip mouse events caused by focus events scrolling the sidebar.
    return !this.focusTime || Date.now() - this.focusTime > 500;
  }

  onScroll() {
    this.position();
  }

  onClick(event) {
    if (event.target === this.clone) {
      $.click(this.cursor);
    }
  }

  onRoute() {
    this.hide();
  }
};