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,219 @@
/* global IntlHelper */
define(function(require, exports, module) {
'use strict';
var Overlap = require('utils/overlap');
var buildElement = require('utils/dom').buildElement;
var core = require('core');
var isSameDate = require('common/calc').isSameDate;
var relativeDuration = require('common/calc').relativeDuration;
var relativeOffset = require('common/calc').relativeOffset;
var spanOfDay = require('common/calc').spanOfDay;
var template = require('templates/multi_day');
var _id = 0;
IntlHelper.define('longDateFormat', 'datetime', {
weekday: 'long',
day: 'numeric',
month: 'long',
year: 'numeric'
});
function SingleDay(config) {
this.date = config.date;
this._hourHeight = config.hourHeight;
this._daysHolder = config.daysHolder;
this._allDayIcon = config.allDayIcon;
this._alldaysHolder = config.alldaysHolder;
this._oneDayLabelFormat = config.oneDayLabelFormat;
this._render = this._render.bind(this);
this._instanceID = _id++;
this.overlaps = new Overlap();
}
module.exports = SingleDay;
SingleDay.prototype = {
_isActive: false,
_borderWidth: 0.1,
_attached: false,
_observer: null,
setup: function() {
this.day = buildElement(template.day.render({
date: this.date
}));
this.allday = buildElement(template.allday.render({
date: this.date,
id: this._instanceID
}));
this._dayName = this.allday.querySelector('.md__day-name');
this._alldayEvents = this.allday.querySelector('.md__allday-events');
this._updateDayName();
this.onactive();
},
_updateDayName: function() {
// we can't use [data-l10n-date-format] because format might change based
// on locale
this._dayName.textContent = this.date.toLocaleString(navigator.languages, {
weekday: 'short',
day: 'numeric'
});
},
handleEvent: function(evt) {
switch(evt.type) {
case 'localized':
this._updateDayName();
break;
}
},
append: function() {
this._daysHolder.appendChild(this.day);
this._alldaysHolder.appendChild(this.allday);
this._attached = true;
},
onactive: function() {
if (this._isActive) {
return;
}
this._observer = core.bridge.observeDay(this.date);
this._observer.listen(this._render);
window.addEventListener('localized', this);
this._isActive = true;
},
_render: function(records) {
this._alldayEvents.innerHTML = '';
records.allday.forEach(this._renderAlldayEvent, this);
this.overlaps.reset();
this.day.innerHTML = '';
records.basic.forEach(this._renderEvent, this);
if (this._alldayEvents.children.length > 0) {
// If there are all day events, the section acts as a listbox.
this._alldayEvents.setAttribute('role', 'listbox');
this._alldayEvents.setAttribute('aria-labelledby', this._allDayIcon.id +
' ' + this._dayName.id);
} else {
// If there are no all day events, the section acts as a create new all
// day event button.
this._alldayEvents.setAttribute('role', 'button');
this._alldayEvents.setAttribute('data-l10n-id', 'create-all-day-event');
this._alldayEvents.setAttribute('aria-describedby', this._dayName.id);
}
},
_renderEvent: function(record) {
var el = this._buildEventElement(record);
var {busytime} = record;
var {startDate, endDate} = busytime;
// we don't set the height on the template because we use the same markup
// for all day events as well
var duration = relativeDuration(this.date, startDate, endDate);
// we subtract border to keep a margin between consecutive events
var hei = duration * this._hourHeight - this._borderWidth;
// It doesn't make sense to set height less than 1 px, so we set it to 1 px
// in order to show events correctly.
hei = Math.max(1, hei);
el.style.height = hei + 'px';
if (duration < 1) {
el.classList.add('is-partial');
var size = '';
// we need to toggle layout if event lasts less than 20, 30 and 45min
if (duration < 0.3) {
size = 'micro';
} else if (duration < 0.5) {
size = 'tiny';
} else if (duration < 0.75) {
size = 'small';
}
if (size) {
el.classList.add('is-partial-' + size);
}
}
var offset = relativeOffset(this.date, startDate);
el.style.top = (offset * this._hourHeight) + 'px';
this.overlaps.add(busytime, el);
this.day.appendChild(el);
},
_buildEventElement: function(record) {
var {title, location, alarms} = record.event.remote;
var {startDate, endDate, _id} = record.busytime;
// screen reader should be aware if the event spans multiple dates and also
// know the event duration without having the open it
var labelFormat = isSameDate(startDate, endDate) ? this._oneDayLabelFormat :
'event-multiple-day-duration';
var longDateFormat = IntlHelper.get('longDateFormat');
var shortTimeFormat = IntlHelper.get('shortTimeFormat');
var labelFormatArgs = JSON.stringify({
startDate: longDateFormat.format(startDate),
startTime: shortTimeFormat.format(startDate),
endDate: longDateFormat.format(endDate),
endTime: shortTimeFormat.format(endDate)
});
return buildElement(template.event.render({
id: _id,
instance: this._instanceID,
title: title,
location: location,
hasAlarms: alarms && alarms.length,
color: record.color,
labelFormat: labelFormat,
labelFormatArgs: labelFormatArgs
}));
},
_renderAlldayEvent: function(record) {
var el = this._buildEventElement(record);
el.classList.add('is-allday');
el.setAttribute('role', 'option');
this._alldayEvents.appendChild(el);
},
destroy: function() {
this.oninactive();
this._detach();
},
_detach: function() {
if (this._attached) {
this._daysHolder.removeChild(this.day);
this._alldaysHolder.removeChild(this.allday);
this._attached = false;
}
},
oninactive: function() {
if (!this._isActive) {
return;
}
this._observer.cancel();
window.removeEventListener('localized', this);
this._isActive = false;
},
setVisibleForScreenReader: function(visibleRange) {
var visible = visibleRange.contains(spanOfDay(this.date));
this.day.setAttribute('aria-hidden', !visible);
this.allday.setAttribute('aria-hidden', !visible);
}
};
});