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,30 @@
define(function(require, exports, module) {
'use strict';
var create = require('template').create;
module.exports = create({
provider: function() {
var name = this.h('name');
return `<li class="${name}" role="presentation">
<a data-l10n-id="preset-${name}" role="option" dir="auto"
data-provider="${name}" href="/create-account/${name}">
</a>
</li>`;
},
account: function() {
var id = this.h('id');
var preset = this.h('preset');
var user = this.h('user');
return `<li id="account-${id}" role="presentation">
<a href="/update-account/${id}" role="option" dir="auto">
<span class="preset" data-l10n-id="preset-${preset}"></span>
<span class="user">${user}</span>
</a>
</li>`;
}
});
});

View file

@ -0,0 +1,178 @@
/* global mozIntl */
define(function(require, exports, module) {
'use strict';
var create = require('template').create;
var MINUTE = 60;
var HOUR = 3600;
var DAY = 86400;
var WEEK = 604800;
var MORNING = HOUR * 9;
var layouts = {
standard: [
'none',
0,
0 - MINUTE * 5,
0 - MINUTE * 15,
0 - MINUTE * 30,
0 - HOUR,
0 - HOUR * 2,
0 - DAY
],
allday: [
'none',
0 + MORNING,
0 - DAY + MORNING,
0 - DAY * 2 + MORNING,
0 - WEEK + MORNING,
0 - WEEK * 2 + MORNING
]
};
var Alarm = create({
reminder: function() {
var alarmContent = '';
var alarms = this.arg('alarms');
var isAllDay = this.arg('isAllDay');
var i = 0;
var alarm;
while ((alarm = alarms[i])) {
i++;
alarmContent += Alarm.description.render({
trigger: alarm.trigger,
layout: isAllDay ? 'allday' : 'standard'
});
}
return alarmContent;
},
description: function() {
var {id, data} = getL10n(this.arg('trigger'), this.arg('layout'));
var args = JSON.stringify(data);
var description = navigator.mozL10n.get(id, data);
return `<div role="listitem" data-l10n-id="${id}"
data-l10n-args=\'${args}\'>
${description}
</div>`;
},
// builds a list of <option>
options: function() {
var content = '';
var selected;
var foundSelected = false;
var trigger = this.arg('trigger');
var layout = this.arg('layout') || 'standard';
var options = layouts[layout];
var i = 0;
var iLen = options.length;
for (; i < iLen; i++) {
selected = false;
// trigger option 'selected' by normalizing imported dates
if (layout === 'allday') {
if (options[i] === (trigger + MORNING)) {
trigger += MORNING;
}
}
if (!selected && trigger && options[i] === trigger) {
selected = true;
foundSelected = true;
}
content += Alarm.option.render({
selected: selected,
layout: layout,
value: options[i]
});
}
// foundSelected is used in cases where user is editing an event that has
// a custom reminder value (X minutes/hours/days before event) and that
// is an option that we don't support internally on the calendar app.
// we always add a new <option> using the custom value and mark it as
// selected.
if (!foundSelected && /^-?\d+$/.test(trigger)) {
content += Alarm.option.render({
selected: true,
layout: layout,
value: trigger
});
}
return content;
},
option: function() {
var _ = navigator.mozL10n.get;
var layout = this.arg('layout');
var value = this.arg('value');
var selected = this.arg('selected');
var l10n = getL10n(value, layout);
var content = [
'<option',
'value="' + value + '"',
(selected ? 'selected' : ''),
'data-l10n-id="' + l10n.id + '"',
'data-l10n-args=\'' + JSON.stringify(l10n.data) + '\'>',
_(l10n.id, l10n.data) + '</option>'
].join(' ');
return content;
},
picker: function() {
return '<span class="button icon icon-dialog">' +
'<select name="alarm[]">' +
Alarm.options.render(this.data) +
'</select>' +
'</span>';
}
});
function getL10n(trigger, layout) {
if (trigger === 'none') {
return {
id: trigger,
data: {}
};
}
// Format the display text based on a zero-offset trigger
if (layout === 'allday') {
var options = layouts.allday;
if (options.indexOf(trigger) !== -1) {
trigger -= MORNING;
}
}
if (trigger === 0) {
return {
id: 'alarm-at-event-' + layout,
data: {}
};
}
var affix = trigger > 0 ? 'after' : 'before';
var part = mozIntl._gaia.relativePart(trigger * 1000);
return {
id: part.unit + '-' + affix,
data: {
value: part.value
}
};
}
module.exports = Alarm;
});

View file

@ -0,0 +1,35 @@
define(function(require, exports, module) {
'use strict';
var create = require('template').create;
var localCalendarId = require('common/constants').localCalendarId;
module.exports = create({
item: function() {
var id = this.h('_id');
var color = this.h('color');
var l10n = '';
var name = '';
// localize only the default calendar; there is no need to set the name
// the [data-l10n-id] will take care of setting the proper value
if (id && localCalendarId === id) {
// localize the default calendar name
l10n = 'data-l10n-id="calendar-local"';
} else {
name = this.h('name');
}
var checked = this.bool('localDisplayed', 'checked');
return `<li id="calendar-${id}" role="presentation">
<div class="gaia-icon icon-calendar-dot" style="color:${color}"
aria-hidden="true"></div>
<gaia-checkbox class="invisible" value="${id}" ${checked}/>
<label ${l10n} class="name" dir="auto">${name}</label>
</gaia-checkbox>
</li>`;
}
});
});

View file

@ -0,0 +1,47 @@
define(function(require, exports, module) {
'use strict';
var Calc = require('common/calc');
var IntlHelper = require('shared/intl_helper');
var create = require('template').create;
module.exports = create({
time: function() {
var time = this.arg('time');
var format = this.h('format');
var formatter = IntlHelper.get(format);
var displayTime = formatter.format(time);
return `<span data-l10n-date-format="${format}"
data-date="${time}">${displayTime}</span>`;
},
hour: function() {
var hour = this.h('hour');
var format = this.h('format');
var className = this.h('className');
// 0ms since epoch as base date to avoid issues with daylight saving time
var date = new Date(0);
date.setHours(hour, 0, 0, 0);
var displayHour;
var formatter = IntlHelper.get(format);
if (this.arg('addAmPmClass')) {
displayHour = formatter.format(date, {
dayperiod: '<span class="ampm" aria-hidden="true">$&</span>',
});
} else {
displayHour = formatter.format(date);
}
var l10nAttr = (hour === Calc.ALLDAY) ?
'data-l10n-id="hour-allday"' :
`data-l10n-date-format="${format}"`;
return `<span class="${className}" data-date="${date}"
${l10nAttr}>${displayHour}</span>`;
}
});
});

View file

@ -0,0 +1,55 @@
define(function(require, exports, module) {
'use strict';
var Calc = require('common/calc');
var DateSpan = require('templates/date_span');
var create = require('template').create;
var l10n = navigator.mozL10n;
module.exports = create({
durationTime: function() {
var format = '';
var startDate = this.arg('startDate');
var endDate = this.arg('endDate');
var isAllDay = this.arg('isAllDay');
if (isAllDay) {
// Use the last second of previous day as the base for endDate
// (e.g., 1991-09-14T23:59:59 insteads of 1991-09-15T00:00:00).
endDate = new Date(endDate - 1000);
format = Calc.isSameDate(startDate, endDate) ?
'one-all-day-duration' :
'multiple-all-day-duration';
} else {
format = Calc.isSameDate(startDate, endDate) ?
'one-day-duration' :
'multiple-day-duration';
}
return l10n.get(format, {
startTime: formatTime(startDate),
startDate: formatDate(startDate),
endTime: formatTime(endDate),
endDate: formatDate(endDate)
});
}
});
function formatDate(date) {
return date.toLocaleString(navigator.languages, {
weekday: 'long',
month: 'long',
day: 'numeric',
year: 'numeric'
});
}
function formatTime(time) {
return DateSpan.time.render({
time: time,
format: 'shortTimeFormat'
});
}
});

View file

@ -0,0 +1,56 @@
define(function(require, exports, module) {
'use strict';
var DateSpan = require('./date_span');
var create = require('template').create;
var MonthDayAgenda = create({
event: function() {
var busytimeId = this.h('busytimeId');
var color = this.h('color');
var eventTime;
if (this.arg('isAllDay')) {
eventTime = '<div class="all-day" data-l10n-id="hour-allday"></div>';
} else {
var startTime = formatTime(this.arg('startTime'));
var endTime = formatTime(this.arg('endTime'));
eventTime = `<div class="start-time">${startTime}</div>
<div class="end-time">${endTime}</div>`;
}
var title = this.h('title');
var eventDetails = `<h5 role="presentation" dir="auto">${title}</h5>`;
var location = this.h('location');
if (location && location.length > 0) {
eventDetails += `<span class="details" dir="auto">
<span class="location">${location}</span>
</span>`;
}
var alarmClass = this.arg('hasAlarms') ? 'has-alarms' : '';
return `<a href="/event/show/${busytimeId}/" class="event ${alarmClass}"
role="option" aria-describedby="${busytimeId}-icon-calendar-alarm">
<div class="container">
<div class="gaia-icon icon-calendar-dot" style="color:${color}"
aria-hidden="true"></div>
<div class="event-time">${eventTime}</div>
<div class="event-details">${eventDetails}</div>
<div id="${busytimeId}-icon-calendar-alarm" aria-hidden="true"
class="gaia-icon icon-calendar-alarm" style="color:${color}"
data-l10n-id="icon-calendar-alarm"></div>
</div>
</a>`;
}
});
module.exports = MonthDayAgenda;
function formatTime(time) {
return DateSpan.time.render({
time: time,
format: 'shortTimeFormat'
});
}
});

View file

@ -0,0 +1,96 @@
define(function(require, exports, module) {
'use strict';
var DateSpan = require('./date_span');
var colorUtils = require('utils/color');
var create = require('template').create;
var multiday = {};
multiday.hour = function() {
var hour = this.arg('hour');
var html = DateSpan.hour.render({
hour: hour,
format: this.arg('format'),
addAmPmClass: this.arg('addAmPmClass'),
className: 'md__display-hour'
});
// we use this temporary element just to grab the textContent
var tmp = document.createElement('div');
tmp.innerHTML = html;
var text = tmp.textContent;
return `<li aria-label="${text}" class="md__hour md__hour-${hour}">
${html}
</li>`;
};
multiday.day = function() {
return `<div class="md__day" data-date="${this.h('date')}"></div>`;
};
multiday.allday = function() {
return `<div class="md__allday" data-date="${this.h('date')}">
<h1 class="md__day-name" aria-level="2"
id="md__day-name-${this.h('id')}"></h1>
<div class="md__allday-events"></div>
</div>`;
};
multiday.event = function() {
var labels = [];
var id = this.h('id');
var instance = this.h('instance');
var color = this.h('color');
var bgColor = colorUtils.hexToBackground(color);
var titleId = `md__event-${id}-title-${instance}`;
labels.push(titleId);
var location = this.h('location');
var locationHtml = '';
if (location) {
var locationId = `md__event-${id}-location-${instance}`;
labels.push(locationId);
locationHtml = `<bdi class="md__event-location" id="${locationId}">
${location}
</bdi>`;
}
var alarmIcon = '';
if (this.arg('hasAlarms')) {
var iconId = `md__event-${id}-icon-${instance}`;
labels.push(iconId);
alarmIcon = `<i class="gaia-icon icon-calendar-alarm"
style="color: ${color}" aria-hidden="true" id="${iconId}"
data-l10n-id="icon-calendar-alarm">
</i>`;
}
var className = ['md__event'];
if (alarmIcon) {
className.push('has-alarms');
}
var descriptionId = `md__event-${id}-description-${instance}`;
labels.push(descriptionId);
return `<a href="/event/show/${id}"
class="${className.join(' ')}"
style="border-color: ${color}; background-color: ${bgColor}"
aria-labelledby="${labels.join(' ')}">
<bdi class="md__event-title" id="${titleId}">${this.h('title')}</bdi>
${locationHtml}
${alarmIcon}
<span id="${descriptionId}" aria-hidden="true"
data-l10n-id="${this.h('labelFormat')}"
data-l10n-args="${this.h('labelFormatArgs')}">
</span>
</a>`;
};
module.exports = create(multiday);
});