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 }); } } };