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:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View 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);
}
};
});