// library tree keyboard navigation manager class LibrarySelection { constructor(options = {}) { this.currentFocusedItem = null; this.currentSection = "artists"; // "artists" or "playlists" } getFocusableItems() { // get all focusable items in library (organized by section for natural navigation) const items = []; const sections = [ { selector: '[data-section="artists"]', containerId: DOM_IDS.LIBRARY_TREE, }, { selector: '[data-section="playlists"]', containerId: DOM_IDS.PLAYLISTS_TREE, }, ]; sections.forEach(({ selector, containerId }) => { const toggle = document.querySelector(selector); if (toggle) { items.push(toggle); const sectionItems = Array.from( document.querySelectorAll( `#${containerId} .${CLASSES.TREE_TOGGLE}, #${containerId} .${CLASSES.TREE_NAME}`, ), ); items.push(...sectionItems); } }); return items; } focusItem(element) { // set focus to specific item if (this.currentFocusedItem) { this.currentFocusedItem.classList.remove(CLASSES.FOCUSED); } if (element) { element.classList.add(CLASSES.FOCUSED); element.scrollIntoView({ block: "nearest" }); this.currentFocusedItem = element; } } _navigateTo(calcNewIndex) { // navigate with direction and optional offset (for page navigation) const items = this.getFocusableItems(); if (items.length === 0) return; if (!this.currentFocusedItem) { this.focusItem(items[0]); return; } const currentIndex = items.indexOf(this.currentFocusedItem); const newIndex = calcNewIndex(currentIndex, items.length); if (newIndex >= 0 && newIndex < items.length) { this.focusItem(items[newIndex]); } } navigate(direction) { // navigate up/down through items this._navigateTo((idx) => idx + direction); } navigatePageUp(pageSize = 10) { // navigate by page (jump multiple items) this._navigateTo((idx) => Math.max(0, idx - pageSize)); } navigatePageDown(pageSize = 10) { // navigate by page down (jump multiple items) this._navigateTo((idx, len) => Math.min(len - 1, idx + pageSize)); } getCurrentItemData() { // get data (item id and type) from currently focused item if (!this.currentFocusedItem) return null; const li = this.currentFocusedItem.closest("li"); if (!li) return null; const inArtists = this.currentFocusedItem.closest(`#${DOM_IDS.LIBRARY_TREE}`) !== null; return { itemId: li.dataset.itemId, section: inArtists ? "artists" : "playlists", }; } } const librarySelection = new LibrarySelection();