110 lines · 2.1 KB · JavaScript
RawDownload
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();  }};