VulpesOS/gaia/apps/clock/js/app.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

165 lines
4.9 KiB
JavaScript
Executable file

define(function(require) {
'use strict';
/* global IntlHelper */
var Tabs = require('tabs');
var View = require('view');
var connectionHandler = require('connection/handler');
/**
* Global Application event handling and paging
*/
var App = {
/**
* Load the Tabs and Panels, attach events and navigate to the default view.
*/
init: function() {
connectionHandler.init();
IntlHelper.define('digit-nopadding', 'number', {
style: 'decimal',
useGrouping: false
});
this.tabs = new Tabs(document.getElementById('clock-tabs'));
window.addEventListener('hashchange', this);
window.addEventListener('visibilitychange', this);
// Tell audio channel manager that we want to adjust the alarm channel
// if the user press the volumeup/volumedown buttons in Clock.
if (navigator.mozAudioChannelManager) {
navigator.mozAudioChannelManager.volumeControlChannel = 'alarm';
}
this.visible = !document.hidden;
this.panels = Array.prototype.map.call(
document.querySelectorAll('[data-panel-id]'),
function(element) {
var panel = {
el: element,
fragment: element.dataset.panelId.replace('_', '-') + '-panel',
instance: null
};
return panel;
}.bind(this)
);
window.performance.mark('navigationLoaded');
this.navigate({ hash: '#alarm-panel' }, function() {
// Dispatch an event to mark when we've finished loading.
// At this point, the navigation is usable, and the primary
// alarm list tab has begun loading.
window.performance.mark('navigationInteractive');
}.bind(this));
return this;
},
/**
* Load and instantiate the specified panel (when necessary).
*
* @param {Object} panel - An object describing the panel. It must contain
* either an `el` attribute (defining the panel's
* containing element) or an `instance` attribute
* (defining the instantiated Panel itself).
* @param {Function} [callback] - A function that will be invoked with the
* instantiated panel once it is loaded.
*/
loadPanel: function(panel, callback) {
if (panel.instance) {
callback && setTimeout(callback, 0, panel);
return;
}
var moduleId = 'panels/' + panel.el.dataset.panelId + '/main';
require([moduleId], function(PanelModule) {
panel.instance = View.instance(panel.el, PanelModule);
callback && callback(panel);
});
},
alarmListLoaded: function() {
// Performance testing markers. See <https://bugzil.la/996038>.
// At this point, the alarm list has been loaded, and all facets
// of Clock are now interactive. The other panels are lazily
// loaded when the user switches tabs.
window.performance.mark('visuallyLoaded');
window.performance.mark('contentInteractive');
window.performance.mark('fullyLoaded');
},
/**
* split each event handler into it's own method
*/
handleEvent: function(event) {
var handler = this['on' + event.type];
if (handler) {
return handler.apply(this, arguments);
}
},
/**
* navigate between pages.
*
* @param {object} data Options for navigation.
* @param {string} data.hash The hash of the panel id. I.E. '#alarm-panel'.
* @param {function} callback Callback to invoke when done.
*/
navigate: function(data, callback) {
var currentIndex = this.panels.indexOf(this.currentPanel);
this.panels.forEach(function(panel, panelIndex) {
if ('#' + panel.fragment === data.hash) {
this.loadPanel(panel, function() {
var instance = panel.instance;
instance.navData = data.data || null;
instance.active = true;
instance.visible = true;
if (currentIndex !== -1 && currentIndex !== panelIndex) {
var direction = currentIndex < panelIndex;
requestAnimationFrame(function startAnimation(oldPanel) {
instance.transition =
direction ? 'slide-in-right' : 'slide-in-left';
oldPanel.instance.transition =
direction ? 'slide-out-left' : 'slide-out-right';
}.bind(null, this.currentPanel));
}
this.currentPanel = panel;
callback && callback();
}.bind(this));
} else {
if (panel.instance) {
panel.instance.active = false;
}
}
}, this);
this.currentHash = data.hash;
},
/**
* Navigate to the new hash.
*/
onhashchange: function(event) {
if (this.currentHash === location.hash) {
return;
}
this.navigate({ hash: location.hash });
},
/**
* Whenever the application gains/loses focus, inform the current panel of
* its visibility loss.
*/
onvisibilitychange: function(event) {
this.visible = !document.hidden;
if (this.currentPanel) {
this.currentPanel.visible = this.visible;
}
}
};
return App;
});