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 @@
;;;window.COMPONENTS_BASE_URL='/shared/elements/';

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,40 @@
/* Generated by grunt-webfont */
/* Based on https://github.com/endtwist/fontcustom/blob/master/lib/fontcustom/templates/fontcustom.css */
@font-face {
font-family: "gaia-icons";
src: url("fonts/gaia-icons.ttf") format("truetype");
font-weight: 500;
font-style: normal;
}
[data-icon]:before,
.ligature-icons {
font-family: "gaia-icons";
content: attr(data-icon);
display: inline-block;
font-weight: 500;
font-style: normal;
text-decoration: inherit;
text-transform: none;
text-rendering: optimizeLegibility;
font-size: 30px;
-webkit-font-smoothing: antialiased;
}
[data-icon]:not([data-l10n-id]):not([aria-label]):not([aria-hidden="true"]):before {
/* Highlight cases where icons are not localized and still visible to screen
reader */
background: rgba(255, 0, 0, 0.4);
}
[data-icon]:not([data-l10n-id]):not([aria-label]):not([aria-hidden="true"]):after {
background: #333;
color: #fff;
position: absolute;
width: 20rem;
border-radius: 0.5rem;
padding: 0.5rem;
content: "Icon is not localized and is still visible to screen reader. Please add data-l10n-id or aria-label for localization or use aria-hidden to hide the icon from screen reader.";
z-index: 9999;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 B

View file

@ -0,0 +1,62 @@
'use strict';
/* global ComponentUtils */
window.GaiaMenu = (function(win) {
// Extend from HTMLElement prototype
var proto = Object.create(HTMLElement.prototype);
// Allow baseurl to be overridden (used for demo page)
var baseurl = window.GaiaMenuBaseurl ||
'/shared/elements/gaia_menu/';
proto.createdCallback = function () {
var shadow = this.createShadowRoot();
this._template = template.content.cloneNode(true);
var cancelButton = this._template.querySelector('.gaia-menu-cancel button');
cancelButton.addEventListener('click', function () {
this.hide();
this.dispatchEvent(new CustomEvent('gaiamenu-cancel'));
}.bind(this));
shadow.appendChild(this._template);
ComponentUtils.style.call(this, baseurl);
document.l10n.ready.then(this.localize.bind(this));
document.addEventListener('DOMRetranslated', this.localize.bind(this));
};
proto.localize = function() {
document.l10n.formatValue('gaia-menu-cancel').then(value => {
this.shadowRoot.querySelector('button').textContent = value;
});
};
proto.show = function() {
this.removeAttribute('hidden');
};
proto.hide = function() {
this.setAttribute('hidden', 'hidden');
};
var template = document.createElement('template');
template.innerHTML =
`<form role="dialog" data-type="action">
<content select="header"></content>
<menu>
<content select="button"></content>
<span class="gaia-menu-cancel">
<button>Cancel</button>
</span>
</menu>
</form>`;
// Register and return the constructor
return document.registerElement('gaia-menu', { prototype: proto });
})(window);

View file

@ -0,0 +1,314 @@
/* ----------------------------------
* gaia_menu
* ---------------------------------- */
/* default alignment follows the UI direction, not the content direction */
:-moz-dir(ltr) [dir] { text-align: left; }
:-moz-dir(rtl) [dir] { text-align: right; }
/* Main dialog setup */
gaia-menu {
background-color: #2d2d2d;
overflow: hidden;
position: fixed;
z-index: 100;
top: 0;
left: 0;
right: 0;
bottom: 0;
padding: 0 0 7rem;
/**
* Using "font-size: 0" to avoid the unwanted visual space (about 3px) created
* by white spaces and line breaks in the code between inline-block elements.
*/
font-size: 0;
color: #fff;
display: block;
transition: transform ease-in-out var(--transition-duration),
visibility var(--transition-duration);
}
gaia-menu[hidden] {
transform: translateY(100%);
visibility: hidden;
}
gaia-menu:before {
content: '';
display: inline-block;
vertical-align: top;
width: 0.1rem;
height: 100%;
margin-inline-start: -0.1rem;
}
header {
-moz-box-sizing: border-box;
font-size: 1.6rem;
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 10;
height: 5rem;
line-height: 4.9rem;
color: #fff;
white-space: nowrap;
text-overflow: ellipsis;
display: block;
overflow: hidden;
font-weight: normal;
padding: 0 3rem;
border-bottom: 0.1rem solid #616262;
}
header h1 {
font-size: 1.6rem;
line-height: 4.9rem;
color: #fff;
white-space: nowrap;
text-overflow: ellipsis;
display: block;
overflow: hidden;
margin: 0;
height: 100%;
font-weight: normal;
}
/* Generic set of actions in toolbar */
header menu.toolbar {
height: 100%;
margin: 0 -3rem;
margin-inline-start: 1rem;
padding: 0;
}
header:-moz-dir(ltr) menu.toolbar { float: right; }
header:-moz-dir(rtl) menu.toolbar { float: left; }
header menu.toolbar a,
header menu.toolbar button {
-moz-box-sizing: border-box;
position: relative;
width: auto;
min-width: 5rem;
height: 4.9rem;
margin-bottom: 0;
padding: 0 1rem;
border-radius: 0;
line-height: 4.9rem;
background: none;
text-align: center;
text-shadow: none;
z-index: 5;
}
header:-moz-dir(ltr) menu.toolbar a,
header:-moz-dir(ltr) menu.toolbar button {
float: left;
}
header:-moz-dir(rtl) menu.toolbar a,
header:-moz-dir(rtl) menu.toolbar button {
float: right;
}
header a,
header button {
border: none;
padding: 0;
overflow: hidden;
font-weight: 400;
font-size: 1.5rem;
line-height: 1.1em;
color: #fff;
border-radius: 0;
text-decoration: none;
}
button::-moz-focus-inner {
outline: none;
border: none;
}
/* Pressed state */
header a:active .icon:after,
header button:active .icon:after,
header menu.toolbar a:active,
header menu.toolbar button:active {
background: #008aaa;
}
/* Disabled state */
header menu.toolbar a[aria-disabled="true"],
header menu.toolbar button[disabled] {
opacity: 0.5;
pointer-events: none;
}
/* Icon definitions */
header .icon {
position: relative;
float: none;
display: inline-block;
vertical-align: top;
width: 4rem;
height: 4.9rem;
margin: 0 -1rem;
background: transparent no-repeat center center / 3rem auto;
font-size: 0;
overflow: hidden;
}
header .icon.icon-close {
background-image: url(images/icons/close.png);
}
header .icon.icon-back {
background-image: url(images/icons/back.png);
}
/* Navigation links (back, cancel, etc) */
header > button,
header > a {
width: 5rem;
height: 4.9rem;
background: none;
overflow: visible;
margin: 0 -1rem;
margin-inline-start: -3rem;
position: relative;
}
header:-moz-dir(ltr) > button,
header:-moz-dir(ltr) > a {
float: left;
}
header:-moz-dir(rtl) > button,
header:-moz-dir(rtl) > a {
float: right;
}
header > button::-moz-focus-inner {
border: 0;
padding: 0;
}
header > button .icon,
header > a .icon {
position: static;
display: block;
width: 3rem;
height: 4.9rem;
margin: 0;
overflow: visible;
font-size: 0;
}
header > button .icon:after,
header > a .icon:after {
content: "";
position: absolute;
offset-inline-start: 0;
top: 0;
z-index: -1;
width: 3rem;
height: 4.9rem;
}
/* Content */
section {
color: #fff;
position: absolute;
top: 7rem;
left: 1.5rem;
right: 1.5rem;
bottom: 2rem;
font-size: 1.6rem;
overflow: scroll;
}
/* Specific component code */
menu {
margin: 0;
padding: 0;
max-height: calc(100% - 13.5rem); /*header(5rem) + footer(7rem) + padding(1.5rem)*/
height: auto;
padding-top: 1.5rem;
overflow: auto;
width: auto;
border: none;
background: none;
position: absolute;
left: 0;
right: 0;
bottom: 7rem;
}
button {
width: calc(100% - 3rem);
height: 4rem;
-moz-box-sizing: border-box;
vertical-align: middle;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
font-weight: normal;
line-height: 4rem;
outline: none;
font-size: 1.6rem;
text-shadow: none;
padding: 0 1.2rem;
margin: 0 1.5rem 1rem;
background: rgba(87, 87, 87, 0.8);
border: none;
border-radius: 0;
position: relative;
color: #fff;
font-family: sans-serif;
font-style: italic;
}
button:-moz-dir(ltr) { text-align: left; }
button:-moz-dir(rtl) { text-align: right; }
span.gaia-menu-cancel {
position: fixed;
width: 100%;
background: #4d4d4d;
height: 7rem;
offset-inline-start: 0;
bottom: 0;
}
span.gaia-menu-cancel button {
position: fixed;
bottom: 0;
offset-inline-start: 0;
color: #333;
background: #d8d8d8;
text-align: center;
border: none;
margin-bottom: 1.5rem;
border-radius: 2rem;
}
button:nth-last-child(2) {
margin-bottom: 1.5rem;
}
/* Press state */
button:active,
span.gaia-menu-cancel button:active {
background: #00aacc;
color: #fff;
}
/* Disabled */
button[disabled] {
background-color: rgba(87, 87, 87, 0.8);
color: rgba(255, 255, 255, 0.4);
opacity: 0.5;
pointer-events: none;
}
button[disabled]:last-child {
background-color: #e7e7e7;
color: #a6a6a6;
opacity: 1;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 B

View file

@ -0,0 +1,185 @@
'use strict';
/* global ComponentUtils, LazyLoader */
/**
* GaiaSimPicker is a helper for dynamically generating menus for selecting SIM
* cards when making calls, sending SMS, etc. It also returns any currently
* in-use SIMs if there is an active call, but only when an app has mozTelephony
* permissions.
*
* Dependencies: gaia-menu web component.
*/
window.GaiaSimPicker = (function(win) {
// Extend from HTMLElement prototype
var proto = Object.create(HTMLElement.prototype);
// Allow baseurl to be overridden (used for demo page)
var baseurl = window.GaiaSimPickerBaseurl ||
'/shared/elements/gaia_sim_picker/';
proto.createdCallback = function() {
var shadow = this.createShadowRoot();
shadow.innerHTML = template;
this._menu = this.shadowRoot.querySelector('gaia-menu');
/**
* Workaround for bug 1100912, to be removed when bug is fixed:
* set internal gaia-menu dir, that's enough for directional-specific
* CSS to kick in.
*/
var updateDir = () => {
this._menu.dir = document.dir || 'ltr';
};
updateDir();
window.addEventListener('localized', updateDir);
LazyLoader.load(['/shared/js/component_utils.js'], function() {
ComponentUtils.style.call(this, baseurl);
}.bind(this));
navigator.mozL10n.ready(this._localizeShadowDom.bind(this));
};
proto._domBuilt = false;
proto._simSelectedCallbacks = [];
proto._dispatchSimSelected = function(cardIndex) {
var simSelectedEvent = new CustomEvent('gaiasimpicker-simselected', {
canBubble: true,
cancelable: true,
detail: {
cardIndex: cardIndex
}
});
if (this.dispatchEvent(simSelectedEvent)) {
// Only call the stored callbacks if the event wasn't preventDefaulted.
proto._simSelectedCallbacks.forEach(function(callback) {
callback(cardIndex);
});
proto._simSelectedCallbacks = [];
}
};
/**
* Localize the component manually as l10n attributes are not supported
* within the shadow dom. See also: bug 1026236.
*/
proto._localizeShadowDom = function() {
navigator.mozL10n.translateFragment(this.shadowRoot);
};
proto.getOrPick = function(defaultCardIndex,
phoneNumber,
simSelectedCallback) {
if (simSelectedCallback) {
this._simSelectedCallbacks.push(simSelectedCallback);
}
if (window.TelephonyHelper) {
var inUseSim = window.TelephonyHelper.getInUseSim();
if (inUseSim !== null) {
this._dispatchSimSelected(inUseSim);
return;
}
}
var dialViaElt = this.shadowRoot.querySelector('#sim-picker-dial-via');
if (phoneNumber) {
navigator.mozL10n.setAttributes(dialViaElt,
'gaia-sim-picker-dial-via-with-number',
{phoneNumber: phoneNumber});
} else {
dialViaElt.setAttribute('data-l10n-id', 'gaia-sim-picker-select-sim');
}
this._buildDom();
this._localizeShadowDom();
var simButtons = this.shadowRoot.querySelectorAll(
'button[data-card-index]');
for (var i = 0; i < simButtons.length; i++) {
if (simButtons[i].dataset.cardIndex == defaultCardIndex) {
simButtons[i].classList.add('is-default');
} else {
simButtons[i].classList.remove('is-default');
}
}
// we want to wait for l10n to happen before we display the UI
LazyLoader.load(['/shared/elements/gaia_menu/script.js'], function() {
navigator.mozL10n.once(function() {
this._menu.show();
this.focus();
}.bind(this));
}.bind(this));
};
proto._buildDom = function() {
if (this._domBuilt) {
return;
}
this._domBuilt = true;
var templateNode = this.shadowRoot.querySelector(
'#sim-picker-button-template');
for (var i = 0; i < navigator.mozIccManager.iccIds.length; i++) {
var clonedNode = templateNode.cloneNode(true);
clonedNode.dataset.cardIndex = i;
clonedNode.addEventListener('click', this);
var button = clonedNode.querySelector('.js-sim-picker-button');
// For example only; l10n will overwrite this.
button.textContent = 'SIM' + (i+1);
navigator.mozL10n.setAttributes(
button, 'gaia-sim-picker-button', {n: i + 1});
templateNode.parentNode.insertBefore(clonedNode, templateNode);
}
templateNode.remove();
};
proto.handleEvent = function(e) {
if (e) {
e.preventDefault();
}
if (e.target.nodeName !== 'BUTTON') {
return;
}
if (e.target.dataset.cardIndex) {
this._dispatchSimSelected(parseInt(e.target.dataset.cardIndex));
} else {
// Clear the stored callbacks anyways since the user must have hit cancel.
this._simSelectedCallbacks = [];
}
this._menu.hide();
};
var stylesheet = baseurl + '../gaia_menu/style.css';
// TODO: We should make this a template node and use template.cloneNode, but
// nested web components don't work yet using this method.
var template = '<style scoped>' +
'@import url(' + stylesheet + ');</style>' +
`<gaia-menu hidden>
<header id="sim-picker-dial-via">Dial 12345 via</header>
<button id="sim-picker-button-template">
<span class="js-sim-picker-button">
SIMX
</span>
<span class="sim-default" data-l10n-id="gaia-sim-picker-button-default">
(default)
</span>
</button>
</gaia-menu>`;
// Register and return the constructor
return document.registerElement('gaia-sim-picker', { prototype: proto });
})(window);

View file

@ -0,0 +1,9 @@
.sim-default {
display: none;
margin-inline-start: 0.15rem;
font-style: italic;
}
.is-default .sim-default {
display: initial;
}