VulpesOS/assets/webapps/sms.gaiamobile.org/views/shared/js/dialog.js
OverSu b38dea0597 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.
2026-09-30 23:13:03 +02:00

165 lines
4.7 KiB
JavaScript

/*global WeakMap */
/* exported Dialog */
(function(exports) {
'use strict';
/*
Generic confirm screen. Only 'cancel/default' is mandatory.
Text fields are localized using commonly defined parameter structure:
https://developer.mozilla.org/en-US/Firefox_OS/Developing_Gaia/
localization_code_best_practices#Writing_APIs_that_operate_on_L10nIDs + 'raw'
can be Node aw well.
The constructor parameter should follow the following structure:
{
title: { raw: 'Non localizable title' },
body: {
id: 'localizableStringWithArgument',
args: { n: count }
},
classes: ['specific-class'], // optional
options: {
// Cancel is a mandatory option. You need to define at least the text.
cancel: {
text: 'localizableCancelLabel'
},
confirm: {
text: 'localizableRemoveLabel',
method: function(params) {
fooFunction(params);
},
params: [arg1, arg2,....],
className: 'optionalClassName'
}
}
*/
// helper to localize an element given parameters
function createLocalizedElement(tagName, valueL10n) {
var element = document.createElement(tagName);
// if we passed an l10nId, use the l10n `setAttributes' method
if (typeof valueL10n === 'string') {
element.setAttribute('data-l10n-id', valueL10n);
} else if (valueL10n.id) {
document.l10n.setAttributes(element, valueL10n.id, valueL10n.args);
// if we passed in a HTML Fragment, it is already localized
} else if (valueL10n.raw && valueL10n.raw.nodeType) {
element.appendChild(valueL10n.raw);
// otherwise - stuff text in here...
} else {
element.textContent = valueL10n.raw;
}
return element;
}
var Dialog = function(params) {
// We need, at least, one cancel option string
if (!params || !params.options || !params.options.cancel) {
return;
}
var handlers = new WeakMap();
// Create the structure
this.form = document.createElement('form');
this.form.dataset.type = 'confirm';
this.form.setAttribute('role', 'dialog');
this.form.tabIndex = -1;
// Pick up option_menu.css styling
this.form.dataset.subtype = 'menu';
if (params.classes) {
this.form.classList.add(...params.classes);
}
var infoSection = document.createElement('section');
infoSection.appendChild(createLocalizedElement('h1', params.title));
infoSection.appendChild(createLocalizedElement('p', params.body));
this.form.appendChild(infoSection);
// Adding options. In this case we have a maximum of 2, with different styles
// per button
var menu = document.createElement('menu');
// Default button (Cancel button). It's mandatory
var cancelOption = params.options.cancel;
var cancelButton = createLocalizedElement('button', cancelOption.text);
handlers.set(cancelButton, cancelOption);
// If we have only button, let's mark it as recommended action.
if (!params.options.confirm) {
cancelButton.className = 'recommend';
}
menu.appendChild(cancelButton);
if (params.options.confirm) {
var confirmOption = params.options.confirm;
var confirmButton = createLocalizedElement('button', confirmOption.text);
confirmButton.className = params.options.confirm.className || 'recommend';
handlers.set(confirmButton, confirmOption);
menu.appendChild(confirmButton);
}
this.form.addEventListener('submit', function(event) {
event.preventDefault();
});
this.form.addEventListener('transitionend', function(event) {
var form = event.target;
if (!form.classList.contains('visible') && form.parentNode) {
form.remove();
} else {
// Focus form for accessibility
form.focus();
}
document.body.classList.remove('dialog-animating');
});
menu.addEventListener('click', function(event) {
var action = handlers.get(event.target);
if (!action) {
return;
}
if (action.method) {
// Delegate operation to target method. This allows
// for a custom "Cancel" to be provided by calling program
action.method.apply(null, action.params || []);
}
// Hide action menu when click is received
this.hide();
}.bind(this));
// Appending the action menu to the form
this.form.appendChild(menu);
};
// We prototype functions to show/hide the UI of action-menu
Dialog.prototype.show = function() {
// Remove the focus to hide the keyboard asap
document.activeElement && document.activeElement.blur();
if (!this.form.parentNode) {
document.body.appendChild(this.form);
// Flush style on form so that the show transition plays once we add
// the visible class.
this.form.clientTop;
}
this.form.classList.add('visible');
document.body.classList.add('dialog-animating');
};
Dialog.prototype.hide = function() {
this.form.classList.remove('visible');
};
exports.Dialog = Dialog;
// end global closure
}(this));