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.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
248
gaia/apps/calendar/js/controllers/recurring_events.js
Executable file
248
gaia/apps/calendar/js/controllers/recurring_events.js
Executable file
|
|
@ -0,0 +1,248 @@
|
|||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
|
||||
var Responder = require('common/responder');
|
||||
var core = require('core');
|
||||
var debug = require('common/debug')('controllers/recurring_events');
|
||||
var nextTick = require('common/next_tick');
|
||||
|
||||
function RecurringEvents() {
|
||||
this.accounts = core.storeFactory.get('Account');
|
||||
Responder.call(this);
|
||||
}
|
||||
module.exports = RecurringEvents;
|
||||
|
||||
RecurringEvents.prototype = {
|
||||
__proto__: Responder.prototype,
|
||||
|
||||
startEvent: 'expandStart',
|
||||
completeEvent: 'expandComplete',
|
||||
|
||||
/**
|
||||
* Adds N number of days to the window to expand
|
||||
* events until. Its very important for this number
|
||||
* to be greater then the maximum number of days displayed
|
||||
* in the month view (or a view with more days) otherwise
|
||||
* the view may be loaded without actually expanding all
|
||||
* the visible days.
|
||||
*
|
||||
* @type Number
|
||||
*/
|
||||
paddingInDays: 85,
|
||||
|
||||
/**
|
||||
* Amount of time (in MS) to wait between triggering
|
||||
* the recurring event expansions.
|
||||
*/
|
||||
waitBeforeMove: 750,
|
||||
|
||||
/**
|
||||
* We need to limit the number of tries on expansions
|
||||
* otherwise its possible we never complete during error
|
||||
* or long recurring event.
|
||||
*/
|
||||
maximumExpansions: 25,
|
||||
|
||||
/**
|
||||
* private timeout (as in setTimeout id) use with waitBeforeMove.
|
||||
*/
|
||||
_moveTimeout: null,
|
||||
|
||||
/**
|
||||
* True when queue is running...
|
||||
*/
|
||||
pending: false,
|
||||
|
||||
unobserve: function() {
|
||||
core.timeController.removeEventListener(
|
||||
'monthChange',
|
||||
this
|
||||
);
|
||||
|
||||
core.syncController.removeEventListener(
|
||||
'syncComplete',
|
||||
this
|
||||
);
|
||||
},
|
||||
|
||||
observe: function() {
|
||||
var time = core.timeController;
|
||||
|
||||
// expand initial time this is necessary
|
||||
// for cases where user has device off for long periods of time.
|
||||
if (time.position) {
|
||||
this.queueExpand(time.position);
|
||||
}
|
||||
|
||||
// register observers
|
||||
time.on('monthChange', this);
|
||||
|
||||
// we must re-expand after sync so events at least
|
||||
// expand to the current position....
|
||||
core.syncController.on('syncComplete', this);
|
||||
},
|
||||
|
||||
handleEvent: function(event) {
|
||||
switch (event.type) {
|
||||
case 'syncComplete':
|
||||
this.queueExpand(
|
||||
core.timeController.position
|
||||
);
|
||||
break;
|
||||
|
||||
case 'monthChange':
|
||||
if (this._moveTimeout !== null) {
|
||||
clearTimeout(this._moveTimeout);
|
||||
this._moveTimeout = null;
|
||||
}
|
||||
|
||||
// trigger the event queue when we move
|
||||
this._moveTimeout = setTimeout(
|
||||
// data[0] is the new date.
|
||||
this.queueExpand.bind(this, event.data[0]),
|
||||
this.waitBeforeMove
|
||||
);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Attempts to expand provider until no events require expansion.
|
||||
*
|
||||
* @param {Date} expandDate expands up to this date.
|
||||
* @param {Calendar.Provider.Abstract} provider instance.
|
||||
* @param {Function} callback
|
||||
* fired when maximumExpansions is hit or
|
||||
* no more events require expansion.
|
||||
*
|
||||
*/
|
||||
_expandProvider: function(expandDate, provider, callback) {
|
||||
debug('Will attempt to expand provider until:', expandDate);
|
||||
var tries = 0;
|
||||
var max = this.maximumExpansions;
|
||||
|
||||
function attemptCompleteExpand() {
|
||||
debug('Will try to complete expansion (tries = ' + tries + ')');
|
||||
if (tries >= max) {
|
||||
return callback(new Error(
|
||||
'could not complete expansion after "' + tries + '"'
|
||||
));
|
||||
}
|
||||
|
||||
provider.ensureRecurrencesExpanded(expandDate, function(err, didExpand) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
debug('Expansion attempt did expand:', didExpand);
|
||||
|
||||
if (!didExpand) {
|
||||
// successfully expanded and no events need expansion
|
||||
// for this date anymore...
|
||||
callback();
|
||||
} else {
|
||||
tries++;
|
||||
// attempt another expand without stack.
|
||||
nextTick(attemptCompleteExpand);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
attemptCompleteExpand();
|
||||
},
|
||||
|
||||
/**
|
||||
* Queues an expansion. If the given date is before
|
||||
* any dates in the stack it will be discarded.
|
||||
*/
|
||||
queueExpand: function(expandTo) {
|
||||
if (this.pending) {
|
||||
if (!this._next) {
|
||||
this._next = expandTo;
|
||||
} else if (expandTo > this._next) {
|
||||
this._next = expandTo;
|
||||
}
|
||||
// don't start the queue if pending...
|
||||
return;
|
||||
}
|
||||
|
||||
// either way we need to process an event
|
||||
// so increment pending for running and non-running cases.
|
||||
this.pending = true;
|
||||
this.emit('expandStart');
|
||||
|
||||
var self = this;
|
||||
function expandNext(date) {
|
||||
self.expand(date, function() {
|
||||
if (date === self._next) {
|
||||
self._next = null;
|
||||
}
|
||||
|
||||
var next = self._next;
|
||||
|
||||
// when the queue is empty emit expandComplete
|
||||
if (!next) {
|
||||
self.pending = false;
|
||||
self.emit('expandComplete');
|
||||
return;
|
||||
}
|
||||
|
||||
expandNext(next);
|
||||
});
|
||||
}
|
||||
|
||||
expandNext(expandTo);
|
||||
},
|
||||
|
||||
/**
|
||||
* Ensures we have time converage until the given date.
|
||||
* Additional time will be added to the date see .paddingInDays.
|
||||
*
|
||||
* @param {Date} expandTo date to expand to.
|
||||
*/
|
||||
expand: function(expandTo, callback) {
|
||||
debug('expand', expandTo);
|
||||
|
||||
this.accounts.all((err, accounts) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// add minimum padding...
|
||||
var expandDate = new Date(expandTo.valueOf());
|
||||
expandDate.setDate(expandDate.getDate() + this.paddingInDays);
|
||||
|
||||
var providers = this._getExpandableProviders(accounts);
|
||||
var pending = providers.length;
|
||||
|
||||
if (!pending) {
|
||||
return nextTick(callback);
|
||||
}
|
||||
|
||||
providers.forEach(provider => {
|
||||
this._expandProvider(expandDate, provider, () => {
|
||||
if (--pending <= 0) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_getExpandableProviders: function(accounts) {
|
||||
var providers = [];
|
||||
Object.keys(accounts).forEach(key => {
|
||||
var account = accounts[key];
|
||||
var provider = core.providerFactory.get(account.providerType);
|
||||
if (provider &&
|
||||
provider.canExpandRecurringEvents &&
|
||||
providers.indexOf(provider) === -1) {
|
||||
providers.push(provider);
|
||||
}
|
||||
});
|
||||
|
||||
return providers;
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
Loading…
Reference in a new issue