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
241
gaia/apps/calendar/js/views/month.js
Executable file
241
gaia/apps/calendar/js/views/month.js
Executable file
|
|
@ -0,0 +1,241 @@
|
|||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
|
||||
var Calc = require('common/calc');
|
||||
var GestureDetector = require('shared/gesture_detector');
|
||||
var SingleMonth = require('./single_month');
|
||||
var View = require('view');
|
||||
var core = require('core');
|
||||
var dateFromId = Calc.dateFromId;
|
||||
var monthStart = Calc.monthStart;
|
||||
var performance = require('performance');
|
||||
var router = require('router');
|
||||
var timeObserver = require('time_observer');
|
||||
|
||||
// minimum difference between X and Y axis to be considered an horizontal swipe
|
||||
var XSWIPE_OFFSET = window.innerWidth / 10;
|
||||
|
||||
function Month() {
|
||||
View.apply(this, arguments);
|
||||
this.frames = new Map();
|
||||
window.addEventListener('localized', this);
|
||||
this._setPresentDate = this._setPresentDate.bind(this);
|
||||
}
|
||||
module.exports = Month;
|
||||
|
||||
Month.prototype = {
|
||||
__proto__: View.prototype,
|
||||
|
||||
SCALE: 'month',
|
||||
|
||||
selectors: {
|
||||
element: '#month-view',
|
||||
},
|
||||
|
||||
date: null,
|
||||
|
||||
/** @type {SingleMonth} */
|
||||
currentFrame: null,
|
||||
|
||||
/**
|
||||
* used to detect if dbltap happened on same date
|
||||
* @type {DOMElement}
|
||||
*/
|
||||
_lastTarget: null,
|
||||
|
||||
/**
|
||||
* store current, previous and next months
|
||||
* we load them beforehand and keep on the cache to speed up swipes
|
||||
* @type {Array<SingleMonth>}
|
||||
*/
|
||||
frames: null,
|
||||
|
||||
onactive: function() {
|
||||
View.prototype.onactive.apply(this, arguments);
|
||||
core.timeController.scale = this.SCALE;
|
||||
if (this.currentFrame) {
|
||||
this.currentFrame.activate();
|
||||
}
|
||||
},
|
||||
|
||||
_onswipe: function(data) {
|
||||
// only move to a different month if it's an horizontal swipe
|
||||
if (Math.abs(data.dy) > (Math.abs(data.dx) - XSWIPE_OFFSET)) {
|
||||
return;
|
||||
}
|
||||
var dir = document.documentElement.dir === 'rtl' ? -1 : 1;
|
||||
this._move(dir * data.dx < 0);
|
||||
},
|
||||
|
||||
_onwheel: function(event) {
|
||||
// mouse wheel is used for a10y
|
||||
if (event.deltaMode !== event.DOM_DELTA_PAGE || event.deltaX === 0) {
|
||||
return;
|
||||
}
|
||||
this._move(event.deltaX > 0);
|
||||
},
|
||||
|
||||
_move: function(isNext) {
|
||||
var controller = core.timeController;
|
||||
var date = isNext ? this._nextTime() : this._previousTime();
|
||||
// If we changed months, set the selected day to the 1st
|
||||
controller.selectedDay = date;
|
||||
controller.move(date);
|
||||
},
|
||||
|
||||
_nextTime: function() {
|
||||
return monthStart(this.date, 1);
|
||||
},
|
||||
|
||||
_previousTime: function() {
|
||||
return monthStart(this.date, -1);
|
||||
},
|
||||
|
||||
_initEvents: function() {
|
||||
this.controller = core.timeController;
|
||||
|
||||
this.element.addEventListener('swipe', this);
|
||||
this.element.addEventListener('wheel', this);
|
||||
this.controller.on('monthChange', this);
|
||||
this.delegate(this.element, 'click', '.month-day', this);
|
||||
this.delegate(this.element, 'dbltap', '.month-day', this);
|
||||
|
||||
timeObserver.on('day', this._setPresentDate);
|
||||
|
||||
this.gd = new GestureDetector(this.element);
|
||||
this.gd.startDetecting();
|
||||
},
|
||||
|
||||
handleEvent: function(e, target) {
|
||||
switch (e.type) {
|
||||
case 'swipe':
|
||||
this._onswipe(e.detail);
|
||||
break;
|
||||
case 'wheel':
|
||||
this._onwheel(e);
|
||||
break;
|
||||
case 'click':
|
||||
var date = dateFromId(target.dataset.date);
|
||||
this.controller.selectedDay = date;
|
||||
break;
|
||||
case 'dbltap':
|
||||
// make sure we discard double taps that started on a different day
|
||||
if (this._lastTarget === target) {
|
||||
this._goToAddEvent();
|
||||
}
|
||||
break;
|
||||
case 'monthChange':
|
||||
this.changeDate(e.data[0]);
|
||||
break;
|
||||
case 'localized':
|
||||
this.reconstruct();
|
||||
break;
|
||||
}
|
||||
this._lastTarget = target;
|
||||
},
|
||||
|
||||
_goToAddEvent: function(date) {
|
||||
// slight delay to avoid tapping the elements inside the add event screen
|
||||
setTimeout(() => {
|
||||
// don't need to set the date since the first tap triggers a click that
|
||||
// sets the timeController.selectedDay
|
||||
router.go('/event/add/');
|
||||
}, 50);
|
||||
},
|
||||
|
||||
changeDate: function(time) {
|
||||
this.date = monthStart(time);
|
||||
|
||||
if (this.currentFrame) {
|
||||
this.currentFrame.deactivate();
|
||||
}
|
||||
|
||||
this.currentFrame = this._getFrame(this.date);
|
||||
|
||||
this._trimFrames();
|
||||
this._appendFrames();
|
||||
|
||||
this.currentFrame.activate();
|
||||
},
|
||||
|
||||
_getFrame: function(date) {
|
||||
var id = date.getTime();
|
||||
var frame = this.frames.get(id);
|
||||
if (!frame) {
|
||||
frame = new SingleMonth({
|
||||
date: date,
|
||||
container: this.element
|
||||
});
|
||||
frame.create();
|
||||
this.frames.set(id, frame);
|
||||
}
|
||||
return frame;
|
||||
},
|
||||
|
||||
_trimFrames: function() {
|
||||
if (this.frames.size <= 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
// full month (we always keep previous/next months)
|
||||
var delta = 31 * 24 * 60 * 60 * 1000;
|
||||
|
||||
this.frames.forEach((frame, ts) => {
|
||||
var base = Number(this.date);
|
||||
if (Math.abs(base - ts) > delta) {
|
||||
frame.destroy();
|
||||
this.frames.delete(ts);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_appendFrames: function() {
|
||||
// sort elements by timestamp (key = timestamp) so DOM makes more sense
|
||||
Array.from(this.frames.keys())
|
||||
.sort((a, b) => a - b)
|
||||
.forEach(key => this.frames.get(key).append());
|
||||
},
|
||||
|
||||
_setPresentDate: function() {
|
||||
var id = Calc.getDayId(new Date());
|
||||
var presentDate = this.element.querySelector('[data-date="' + id + '"]');
|
||||
var previousDate = this.element.querySelector('.present');
|
||||
|
||||
if (previousDate) {
|
||||
previousDate.classList.remove('present');
|
||||
previousDate.classList.add('past');
|
||||
}
|
||||
if (presentDate) {
|
||||
presentDate.classList.add('present');
|
||||
}
|
||||
},
|
||||
|
||||
oninactive: function() {
|
||||
View.prototype.oninactive.call(this);
|
||||
if (this.currentFrame) {
|
||||
this.currentFrame.deactivate();
|
||||
}
|
||||
},
|
||||
|
||||
onfirstseen: function() {
|
||||
this._initEvents();
|
||||
this.changeDate(this.controller.month);
|
||||
performance.monthReady();
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.frames.forEach((frame, key) => {
|
||||
this.frames.delete(key);
|
||||
frame.destroy();
|
||||
});
|
||||
},
|
||||
|
||||
reconstruct: function() {
|
||||
// Watch for changed value from transition of a locale to another
|
||||
this.destroy();
|
||||
this.changeDate(this.controller.month);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
});
|
||||
Loading…
Reference in a new issue