VulpesOS/gaia/apps/homescreen/js/window.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

175 lines
5.1 KiB
JavaScript
Executable file

/* global Apps, Pages */
'use strict';
(function(exports) {
/**
* Time after receiving a handled hashchange that we ignore hashchange
* events for.
*/
const HASH_CHANGE_DEBOUNCE = 100;
function AppWindow() {
this.header = document.getElementById('page-indicator-header');
this.indicator = document.getElementById('page-indicator');
this.panels = document.getElementById('panels');
this.shadow = document.getElementById('shadow');
this.apps = new Apps();
this.pages = new Pages();
// Panel visibility state
this.appsVisible = undefined;
// Home-button handling
this.ignoreHashChangeTimeout = null;
// Signal handlers
this.indicator.addEventListener('keypress', this);
this.panels.addEventListener('scroll', this);
window.addEventListener('hashchange', this, true);
window.addEventListener('localized', this);
document.addEventListener('visibilitychange', this);
// Update the panel indicator
this.updatePanelIndicator();
// Application has finished initialisation
window.performance.mark('navigationInteractive');
}
AppWindow.prototype = {
updatePanelIndicator: function() {
var appsVisible =
Math.abs(this.panels.scrollLeft) <= this.panels.scrollWidth / 4;
if (this.appsVisible !== appsVisible) {
this.appsVisible = appsVisible;
this.header.setAttribute('data-l10n-id', appsVisible ?
'apps-panel' : 'pages-panel');
this.indicator.children[0].classList.toggle('active', appsVisible);
this.indicator.children[1].classList.toggle('active', !appsVisible);
this.indicator.setAttribute('aria-valuenow', appsVisible ? 1 : 2);
this.indicator.setAttribute('data-l10n-args', JSON.stringify({
currentPage: appsVisible ? 1 : 2,
totalPages: 2
}));
this.apps.panel.setAttribute('aria-hidden', !appsVisible);
this.pages.panel.setAttribute('aria-hidden', appsVisible);
if (appsVisible) {
this.pages.scrollable.removeEventListener('scroll', this);
this.apps.scrollable.addEventListener('scroll', this);
} else {
this.apps.scrollable.removeEventListener('scroll', this);
this.pages.scrollable.addEventListener('scroll', this);
}
this.updateShadowState();
}
},
updateShadowState: function() {
var position = this.appsVisible ?
this.apps.scrollable.scrollTop : this.pages.scrollable.scrollTop;
var scrolled = position > 1;
if (this.shadow.classList.contains('visible') !== scrolled) {
this.shadow.classList.toggle('visible', scrolled);
}
},
handleEvent: function(e) {
switch (e.type) {
// Switch between panels
case 'keypress':
if (!e.ctrlKey) {
return;
}
switch (e.keyCode) {
case e.DOM_VK_RIGHT:
this.panels.scrollTo(
{ left: this.panels.scrollLeftMax, top: 0, behavior: 'smooth' });
return;
case e.DOM_VK_LEFT:
this.panels.scrollTo(
{ left: 0, top: 0, behavior: 'smooth' });
return;
}
return;
// Display the top shadow when scrolling down
case 'scroll':
if (e.target === this.panels) {
this.updatePanelIndicator();
} else {
this.updateShadowState();
}
return;
// Cancel edit modes/scroll to the top/scroll to apps on home-button
case 'hashchange':
if (document.hidden || this.ignoreHashChangeTimeout !== null) {
return;
}
e.preventDefault();
e.stopImmediatePropagation();
this.ignoreHashChangeTimeout = setTimeout(() => {
this.ignoreHashChangeTimeout = null;
}, HASH_CHANGE_DEBOUNCE);
// If a dialog is showing, cancel the dialog
for (var dialog of this.apps.dialogs.concat(this.pages.dialogs)) {
if (!dialog.opened) {
continue;
}
dialog.close();
return;
}
// If we're in edit mode, cancel edit mode
if (this.apps.editMode) {
this.apps.exitEditMode();
return;
}
if (this.pages.editMode) {
this.pages.exitEditMode();
return;
}
// If we're on the pages panel and scrolled to the top, show apps
if (!this.appsVisible && this.pages.scrollable.scrollTop === 0) {
this.panels.scrollTo({ left: 0, top: 0, behavior: 'smooth' });
return;
}
// Otherwise, scroll the visible panel to the top
var visiblePanel = this.appsVisible ?
this.apps.scrollable : this.pages.scrollable;
visiblePanel.scrollTo({ left: 0, top: 0, behavior: 'smooth' });
return;
case 'localized':
this.updatePanelIndicator();
return;
// Exit edit mode if the user switches away from the home screen (e.g.
// by locking the phone).
case 'visibilitychange':
if (document.hidden) {
this.apps.exitEditMode();
this.pages.exitEditMode();
}
return;
}
}
};
exports.AppWindow = AppWindow;
}(window));