VulpesOS/gaia/tv_apps/remote-control/js/section.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

183 lines
4.7 KiB
JavaScript
Executable file

/* global SpatialNavigator */
'use strict';
(function(exports) {
function Section(id) {
this.id = id;
this._dom = document.getElementById(this.id);
var focusables = this._dom.querySelectorAll('.focusable');
Array.from(focusables).forEach(function(elem) {
elem.setAttribute('tabindex', -1);
});
this._spatialNav = new SpatialNavigator(
focusables,
{
ignoreHiddenElement: true,
rememberSource: true
}
);
this._spatialNav.on('focus', (elem) => {
elem.focus();
});
this._childSections = {};
this._activeChildSectionId = '';
this._defaultFocusElement = undefined;
this._focusableElementCount = focusables.length;
}
Section.prototype = {
uninit: function() {
if (this._uninit) {
this._uninit();
}
this._defaultFocusElement = undefined;
this._activeChildSectionId = '';
this._childSections = {};
this._parentSection = undefined;
this._spatialNav = undefined;
this._dom = undefined;
},
addChild: function(id, section) {
this._childSections[id] = section;
section._parentSection = this;
},
removeChild: function(id) {
this._childSections[id]._parentSection = undefined;
delete this._childSections[id];
},
focus: function(elem) {
if (typeof elem === 'string') {
elem = document.getElementById(elem);
}
return this._spatialNav.focus(elem);
},
unfocus: function() {
return this._spatialNav.unfocus();
},
handleMove: function(direction) {
var activeChildSection = this.getActiveChildSection();
if (activeChildSection) {
activeChildSection.handleMove(direction);
} else {
if (this._handleMove) {
var nextElement = this._handleMove(direction);
if (nextElement) {
if (this._spatialNav.focus(nextElement)) {
return;
}
}
}
if (!this._spatialNav.move(direction)) {
// If failed to move, re-focus the current one.
this._spatialNav.focus();
}
}
},
handleClick: function() {
var activeChildSection = this.getActiveChildSection();
if (activeChildSection) {
activeChildSection.handleClick();
} else if (this._handleClick) {
this._handleClick();
} else if (!this._focusableElementCount) {
// If there is no focusable element in this section, just close it.
this.backToParent();
}
},
handleBack: function() {
var activeChildSection = this.getActiveChildSection();
if (activeChildSection) {
if (!activeChildSection.handleBack()) {
// Hide the child section if it doesn't handle BACK key.
this.hideChildSection();
return true;
}
} else if (this._handleBack) {
return this._handleBack();
}
// Returning false can let BACK key to be bubbled to its parent.
return false;
},
getFocusedElement: function() {
return this._spatialNav.getFocusedElement();
},
getActiveChildSection: function() {
if (!this._activeChildSectionId) {
return undefined;
}
return this._childSections[this._activeChildSectionId];
},
backToParent: function() {
if (this._parentSection) {
this._parentSection.hideChildSection();
return true;
}
return false;
},
show: function(previousId) {
document.activeElement.blur();
if (this._readyToShow) {
this._readyToShow(previousId);
}
this._dom.classList.add('visible');
this._dom.removeAttribute('aria-hidden');
this._spatialNav.focus(this._defaultFocusElement);
},
hide: function() {
this._dom.classList.remove('visible');
this._dom.setAttribute('aria-hidden', true);
return this;
},
showChildSection: function(id) {
var child = this._childSections[id];
if (child) {
this.hide();
this._childSections[id].show();
this._activeChildSectionId = id;
}
},
hideChildSection: function() {
var activeChildSection = this.getActiveChildSection();
if (activeChildSection) {
var previousId = this._activeChildSectionId;
this._activeChildSectionId = '';
activeChildSection.hide();
this.show(previousId);
}
},
setDefaultFocusElement: function(elem) {
if (typeof elem === 'string') {
elem = document.getElementById(elem);
}
if (elem) {
this._defaultFocusElement = elem;
} else {
this._defaultFocusElement = undefined;
}
}
};
exports.Section = Section;
}(window));