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,488 @@
/* global BaseUI */
'use strict';
(function(exports) {
var _id = 0;
/**
* The ModalDialog of the AppWindow.
*
* Including **alert**, **prompt**, **confirm**, and
* **single select** dialogs.
*
* @class AppModalDialog
* @param {AppWindow} app The app window instance
* where this dialog should popup.
* @extends BaseUI
*/
var AppModalDialog = function AppModalDialog(app) {
this.app = app;
this.containerElement = app.element;
this.events = [];
// One to one mapping.
this.instanceID = _id++;
this._injected = false;
this._visible = false;
app.element.addEventListener('mozbrowsershowmodalprompt', this);
return this;
};
AppModalDialog.prototype = Object.create(BaseUI.prototype);
AppModalDialog.prototype.CLASS_NAME = 'AppModalDialog';
AppModalDialog.prototype.ELEMENT_PREFIX = 'modal-dialog-';
AppModalDialog.prototype.customID = function amd_customID() {
if (this.app) {
return '[' + this.app.origin + ']';
} else {
return '';
}
};
AppModalDialog.prototype.handleEvent = function amd_handleEvent(evt) {
this.app.debug('handling ' + evt.type);
evt.preventDefault();
evt.stopPropagation();
this.events.push(evt);
this.menuHeight = 0;
if (!this._injected) {
this.render();
}
this.show();
this._injected = true;
};
AppModalDialog.prototype.isVisible = function amd_isVisible() {
return this._visible;
};
AppModalDialog.prototype._fetchElements = function amd__fetchElements() {
this.element = document.getElementById(this.CLASS_NAME + this.instanceID);
this.elements = {};
var toCamelCase = function toCamelCase(str) {
return str.replace(/\-(.)/g, function replacer(str, p1) {
return p1.toUpperCase();
});
};
this.elementClasses = ['alert', 'alert-ok', 'alert-message',
'prompt', 'prompt-ok', 'prompt-cancel', 'prompt-input', 'prompt-message',
'confirm', 'confirm-ok', 'confirm-cancel', 'confirm-message',
'select-one', 'select-one-cancel', 'select-one-menu', 'select-one-title',
'alert-title', 'confirm-title', 'prompt-title',
'custom-prompt', 'custom-prompt-message', 'custom-prompt-buttons',
'custom-prompt-checkbox'];
// Loop and add element with camel style name to Modal Dialog attribute.
this.elementClasses.forEach(function createElementRef(name) {
this.elements[toCamelCase(name)] =
this.element.querySelector('.' + this.ELEMENT_PREFIX + name);
}, this);
this.elements.menu = this.element.querySelector('menu');
};
AppModalDialog.prototype._registerEvents = function amd__registerEvents() {
var elements = this.elements;
for (var id in elements) {
var tagName = elements[id].tagName.toLowerCase();
if (tagName == 'button' || tagName == 'ul') {
if (elements[id].classList.contains('confirm')) {
elements[id].addEventListener('click',
this.confirmHandler.bind(this));
} else if (elements[id].classList.contains('cancel')) {
elements[id].addEventListener('click', this.cancelHandler.bind(this));
}
}
}
};
AppModalDialog.prototype.view = function amd_view() {
var id = this.CLASS_NAME + this.instanceID;
return `<div class="modal-dialog" id="${id}">
<form class="modal-dialog-alert generic-dialog"
role="dialog" tabindex="-1">
<div class="modal-dialog-message-container inner">
<h3 class="modal-dialog-alert-title"></h3>
<p>
<span class="modal-dialog-alert-message"></span>
</p>
</div>
<menu>
<button type="submit"
class="modal-dialog-alert-ok confirm affirmative"
data-l10n-id="ok">Value for Marionette (see bug 1224063)</button>
</menu>
</form>
<form class="modal-dialog-confirm generic-dialog"
role="dialog" tabindex="-1">
<div class="modal-dialog-message-container inner">
<h3 class="modal-dialog-confirm-title"></h3>
<p>
<span class="modal-dialog-confirm-message"></span>
</p>
</div>
<menu data-items="2">
<button type="button" class="modal-dialog-confirm-cancel cancel"
data-l10n-id="cancel"></button>
<button type="submit"
class="modal-dialog-confirm-ok confirm affirmative"
data-l10n-id="ok"></button>
</menu>
</form>
<form class="modal-dialog-prompt generic-dialog"
role="dialog" tabindex="-1">
<div class="modal-dialog-message-container inner">
<h3 class="modal-dialog-prompt-title"></h3>
<p>
<span class="modal-dialog-prompt-message"></span>
<input class="modal-dialog-prompt-input" />
</p>
</div>
<menu data-items="2">
<button type="button" class="modal-dialog-prompt-cancel cancel"
data-l10n-id="cancel"></button>
<button type="submit"
class="modal-dialog-prompt-ok confirm affirmative"
data-l10n-id="ok"></button>
</menu>
</form>
<form class="modal-dialog-select-one generic-dialog"
role="dialog" tabindex="-1">
<div class="modal-dialog-message-container inner">
<h3 class="modal-dialog-select-one-title"></h3>
<ul class="modal-dialog-select-one-menu"></ul>
</div>
<menu>
<button type="submit"
class="modal-dialog-select-one-cancel cancel"
data-l10n-id="cancel"></button>
</menu>
</form>
<form class="modal-dialog-custom-prompt generic-dialog"
role="dialog" tabindex="-1">
<div class="modal-dialog-message-container inner">
<h3 class="modal-dialog-custom-prompt-title"></h3>
<p class="modal-dialog-custom-prompt-message"></p>
<gaia-checkbox class="modal-dialog-custom-prompt-checkbox">
<label></label>
</gaia-checkbox>
</div>
<menu class="modal-dialog-custom-prompt-buttons"></menu>
</form>
</div>`;
};
AppModalDialog.prototype.processNextEvent = function amd_processNextEvent() {
this.events.splice(0, 1);
if (this.events.length) {
this.show();
} else {
this.hide();
}
};
AppModalDialog.prototype.kill = function amd_kill() {
this._visible = false;
this.containerElement.removeChild(this.element);
};
// Show relative dialog and set message/input value well
AppModalDialog.prototype.show = function amd_show() {
if (!this.events.length) {
return;
}
this._visible = true;
var evt = this.events[0];
var message = evt.detail.message || '';
var title = this._getTitle(evt.detail.title);
var elements = this.elements;
var type = evt.detail.promptType || evt.detail.type;
switch (type) {
case 'alert':
elements.alertTitle.textContent = title;
elements.alertMessage.textContent = message;
elements.alert.classList.add('visible');
if (evt.yesText) {
elements.alertOk.removeAttribute('data-l10n-id');
elements.alertOk.textContent = evt.yesText;
} else {
elements.alertOk.setAttribute('data-l10n-id', 'ok');
}
elements.alert.focus();
this.updateMaxHeight();
break;
case 'prompt':
elements.prompt.classList.add('visible');
elements.promptInput.value = evt.detail.initialValue;
elements.promptTitle.textContent = title;
elements.promptMessage.textContent = message;
if (evt.yesText) {
elements.promptOk.removeAttribute('data-l10n-id');
elements.promptOk.textContent = evt.yesText;
} else {
elements.promptOk.setAttribute('data-l10n-id', 'ok');
}
if (evt.noText) {
elements.promptCancel.removeAttribute('data-l10n-id');
elements.promptCancel.textContent = evt.noText;
} else {
elements.promptCancel.setAttribute('data-l10n-id', 'cancel');
}
elements.prompt.focus();
break;
case 'confirm':
elements.confirm.classList.add('visible');
elements.confirmTitle.textContent = title;
elements.confirmMessage.textContent = message;
if (evt.yesText) {
elements.confirmOk.removeAttribute('data-l10n-id');
elements.confirmOk.textContent = evt.yesText;
} else {
elements.confirmOk.setAttribute('data-l10n-id', 'ok');
}
if (evt.noText) {
elements.confirmCancel.removeAttribute('data-l10n-id');
elements.confirmCancel.textContent = evt.noText;
} else {
elements.confirmCancel.setAttribute('data-l10n-id', 'cancel');
}
elements.confirm.focus();
break;
case 'selectone':
this.buildSelectOneDialog(message);
elements.selectOne.classList.add('visible');
elements.selectOne.focus();
break;
case 'custom-prompt':
var customPrompt = evt.detail;
elements.customPrompt.classList.add('visible');
elements.customPromptMessage.textContent = customPrompt.message;
// Display custom list of buttons
elements.customPromptButtons.innerHTML = '';
elements.customPromptButtons.setAttribute('data-items',
customPrompt.buttons.length);
var domElement = null;
for (var i = customPrompt.buttons.length - 1; i >= 0; i--) {
var button = customPrompt.buttons[i];
domElement = document.createElement('button');
domElement.dataset.buttonIndex = i;
if (button.messageType === 'builtin') {
domElement.setAttribute('data-l10n-id', button.message);
} else if (button.messageType === 'custom') {
// For custom button, we assume that the text is already translated
domElement.textContent = button.message;
} else {
console.error('Unexpected button type : ' + button.messageType);
continue;
}
domElement.addEventListener('click', this.confirmHandler.bind(this));
elements.customPromptButtons.appendChild(domElement);
}
domElement.classList.add('affirmative');
// Eventualy display a checkbox:
var checkbox = elements.customPromptCheckbox;
if (customPrompt.showCheckbox) {
if (customPrompt.checkboxCheckedByDefault) {
checkbox.checked = true;
} else {
checkbox.checked = false;
}
// We assume that checkbox custom message is already translated
checkbox.querySelector('label').textContent =
customPrompt.checkboxMessage;
} else {
checkbox.style.display = 'none';
}
elements.customPrompt.focus();
break;
}
this.app.browser.element.setAttribute('aria-hidden', true);
this.element.classList.add('visible');
};
AppModalDialog.prototype.hide = function amd_hide() {
this._visible = false;
this.element.blur();
this.app.browser.element.removeAttribute('aria-hidden');
this.element.classList.remove('visible');
if (this.app) {
this.app.focus();
}
if (!this.events.length) {
return;
}
var evt = this.events[0];
var type = evt.detail.promptType || evt.detail.type;
if (type === 'prompt') {
this.elements.promptInput.blur();
}
this.elements[type].classList.remove('visible');
};
// When user clicks OK button on alert/confirm/prompt
AppModalDialog.prototype.confirmHandler =
function amd_confirmHandler(clickEvt) {
if (!this.events.length) {
return;
}
clickEvt.preventDefault();
var elements = this.elements;
var evt = this.events[0];
var type = evt.detail.promptType || evt.detail.type;
switch (type) {
case 'alert':
elements.alert.classList.remove('visible');
break;
case 'prompt':
evt.detail.returnValue = elements.promptInput.value;
elements.prompt.classList.remove('visible');
break;
case 'confirm':
evt.detail.returnValue = true;
elements.confirm.classList.remove('visible');
break;
case 'custom-prompt':
var returnValue = {
selectedButton: clickEvt.target.dataset.buttonIndex
};
if (evt.detail.showCheckbox) {
returnValue.checked = elements.customPromptCheckbox.checked;
}
evt.detail.returnValue = returnValue;
elements.customPrompt.classList.remove('visible');
break;
}
if (evt.detail.unblock) {
evt.detail.unblock();
}
this.processNextEvent();
};
// When user clicks cancel button on confirm/prompt or
// when the user try to escape the dialog with the escape key
AppModalDialog.prototype.cancelHandler =
function amd_cancelHandler(clickEvt) {
if (!this.events.length) {
return;
}
clickEvt.preventDefault();
var evt = this.events[0];
var elements = this.elements;
var type = evt.detail.promptType || evt.detail.type;
switch (type) {
case 'alert':
elements.alert.classList.remove('visible');
break;
case 'prompt':
/* return null when click cancel */
evt.detail.returnValue = null;
elements.prompt.classList.remove('visible');
break;
case 'confirm':
/* return false when click cancel */
evt.detail.returnValue = false;
elements.confirm.classList.remove('visible');
break;
case 'selectone':
/* return null when click cancel */
evt.detail.returnValue = null;
elements.selectOne.classList.remove('visible');
break;
}
if (evt.detail.unblock) {
evt.detail.unblock();
}
this.processNextEvent();
};
// When user selects an option on selectone dialog
AppModalDialog.prototype.selectOneHandler =
function amd_selectOneHandler(target) {
if (!this.events.length) {
return;
}
var elements = this.elements;
var evt = this.events[0];
evt.detail.returnValue = target.id;
elements.selectOne.classList.remove('visible');
if (evt.detail.unblock) {
evt.detail.unblock();
}
this.processNextEvent();
};
AppModalDialog.prototype.updateMaxHeight = function() {
// Setting maxHeight for being able to scroll long
// texts: formHeight - menuHeight - titleHeight - margin
// We should fix this in a common way for all the dialogs
// in the building blocks layer: Bug 1096902
this.menuHeight = this.menuHeight || this.elements.menu.offsetHeight;
var messageHeight = this.element.offsetHeight - this.menuHeight;
messageHeight -= this.elements.alertTitle.offsetHeight;
var margin = window.getComputedStyle(this.elements.alertTitle).marginBottom;
var messageContainer = this.elements.alert.querySelector('.inner p');
var calc = 'calc(' + messageHeight + 'px - ' + margin + ')';
messageContainer.style.maxHeight = calc;
};
AppModalDialog.prototype._getTitle =
function amd__getTitle(title) {
//
// XXX Bug 982006, subsystems like uriloader still report errors with
// titles which are important to the user for context in diagnosing
// issues.
//
// However, we will ignore all titles containing a URL using the app
// protocol. These types of titles simply indicate that the active
// application is prompting and are more confusing to the user than
// useful. Instead we will return the application name if there is one
// or an empty string.
//
if (!title ||
title.includes('app://')) {
return this.app.name || '';
}
return title;
};
exports.AppModalDialog = AppModalDialog;
}(window));