VulpesOS/gaia/apps/calendar/js/controllers/sync.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

174 lines
3.9 KiB
JavaScript
Executable file

define(function(require, exports, module) {
'use strict';
var Responder = require('common/responder');
var core = require('core');
var isOffline = require('common/is_offline');
/**
* Handles all synchronization related
* tasks. The intent is that this will
* be the focal point for any view
* to observe sync events and this
* controller will decide when to actually
* tell the stores when to sync.
*/
function Sync() {
this.pending = 0;
Responder.call(this);
}
module.exports = Sync;
Sync.prototype = {
__proto__: Responder.prototype,
startEvent: 'syncStart',
completeEvent: 'syncComplete',
_incrementPending: function() {
if (!this.pending) {
this.emit('syncStart');
}
this.pending++;
},
_resolvePending: function() {
if (!(--this.pending)) {
this.emit('syncComplete');
}
if (this.pending < 0) {
dump('\n\n Error calendar sync .pending is < 0 \n\n');
}
},
/**
* Sync all accounts, calendars, events.
* There is no callback for all intentionally.
*
* Use:
*
* controller.once('syncComplete', cb);
*
*/
all: function(callback) {
// this is for backwards compatibility... in reality we should remove
// callbacks from .all.
if (callback) {
this.once('syncComplete', callback);
}
if (isOffline()) {
this.emit('offline');
this.emit('syncComplete');
return;
}
var account = core.storeFactory.get('Account');
account.all(function(err, list) {
for (var key in list) {
this.account(list[key]);
}
// If we have nothing to sync
if (!this.pending) {
this.emit('syncComplete');
}
}.bind(this));
},
/**
* Initiates a sync for a single calendar.
*
* @param {Object} account parent of calendar.
* @param {Object} calendar specific calendar to sync.
* @param {Function} [callback] optional callback.
*/
calendar: function(account, calendar, callback) {
var store = core.storeFactory.get('Calendar');
var self = this;
this._incrementPending();
store.sync(account, calendar, err => {
self._resolvePending();
this.handleError(err, callback);
});
},
/**
* Initiates a sync of a single account and all
* associated calendars (calendars that exist after
* the full sync of the account itself).
*
* The contract is if an callback is given the callback MUST handle the
* error given. The default behaviour is to bubble up the error up to the
* error controller.
*
* @param {Object} account sync target.
* @param {Function} [callback] optional callback.
*/
account: function(account, callback) {
var storeFactory = core.storeFactory;
var accountStore = storeFactory.get('Account');
var calendarStore = storeFactory.get('Calendar');
var self = this;
this._incrementPending();
accountStore.sync(account, err => {
if (err) {
self._resolvePending();
return this.handleError(err, callback);
}
var pending = 0;
function next() {
if (!(--pending)) {
self._resolvePending();
if (callback) {
callback();
}
}
}
function fetchCalendars(err, calendars) {
if (err) {
self._resolvePending();
return self.handleError(err, callback);
}
for (var key in calendars) {
pending++;
self.calendar(account, calendars[key], next);
}
}
// find all calendars
calendarStore.remotesByAccount(
account._id,
fetchCalendars
);
});
},
/**
* Private helper for choosing how to dispatch errors.
* When given a callback the callback will be called otherwise the error
* controller will be invoked.
*/
handleError: function(err, callback) {
if (callback) {
return callback(err);
}
core.errorController.dispatch(err);
}
};
});