185 lines · 4.3 KB · JavaScript
RawDownload
app.views.ListFocus = class ListFocus extends app.View {  static activeClass = "focus";   static events = { click: "onClick" };   static shortcuts = {    up: "onUp",    down: "onDown",    left: "onLeft",    enter: "onEnter",    superEnter: "onSuperEnter",    escape: "blur",  };   constructor(el) {    super(el);    this.focusOnNextFrame = (el) => requestAnimationFrame(() => this.focus(el));  }   focus(el, options) {    if (options == null) {      options = {};    }    if (el && !el.classList.contains(this.constructor.activeClass)) {      this.blur();      el.classList.add(this.constructor.activeClass);      if (options.silent !== true) {        $.trigger(el, "focus");      }    }  }   blur() {    let cursor;    if ((cursor = this.getCursor())) {      cursor.classList.remove(this.constructor.activeClass);      $.trigger(cursor, "blur");    }  }   getCursor() {    return (      this.findByClass(this.constructor.activeClass) ||      this.findByClass(app.views.ListSelect.activeClass)    );  }   findNext(cursor) {    let next;    if ((next = cursor.nextSibling)) {      if (next.tagName === "A") {        return next;      } else if (next.tagName === "SPAN") {        // pagination link        $.click(next);        return this.findNext(cursor);      } else if (next.tagName === "DIV") {        // sub-list        if (cursor.className.includes(" open")) {          return this.findFirst(next) || this.findNext(next);        } else {          return this.findNext(next);        }      } else if (next.tagName === "H6") {        // title        return this.findNext(next);      }    } else if (cursor.parentNode !== this.el) {      return this.findNext(cursor.parentNode);    }  }   findFirst(cursor) {    let first;    if (!(first = cursor.firstChild)) {      return;    }     if (first.tagName === "A") {      return first;    } else if (first.tagName === "SPAN") {      // pagination link      $.click(first);      return this.findFirst(cursor);    }  }   findPrev(cursor) {    let prev;    if ((prev = cursor.previousSibling)) {      if (prev.tagName === "A") {        return prev;      } else if (prev.tagName === "SPAN") {        // pagination link        $.click(prev);        return this.findPrev(cursor);      } else if (prev.tagName === "DIV") {        // sub-list        if (prev.previousSibling.className.includes("open")) {          return this.findLast(prev) || this.findPrev(prev);        } else {          return this.findPrev(prev);        }      } else if (prev.tagName === "H6") {        // title        return this.findPrev(prev);      }    } else if (cursor.parentNode !== this.el) {      return this.findPrev(cursor.parentNode);    }  }   findLast(cursor) {    let last;    if (!(last = cursor.lastChild)) {      return;    }     if (last.tagName === "A") {      return last;    } else if (last.tagName === "SPAN" || last.tagName === "H6") {      // pagination link or title      return this.findPrev(last);    } else if (last.tagName === "DIV") {      // sub-list      return this.findLast(last);    }  }   onDown() {    let cursor;    if ((cursor = this.getCursor())) {      this.focusOnNextFrame(this.findNext(cursor));    } else {      this.focusOnNextFrame(this.findByTag("a"));    }  }   onUp() {    let cursor;    if ((cursor = this.getCursor())) {      this.focusOnNextFrame(this.findPrev(cursor));    } else {      this.focusOnNextFrame(this.findLastByTag("a"));    }  }   onLeft() {    const cursor = this.getCursor();    if (      cursor &&      !cursor.classList.contains(app.views.ListFold.activeClass) &&      cursor.parentNode !== this.el    ) {      const prev = cursor.parentNode.previousSibling;      if (prev && prev.classList.contains(app.views.ListFold.targetClass)) {        this.focusOnNextFrame(cursor.parentNode.previousSibling);      }    }  }   onEnter() {    let cursor;    if ((cursor = this.getCursor())) {      $.click(cursor);    }  }   onSuperEnter() {    let cursor;    if ((cursor = this.getCursor())) {      $.popup(cursor);    }  }   onClick(event) {    if (event.which !== 1 || event.metaKey || event.ctrlKey) {      return;    }    const target = $.eventTarget(event);    if (target.tagName === "A") {      this.focus(target, { silent: true });    }  }};