VulpesOS/gaia/apps/calendar/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

230 lines
7.2 KiB
JavaScript
Executable file

define(function(require, exports) {
'use strict';
var Db = require('db');
var ErrorController = require('controllers/error');
var PendingManager = require('pending_manager');
var RecurringEventsController = require('controllers/recurring_events');
var ServiceController = require('controllers/service');
var SyncController = require('controllers/sync');
var TimeController = require('controllers/time');
var asyncRequire = require('common/async_require');
var bridge = require('bridge');
var co = require('ext/co');
var core = require('core');
var dateL10n = require('date_l10n');
var dayObserver = require('day_observer');
var debug = require('common/debug')('app');
var intl = require('./intl');
var messageHandler = require('message_handler');
var nextTick = require('common/next_tick');
var notificationsController = require('controllers/notifications');
var performance = require('performance');
var periodicSyncController = require('controllers/periodic_sync');
var providerFactory = require('provider/factory');
var router = require('router');
var storeFactory = require('store/factory');
var timeObserver = require('time_observer');
var viewFactory = require('views/factory');
var loadLazyStyles = null;
var l10nReady = new Promise(resolve => navigator.mozL10n.once(() => resolve()));
var pendingManager = new PendingManager();
var startingURL = window.location.href;
function setupCore(dbName) {
if (core.db) {
return;
}
core.bridge = bridge;
core.db = new Db(dbName || 'b2g-calendar');
core.errorController = new ErrorController();
core.notificationsController = notificationsController;
core.periodicSyncController = periodicSyncController;
core.providerFactory = providerFactory;
core.serviceController = new ServiceController();
core.storeFactory = storeFactory;
core.syncController = new SyncController();
core.timeController = new TimeController();
core.viewFactory = viewFactory;
}
function setupPendingManager() {
pendingManager.onpending = () => {
document.body.classList.add('pending-operation');
};
pendingManager.oncomplete = () => {
document.body.classList.remove('pending-operation');
performance.pendingReady();
if (!loadLazyStyles) {
// XXX: not loading the 'lazy_loaded.js' here anymore because for some
// weird reason curl.js was returning an object instead of
// a constructor when loading the "views/view_event" when starting the
// app from a notification; might be related to the fact we bundled
// multiple modules into the same file, are using the "paths" config to
// set the location and also using the async require in 2 places and
// using different module ids for each call.. the important thing is
// that this should still give a good performance result and works as
// expected.
loadLazyStyles = asyncRequire('css!lazy_loaded');
}
};
pendingManager.register(core.syncController);
}
function setupRouter() {
router.state('/week/', 'Week');
router.state('/day/', 'Day');
router.state('/month/', ['Month', 'MonthDayAgenda']);
router.modifier('/settings/', 'Settings', { clear: false });
router.modifier('/advanced-settings/', 'AdvancedSettings', {
color: 'settings'
});
router.state('/alarm-display/:id', 'ViewEvent', { path: false });
router.state('/event/add/', 'ModifyEvent');
router.state('/event/edit/:id', 'ModifyEvent');
router.state('/event/show/:id', 'ViewEvent');
router.modifier('/select-preset/', 'CreateAccount', {
color: 'settings'
});
router.modifier('/create-account/:preset', 'ModifyAccount');
router.modifier('/update-account/:id', 'ModifyAccount');
router.start();
// at this point the tabs should be interactive and the router ready to
// handle the path changes (meaning the user can start interacting with
// the app)
performance.chromeInteractive();
var pathname = window.location.pathname;
// default view
if (pathname === '/index.html' || pathname === '/') {
router.go('/month/');
}
}
/**
* Can only be initialized after db.load()
*/
function setupControllers() {
// start the workers
core.serviceController.start(false);
notificationsController.observe();
periodicSyncController.observe();
var recurringEventsController = new RecurringEventsController();
pendingManager.register(recurringEventsController);
recurringEventsController.observe();
// turn on the auto queue this means that when
// alarms are added to the database we manage them
// transparently. Defaults to off for tests.
var alarms = core.storeFactory.get('Alarm');
alarms.autoQueue = true;
}
function setupUI() {
intl.init();
return co(function *() {
// re-localize dates on screen
dateL10n.init();
timeObserver.init();
core.timeController.move(new Date());
// Restart the calendar when the timezone changes.
// We do this on a timer because this event may fire
// many times. Refreshing the url of the calendar frequently
// can result in crashes so we attempt to do this only after
// the user has completed their selection.
window.addEventListener('moztimechange', () => {
// for info on why we need to restart the app when the time changes see:
// https://bugzilla.mozilla.org/show_bug.cgi?id=1093016#c9
debug('Noticed timezone change!');
nextTick(() => window.location.href = startingURL);
});
nextTick(() => viewFactory.get('Errors'));
yield [
renderView('TimeHeader'),
renderView('ViewSelector')
];
// at this point we remove the .loading class and user will see the main
// app frame
document.body.classList.remove('loading');
performance.domLoaded();
setupRouter();
});
}
function renderView(viewName) {
return new Promise(accept => {
viewFactory.get(viewName, view => {
view.render();
accept();
});
});
}
function startDayObserver() {
// it should only start listening for month change after we have the
// calendars data, otherwise we might display events from calendars
// that are not visible. this also makes sure we load the calendars
// as soon as possible
return co(function *() {
var storeFactory = core.storeFactory;
var calendars = storeFactory.get('Calendar');
yield calendars.all();
dayObserver.init();
});
}
function startUI() {
// we init the UI after the db.load to increase perceived performance
// (will feel like busytimes are displayed faster)
return co(function *() {
yield l10nReady;
yield setupUI();
});
}
function configureAudioChannelManager() {
// Tell audio channel manager that we want to adjust the notification
// channel if the user press the volumeup/volumedown buttons in Calendar.
var audioChannelManager = navigator.mozAudioChannelManager;
if (audioChannelManager) {
audioChannelManager.volumeControlChannel = 'notification';
}
}
/**
* Primary code for app can go here.
*/
function init() {
return co(function *() {
debug('Will initialize calendar app');
setupCore();
setupPendingManager();
yield core.db.load();
setupControllers();
yield [startDayObserver(), startUI()];
messageHandler.start();
configureAudioChannelManager();
});
}
exports.init = init;
exports.pendingManager = pendingManager;
exports.setupCore = setupCore;
});