Release Vulpes OS 2.7-preview.24
42
overrides/marketplace.gaiamobile.org/marketplace.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
(async()=>{
|
||||
const frame=document.getElementById('catalogue'),message=document.getElementById('message'),dialog=document.getElementById('confirm');
|
||||
let attempt=0,busy=false,prepared=null,installed=null,language=await VulpesCompat.call('locale.current');
|
||||
const fr=()=>/^fr(?:-|$)/i.test(language);
|
||||
const text=(f,e)=>fr()?f:e;
|
||||
function labels(){document.getElementById('browse').textContent=text('Ouvrir le catalogue','Open catalogue');document.getElementById('open').textContent=text('Ouvrir','Open');document.getElementById('install').textContent=text('Installer','Install');document.getElementById('cancel').textContent=text('Annuler','Cancel');}
|
||||
function loadFailed(){status(text('Catalogue inaccessible. Vérifiez la connexion Internet, puis réessayez.','Catalogue unavailable. Check your Internet connection, then try again.'));document.getElementById('open').hidden=true;}
|
||||
frame.addEventListener('mozbrowsererror',loadFailed);
|
||||
frame.addEventListener('mozbrowserclose',()=>{
|
||||
if(busy)return;
|
||||
status(text('Le catalogue est fermé. Vous pouvez le rouvrir ci-dessous.',
|
||||
'The catalogue is closed. You can reopen it below.'));
|
||||
document.getElementById('open').hidden=true;
|
||||
});
|
||||
let catalogueUrl='';
|
||||
function browse(reload=false){labels();message.hidden=true;dialog.hidden=true;frame.style.visibility='visible';const next='https://vulpes-os.org/marketplace/?mode=app&lang='+(fr()?'fr':'en');if(reload||!catalogueUrl){catalogueUrl=next;frame.src=next;}}
|
||||
function status(value){frame.style.visibility='hidden';message.hidden=false;document.getElementById('status').textContent=value;}
|
||||
async function prepare(url){
|
||||
if(busy)return;const current=++attempt;busy=true;prepared=null;installed=null;document.getElementById('open').hidden=true;
|
||||
status(text('Vérification de l’application…','Checking application…'));
|
||||
try {const value=await VulpesCompat.call('marketplace.prepare',{url});if(current!==attempt)return;prepared=value;
|
||||
document.getElementById('title').textContent=prepared.name;
|
||||
document.getElementById('question').textContent=text('Installer cette application archivée ?','Install this archived application?')+' ('+(prepared.bytes/1048576).toFixed(1)+' Mio)';
|
||||
document.getElementById('permissions').textContent=text('Elle sera exécutée comme une application web, sans accès aux fonctions système. Certains anciens services peuvent ne plus fonctionner.','It will run as a web application without system access. Some old services may no longer work.');
|
||||
message.hidden=true;dialog.hidden=false;
|
||||
}catch(error){if(current!==attempt)return;status(error.message==='PRIVILEGED_APP_UNSUPPORTED'?
|
||||
text('Cette application demande des API privilégiées qui ne sont pas disponibles dans Vulpes OS.',
|
||||
'This app requires privileged APIs that are not available in Vulpes OS.'):
|
||||
text('Installation impossible : ','Cannot install: ')+error.message);busy=false;}
|
||||
}
|
||||
dialog.addEventListener('submit',async event=>{event.preventDefault();if(!prepared)return;const token=prepared.token;prepared=null;dialog.hidden=true;status(text('Installation…','Installing…'));
|
||||
try {installed=await VulpesCompat.call('marketplace.install',{token});status(text('Application ajoutée à l’accueil.','Application added to Home.'));document.getElementById('open').hidden=false;}
|
||||
catch(error){status(text('Installation impossible : ','Cannot install: ')+error.message);}finally{busy=false;}
|
||||
});
|
||||
const cancel=()=>{attempt++;prepared=null;busy=false;VulpesCompat.call('marketplace.cancel').catch(console.error);browse();};
|
||||
document.getElementById('cancel').onclick=cancel;
|
||||
document.getElementById('browse').onclick=cancel;
|
||||
document.getElementById('open').onclick=()=>installed && VulpesCompat.call('apps.launch',{manifestURL:installed.manifestURL});
|
||||
addEventListener('languagechange',()=>{language=navigator.language;if(!busy)browse(true);});
|
||||
browse();
|
||||
setInterval(async()=>{if(busy)return;try{const url=await VulpesCompat.call('marketplace.poll');if(url)await prepare(url);}catch(error){console.error(error);}},750);
|
||||
})();
|
||||
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
|
@ -0,0 +1,366 @@
|
|||
|
||||
define('modules/navigator/mozPermissionSettings',[],function(){'use strict';return window.navigator.mozPermissionSettings;});define('panels/app_permissions_list/app_permissions_list',["require", "modules/settings_service", "shared/manifest_helper", "modules/apps_cache", "modules/navigator/mozApps", "modules/navigator/mozPermissionSettings"],function(require) {
|
||||
'use strict';
|
||||
|
||||
var SettingsService = require('modules/settings_service');
|
||||
var ManifestHelper = require('shared/manifest_helper');
|
||||
var AppsCache = require('modules/apps_cache');
|
||||
var mozApps = require('modules/navigator/mozApps');
|
||||
var mozPerms = require('modules/navigator/mozPermissionSettings');
|
||||
|
||||
var PermissionsList = function pl() {
|
||||
this._listRoot = null;
|
||||
this._permissionsTable = null;
|
||||
this._permissionTableHaveProcessed = false;
|
||||
this._apps = null;
|
||||
this._enabled = false;
|
||||
};
|
||||
|
||||
PermissionsList.prototype = {
|
||||
/**
|
||||
* initialization
|
||||
*
|
||||
* @memberOf PermissionsList
|
||||
* @param {HTMLElement} listRoot
|
||||
* @access public
|
||||
*/
|
||||
init: function pl_init(listRoot) {
|
||||
this._listRoot = listRoot;
|
||||
|
||||
this._boundOnAppChoose = this._onAppChoose.bind(this);
|
||||
this._boundOnApplicationInstall = this._onApplicationInstall.bind(this);
|
||||
this._boundOnApplicationUninstall =
|
||||
this._onApplicationUninstall.bind(this);
|
||||
},
|
||||
|
||||
set enabled(value) {
|
||||
if (value !== this._enabled) {
|
||||
this._enabled = value;
|
||||
if (this._enabled) {
|
||||
this._bindEvents();
|
||||
} else {
|
||||
this._unbindEvents();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_bindEvents: function pl__bindEvents() {
|
||||
this._listRoot.addEventListener('click', this._boundOnAppChoose);
|
||||
AppsCache.addEventListener('oninstall', this._boundOnApplicationInstall);
|
||||
AppsCache.addEventListener('onuninstall',
|
||||
this._boundOnApplicationUninstall);
|
||||
},
|
||||
|
||||
_unbindEvents: function pl__unbindEvents() {
|
||||
this._listRoot.removeEventListener('click', this._boundOnAppChoose);
|
||||
AppsCache.removeEventListener('oninstall',
|
||||
this._boundOnApplicationInstall);
|
||||
AppsCache.removeEventListener('onuninstall',
|
||||
this._boundOnApplicationUninstall);
|
||||
},
|
||||
|
||||
/**
|
||||
* Set /resources/permissions_table.json.
|
||||
*
|
||||
* @memberOf PermissionsList
|
||||
* @param {Object} permissionTable
|
||||
* @access public
|
||||
*/
|
||||
setPermissionsTable: function pl_setPermissionsTable(permissionTable) {
|
||||
this._permissionTable = permissionTable;
|
||||
},
|
||||
|
||||
/**
|
||||
* Refresh the app list when we enter into panel.
|
||||
*
|
||||
* @memberOf PermissionsList
|
||||
* @access public
|
||||
* @return {Promise}
|
||||
*/
|
||||
refresh: function pl_refresh() {
|
||||
var self = this;
|
||||
this._apps = [];
|
||||
if (this._permissionTableHaveProcessed) {
|
||||
return this.loadApps();
|
||||
} else {
|
||||
return mozApps.getSelf().then(function(app) {
|
||||
return self._initExplicitPermissionsTable(app);
|
||||
}).then(function() {
|
||||
return self.loadApps();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Go to app_permissions_detail panel when user select an app.
|
||||
*
|
||||
* @memberOf PermissionsList
|
||||
* @param {Event} evt
|
||||
* @access public
|
||||
*/
|
||||
_onAppChoose: function pl__onAppChoose(evt) {
|
||||
var target = evt.target.closest('[data-app-index]');
|
||||
if (target && this._listRoot.contains(target)) {
|
||||
SettingsService.navigate('appPermissions-details', {
|
||||
app: this._apps[target.dataset.appIndex],
|
||||
permissionsTable: this._permissionTable
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* When new application is installed, we push the app to list, sort them and
|
||||
* rerender the app list.
|
||||
*
|
||||
* @memberOf PermissionsList
|
||||
* @param {Event} evt
|
||||
* @access public
|
||||
*/
|
||||
_onApplicationInstall: function pl__onApplicationInstall(evt) {
|
||||
var app = evt.application;
|
||||
this._apps.push(app);
|
||||
this._sortApps();
|
||||
this.renderList();
|
||||
},
|
||||
|
||||
/**
|
||||
* When application is uninstalled, we remove it from list and rerender the
|
||||
* app list.
|
||||
*
|
||||
* @memberOf PermissionsList
|
||||
* @param {Event} evt
|
||||
* @access public
|
||||
*/
|
||||
_onApplicationUninstall: function pl__onApplicationUninstall(evt) {
|
||||
var app;
|
||||
var appIndex;
|
||||
this._apps.some(function findApp(anApp, index) {
|
||||
if (anApp.origin === evt.application.origin) {
|
||||
app = anApp;
|
||||
appIndex = index;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (!app) {
|
||||
return;
|
||||
}
|
||||
SettingsService.navigate('appPermissions');
|
||||
this._apps.splice(appIndex, 1);
|
||||
this.renderList();
|
||||
},
|
||||
|
||||
/**
|
||||
* Sort the applist by the name of its manifest.
|
||||
*
|
||||
* @memberOf PermissionsList
|
||||
* @access private
|
||||
*/
|
||||
_sortApps: function pl__sortApps() {
|
||||
this._apps.sort(function alphabeticalSort(app, otherApp) {
|
||||
var manifest = new ManifestHelper(app.manifest ?
|
||||
app.manifest : app.updateManifest);
|
||||
var otherManifest = new ManifestHelper(otherApp.manifest ?
|
||||
otherApp.manifest : otherApp.updateManifest);
|
||||
return manifest.name > otherManifest.name;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Genrate UI template of app item.
|
||||
*
|
||||
* @memberOf PermissionsList
|
||||
* @access private
|
||||
* @param {Object} itemData
|
||||
* @return {HTMLDivElement}
|
||||
*/
|
||||
_genAppItemTemplate: function pl__genAppItemTemplate(itemData) {
|
||||
var icon = document.createElement('img');
|
||||
var item = document.createElement('li');
|
||||
var link = document.createElement('a');
|
||||
var span = document.createElement('span');
|
||||
span.textContent = itemData.name;
|
||||
span.dir = 'auto';
|
||||
icon.src = itemData.iconSrc;
|
||||
link.dataset.appIndex = itemData.index;
|
||||
link.href = '#';
|
||||
link.classList.add('menu-item');
|
||||
link.appendChild(icon);
|
||||
link.appendChild(span);
|
||||
item.appendChild(link);
|
||||
return item;
|
||||
},
|
||||
|
||||
/**
|
||||
* Genrate UI template of app item.
|
||||
*
|
||||
* @memberOf PermissionsList
|
||||
* @access public
|
||||
*/
|
||||
renderList: function pl_renderList() {
|
||||
this._listRoot.innerHTML = '';
|
||||
var listFragment = document.createDocumentFragment();
|
||||
this._apps.forEach(function appIterator(app, index) {
|
||||
var manifest = new ManifestHelper(app.manifest ?
|
||||
app.manifest : app.updateManifest);
|
||||
var li = this._genAppItemTemplate({
|
||||
name: manifest.displayName,
|
||||
index: index,
|
||||
iconSrc: this._getBestIconURL(app, manifest.icons)
|
||||
});
|
||||
listFragment.appendChild(li);
|
||||
}.bind(this));
|
||||
this._listRoot.appendChild(listFragment);
|
||||
},
|
||||
|
||||
/**
|
||||
* Genrate explicitCertifiedPermissions table from plainPermissions table
|
||||
* table and "composedPermissions + accessModes" table.
|
||||
*
|
||||
* @memberOf PermissionsList
|
||||
* @param {Event} evt
|
||||
* @access private
|
||||
*/
|
||||
_initExplicitPermissionsTable:
|
||||
function pl__initExplicitPermissionsTable(app) {
|
||||
this._currentApp = app;
|
||||
|
||||
var table = this._permissionTable;
|
||||
table.explicitCertifiedPermissions = [];
|
||||
table.plainPermissions.forEach(function plainPermIterator(perm) {
|
||||
if (this._isExplicitPerm(perm)) {
|
||||
table.explicitCertifiedPermissions.push({
|
||||
explicitPermission: perm,
|
||||
permission: perm
|
||||
});
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
table.composedPermissions.forEach(function permIterator(perm) {
|
||||
table.accessModes.forEach(function modeIterator(mode) {
|
||||
var composedPerm = perm + '-' + mode;
|
||||
if (this._isExplicitPerm(composedPerm)) {
|
||||
table.explicitCertifiedPermissions.push({
|
||||
explicitPermission: composedPerm,
|
||||
permission: perm
|
||||
});
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
this._permissionTableHaveProcessed = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Identify the permission whether is explict or not.
|
||||
*
|
||||
* @memberOf PermissionsList
|
||||
* @access private
|
||||
* @return {Bool}
|
||||
*/
|
||||
_isExplicitPerm: function pl_isExplicitPerm(perm) {
|
||||
return mozPerms && mozPerms.isExplicit(perm, this._currentApp.manifestURL,
|
||||
this._currentApp.origin, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Filter explicit apps from moz apps, sort them, and render to screen.
|
||||
*
|
||||
* @memberOf PermissionsList
|
||||
* @access public
|
||||
* @return {Promise}
|
||||
*/
|
||||
loadApps: function pl_loadApps() {
|
||||
var self = this;
|
||||
return AppsCache.apps().then(function(apps) {
|
||||
self._loadApps(apps);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Iterate internal apps and render them on UI.
|
||||
*
|
||||
* @memberOf PermissionsList
|
||||
* @param {Object[]} apps
|
||||
* @access private
|
||||
*/
|
||||
_loadApps: function pl__loadApps(apps) {
|
||||
var table = this._permissionTable;
|
||||
var internalRoles = ['system', 'input', 'homescreen', 'search', 'addon', 'langpack'];
|
||||
apps.forEach(function(app) {
|
||||
var manifest = app.manifest ? app.manifest : app.updateManifest;
|
||||
if (manifest.role && internalRoles.indexOf(manifest.role) !== -1) {
|
||||
return;
|
||||
}
|
||||
if (manifest.type != 'certified') {
|
||||
this._apps.push(app);
|
||||
return;
|
||||
}
|
||||
|
||||
var display = table.explicitCertifiedPermissions
|
||||
.some(function iterator(perm) {
|
||||
var permInfo = mozPerms.get(perm.explicitPermission,
|
||||
app.manifestURL, app.origin, false);
|
||||
return permInfo != 'unknown';
|
||||
}.bind(this));
|
||||
|
||||
if (display) {
|
||||
this._apps.push(app);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this._sortApps();
|
||||
this.renderList();
|
||||
},
|
||||
|
||||
/**
|
||||
* Get icon URL.
|
||||
*
|
||||
* @memberOf PermissionsList
|
||||
* @param {Object} app
|
||||
* @param {Object} icons
|
||||
* @access private
|
||||
*/
|
||||
_getBestIconURL: function pl__getBestIconURL(app, icons) {
|
||||
if (!icons || !Object.keys(icons).length) {
|
||||
return '../style/images/default.png';
|
||||
}
|
||||
|
||||
// The preferred size is 30 by the default. If we use HDPI device, we may
|
||||
// use the image larger than 30 * 1.5 = 45 pixels.
|
||||
var preferredIconSize = 30 * (window.devicePixelRatio || 1);
|
||||
var preferredSize = Number.MAX_VALUE;
|
||||
var max = 0;
|
||||
|
||||
for (var size in icons) {
|
||||
size = parseInt(size, 10);
|
||||
if (size > max) {
|
||||
max = size;
|
||||
}
|
||||
|
||||
if (size >= preferredIconSize && size < preferredSize) {
|
||||
preferredSize = size;
|
||||
}
|
||||
}
|
||||
// If there is an icon matching the preferred size, we return the result,
|
||||
// if there isn't, we will return the maximum available size.
|
||||
if (preferredSize === Number.MAX_VALUE) {
|
||||
preferredSize = max;
|
||||
}
|
||||
|
||||
var url = icons[preferredSize];
|
||||
|
||||
if (url) {
|
||||
return !(/^(http|https|data):/.test(url)) ? app.origin + url : url;
|
||||
} else {
|
||||
return '../style/images/default.png';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return function ctor_permissions_list() {
|
||||
return new PermissionsList();
|
||||
};
|
||||
});
|
||||
define('panels/app_permissions_list/panel',['require','modules/settings_panel','panels/app_permissions_list/app_permissions_list','shared/lazy_loader'],function(require){'use strict';var SettingsPanel=require('modules/settings_panel');var PermissionList=require('panels/app_permissions_list/app_permissions_list');var LazyLoader=require('shared/lazy_loader');return function ctor_app_permissions_list_panel(){var permissionsTableHasBeenLoaded=false;var elements={};var permissionListModule=PermissionList();return SettingsPanel({onInit:function(panel){elements={list:panel.querySelector('.app-list')};permissionListModule.init(elements.list);},onBeforeShow:function(){if(permissionsTableHasBeenLoaded){permissionListModule.refresh();}else{LazyLoader.getJSON('/resources/permissions_table.json').then(function(data){permissionsTableHasBeenLoaded=true;permissionListModule.setPermissionsTable(data);permissionListModule.refresh();});}
|
||||
permissionListModule.enabled=true;},onBeforeHide:function(){permissionListModule.enabled=false;}});};});
|
||||
75
overrides/settings.gaiamobile.org/js/panels/battery/panel.js
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* The battery panel displays battery information provided by Battery.
|
||||
*/
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var SettingsPanel = require('modules/settings_panel');
|
||||
var Battery = require('modules/battery');
|
||||
|
||||
return function ctor_battery_panel() {
|
||||
var _batteryLevelText = null;
|
||||
var _batteryTimeText = null;
|
||||
var _getBatteryTimeL10n = function(type) {
|
||||
type = type === 'charging' ? 'charging': 'discharging';
|
||||
|
||||
var time = Battery[type + 'Time'];
|
||||
var l10nAttrs = {
|
||||
id: 'battery-' + type + '-calculating',
|
||||
args: {}
|
||||
};
|
||||
|
||||
if (time !== Infinity && time > 0) {
|
||||
var timeLeft = new Date(0, 0, 0, 0, 0, time);
|
||||
l10nAttrs.args.hours = timeLeft.getHours();
|
||||
l10nAttrs.args.minutes = timeLeft.getMinutes();
|
||||
|
||||
if (l10nAttrs.args.hours > 0) {
|
||||
l10nAttrs.id = 'battery-' + type + '-hours';
|
||||
} else {
|
||||
l10nAttrs.id = 'battery-' + type + '-minutes';
|
||||
}
|
||||
} else if (time !== Infinity && time === 0) {
|
||||
l10nAttrs.id = 'battery-' + type + '-complete';
|
||||
} else {
|
||||
l10nAttrs.id = 'battery-' + type + '-unavailable';
|
||||
}
|
||||
|
||||
return l10nAttrs;
|
||||
};
|
||||
var _refreshText = function() {
|
||||
document.l10n.setAttributes(_batteryLevelText,
|
||||
'battery-current-level', { level: Battery.level });
|
||||
|
||||
if (Battery.state === 'unplugged') {
|
||||
var l10nDischarging = _getBatteryTimeL10n('discharging');
|
||||
document.l10n.setAttributes(_batteryTimeText,
|
||||
l10nDischarging.id, l10nDischarging.args);
|
||||
}
|
||||
else {
|
||||
var l10nCharging = _getBatteryTimeL10n('charging');
|
||||
document.l10n.setAttributes(_batteryTimeText,
|
||||
l10nCharging.id, l10nCharging.args);
|
||||
}
|
||||
};
|
||||
|
||||
return SettingsPanel({
|
||||
onInit: function bp_onInit(rootElement) {
|
||||
_batteryLevelText = rootElement.querySelector(
|
||||
'#battery-level');
|
||||
_batteryTimeText = rootElement.querySelector(
|
||||
'#battery-time');
|
||||
},
|
||||
onBeforeShow: function bp_onBeforeShow(rootElement) {
|
||||
Battery.observe('level', _refreshText);
|
||||
Battery.observe('state', _refreshText);
|
||||
Battery.observe('chargingTime', _refreshText);
|
||||
Battery.observe('dischargingTime', _refreshText);
|
||||
_refreshText();
|
||||
},
|
||||
onBeforeHide: function bp_onBeforeHide() {
|
||||
Battery.unobserve(_refreshText);
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
240
overrides/shared/style/value_selector.css
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
/* ----------------------------------
|
||||
* Value selector (Single & Multiple)
|
||||
* ---------------------------------- */
|
||||
|
||||
/* Main dialog setup */
|
||||
[role="dialog"][data-type="value-selector"] {
|
||||
background: #2d2d2d;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 0 0 7rem;
|
||||
color: #fff;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="value-selector"] > section {
|
||||
padding: 0 1.5rem;
|
||||
box-sizing: padding-box;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="value-selector"] h1 {
|
||||
font-weight: 400;
|
||||
font-size: 1.9rem;
|
||||
line-height: 4.8rem;
|
||||
color: #fff;
|
||||
border-bottom: 0.1rem solid #616262;
|
||||
background-color: rgba(0, 0, 0, .2);
|
||||
margin: 0 -1.5rem;
|
||||
padding: 0 3rem 1rem;
|
||||
height: 4.8rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Specific component code */
|
||||
[role="dialog"][data-type="value-selector"] [role="listbox"] {
|
||||
position: relative;
|
||||
padding: 0;
|
||||
margin: 0 -1.5rem;
|
||||
max-height: calc(100% - 5rem);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="value-selector"] [role="listbox"] li {
|
||||
margin: 0;
|
||||
padding: 0 1.5rem;
|
||||
height: auto;
|
||||
list-style: none;
|
||||
position: relative;
|
||||
font-weight: 300;
|
||||
font-size: 2.2rem;
|
||||
line-height: normal;
|
||||
color: #fff;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
html[dir="ltr"] [role="dialog"][data-type="value-selector"] [role="listbox"],
|
||||
html[dir="ltr"] [role="dialog"][data-type="value-selector"] [role="listbox"] li {
|
||||
text-align: left;
|
||||
}
|
||||
html[dir="rtl"] [role="dialog"][data-type="value-selector"] [role="listbox"],
|
||||
html[dir="rtl"] [role="dialog"][data-type="value-selector"] [role="listbox"] li {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="value-selector"] [role="listbox"] li:first-child label {
|
||||
border-top-color: transparent;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="value-selector"] [role="listbox"] li label {
|
||||
outline: none;
|
||||
display: block;
|
||||
color: #fff;
|
||||
border-top: 0.1rem solid #666;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="value-selector"] [role="listbox"] li label span {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
min-height: 5.2rem;
|
||||
padding: 1.2rem 1.5rem;
|
||||
line-height: 2.8rem;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
/* Pressed status */
|
||||
[role="dialog"][data-type="value-selector"] [role="listbox"] li:active {
|
||||
background-color: #00ABCC;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="value-selector"] [role="listbox"] li:active label,
|
||||
[role="dialog"][data-type="value-selector"] [role="listbox"] li:active + li label {
|
||||
border-top-color: transparent;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="value-selector"] [role="listbox"] li:active label span {
|
||||
color: #fff !important;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
/* Subheaders */
|
||||
[role="dialog"][data-type="value-selector"] [role="listbox"] li[role="subheader"] {
|
||||
border: none;
|
||||
background-color: #242424;
|
||||
pointer-events: none;
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="value-selector"] [role="listbox"] li[role="subheader"] label {
|
||||
color: #f4f4f4;
|
||||
font-size: 1.4rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="value-selector"] [role="listbox"] li[role="subheader"] label,
|
||||
[role="dialog"][data-type="value-selector"] [role="listbox"] li[role="subheader"] + li label {
|
||||
border: none;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="value-selector"] [role="listbox"] li[role="subheader"] label span {
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
/* Checked status */
|
||||
[role="dialog"][data-type="value-selector"] [role="listbox"] li[aria-selected="true"] label {
|
||||
background-image: url(value_selector/images/icons/checked.png);
|
||||
background-color: transparent;
|
||||
background-size: 2.4rem;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
html[dir="ltr"] [role="dialog"][data-type="value-selector"] [role="listbox"] li[aria-selected="true"] label {
|
||||
background-position: right 1.2rem top 50%;
|
||||
}
|
||||
html[dir="rtl"] [role="dialog"][data-type="value-selector"] [role="listbox"] li[aria-selected="true"] label {
|
||||
background-position: left 1.2rem top 50%;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="value-selector"] [role="listbox"] li[aria-selected="true"] span {
|
||||
color: #00abcd;
|
||||
}
|
||||
html[dir="ltr"] [role="dialog"][data-type="value-selector"] [role="listbox"] li[aria-selected="true"] span {
|
||||
padding-right: 2.6rem;
|
||||
margin-right: 1.2rem;
|
||||
}
|
||||
html[dir="rtl"] [role="dialog"][data-type="value-selector"] [role="listbox"] li[aria-selected="true"] span {
|
||||
padding-left: 2.6rem;
|
||||
margin-left: 1.2rem;
|
||||
}
|
||||
|
||||
/* Menu & buttons setup */
|
||||
.value-selector > [role="dialog"][data-type="value-selector"] menu.value-selector-buttons {
|
||||
white-space: nowrap;
|
||||
margin: 0;
|
||||
padding: 1.5rem;
|
||||
background: #4d4d4d;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.value-selector > [role="dialog"][data-type="value-selector"] menu.value-selector-buttons button::-moz-focus-inner {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.value-selector > [role="dialog"][data-type="value-selector"] menu.value-selector-buttons button {
|
||||
width: calc((100% - 1rem) / 2);
|
||||
font-family: sans-serif;
|
||||
font-style: italic;
|
||||
height: 4rem;
|
||||
margin: 0 0 1rem;
|
||||
padding: 0 1.2rem;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
background: #d8d8d8;
|
||||
border: none;
|
||||
border-radius: 2rem;
|
||||
font-weight: normal;
|
||||
font-size: 1.6rem;
|
||||
line-height: 4rem;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
text-shadow: none;
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Affirmative */
|
||||
.value-selector > [role="dialog"][data-type="value-selector"] menu.value-selector-buttons button.affirmative,
|
||||
.value-selector > [role="dialog"][data-type="value-selector"] menu.value-selector-buttons button.recommend {
|
||||
background-color: #00caf2;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Pressed */
|
||||
.value-selector > [role="dialog"][data-type="value-selector"] menu.value-selector-buttons button:active {
|
||||
background: #00aacc;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Disabled */
|
||||
[role="dialog"][data-type="value-selector"] > menu.value-selector-buttons > button[disabled] {
|
||||
background-color: #565656;
|
||||
color: rgba(255,255,255,0.4);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
[role="dialog"][data-type="value-selector"] > menu.value-selector-buttons > button[disabled].recommend {
|
||||
background-color: #006579;
|
||||
}
|
||||
|
||||
button[disabled]::-moz-selection {
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.value-selector > [role="dialog"][data-type="value-selector"] menu.value-selector-buttons button:last-child {
|
||||
margin-inline-start: 1rem;
|
||||
}
|
||||
|
||||
.value-selector > [role="dialog"][data-type="value-selector"] menu.value-selector-buttons button,
|
||||
.value-selector > [role="dialog"][data-type="value-selector"] menu.value-selector-buttons button:first-child {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.value-selector > [role="dialog"][data-type="value-selector"] menu.value-selector-buttons button.full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
|
@ -475,20 +475,25 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Set the .icon property before saving for
|
||||
// backwards compatibility with verticalhome
|
||||
// Set the .icon property before saving for backwards compatibility with
|
||||
// verticalhome. A missing favicon must not prevent pinning the site.
|
||||
var saveSite = function(icon) {
|
||||
siteObject.icon = icon || '';
|
||||
BookmarksDatabase.put(siteObject, siteObject.id)
|
||||
.then(() => {
|
||||
this.app.debug('pinSite: ' + siteObject.id);
|
||||
this.systemBanner.show('site-pinned-to-home-screen');
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('pinSite, Failed to pin site: ' + error);
|
||||
});
|
||||
}.bind(this);
|
||||
|
||||
IconsHelper.getIcon(siteObject.url, null,
|
||||
{icons: this.app.favicons}, siteObject).then(icon => {
|
||||
siteObject.icon = icon;
|
||||
BookmarksDatabase.put(siteObject, siteObject.id)
|
||||
.then(() => {
|
||||
this.app.debug('pinSite: ' + siteObject.id);
|
||||
this.systemBanner.show('site-pinned-to-home-screen');
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('pinSite, Failed to pin site: ' + error);
|
||||
});
|
||||
});
|
||||
{icons: this.app.favicons}, siteObject).then(saveSite, function(error) {
|
||||
this.app.debug('pinSite: using no favicon: ' + error);
|
||||
saveSite('');
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -986,12 +991,14 @@
|
|||
return;
|
||||
}
|
||||
|
||||
// Enable/disable the bookmark option
|
||||
BookmarksDatabase.get(this._currentURL).then(function resolve(result) {
|
||||
// start_url is the bookmark key for installed web apps, while _currentURL
|
||||
// may be a later page in the app. Check the canonical key first.
|
||||
var siteUrl = this.getSiteUrl();
|
||||
BookmarksDatabase.get(siteUrl).then(function resolve(result) {
|
||||
this.addToHomeButton.hidden = !!result;
|
||||
}.bind(this),
|
||||
function reject() {
|
||||
this.addToHomeButton.hidden = true;
|
||||
this.addToHomeButton.hidden = false;
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,173 @@
|
|||
/* dialog */
|
||||
/* FIXME we have to see why we need such specific style here and why
|
||||
* the general style in confirm.css isn't sufficient */
|
||||
#setup-installed-app-dialog,
|
||||
#ime-layout-dialog,
|
||||
#app-install-dialog,
|
||||
#app-install-cancel-dialog,
|
||||
#app-download-cancel-dialog {
|
||||
display: none;
|
||||
top: 3rem;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Shift the bottom of the prompt to account for the height of the
|
||||
software home button */
|
||||
#screen.software-button-enabled #setup-installed-app-dialog,
|
||||
#screen.software-button-enabled #ime-layout-dialog,
|
||||
#screen.software-button-enabled #app-install-dialog,
|
||||
#screen.software-button-enabled #app-install-cancel-dialog,
|
||||
#screen.software-button-enabled #app-download-cancel-dialog {
|
||||
bottom: var(--software-home-button-height);
|
||||
}
|
||||
|
||||
@media (orientation: landscape) {
|
||||
#screen.software-button-enabled #setup-installed-app-dialog,
|
||||
#screen.software-button-enabled #ime-layout-dialog,
|
||||
#screen.software-button-enabled #app-install-dialog,
|
||||
#screen.software-button-enabled #app-install-cancel-dialog,
|
||||
#screen.software-button-enabled #app-download-cancel-dialog {
|
||||
bottom: 0;
|
||||
/* BiDi note: the software home button should not be mirrored in RTL. */
|
||||
right: var(--software-home-button-height);
|
||||
}
|
||||
}
|
||||
|
||||
#setup-installed-app-dialog.visible,
|
||||
#ime-layout-dialog.visible,
|
||||
#app-install-dialog.visible,
|
||||
#app-install-cancel-dialog.visible,
|
||||
#app-download-cancel-dialog.visible {
|
||||
display: inline-block;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
#app-uninstall-dialog {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#setup-installed-app-dialog section,
|
||||
#ime-layout-dialog section,
|
||||
#app-install-dialog section,
|
||||
#app-install-cancel-dialog section,
|
||||
#app-download-cancel-dialog section {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#setup-installed-app-dialog h1,
|
||||
#ime-layout-dialog h1,
|
||||
#app-install-dialog h1,
|
||||
#app-install-cancel-dialog h1,
|
||||
#app-download-cancel-dialog h1 {
|
||||
border-bottom: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
#app-install-dialog dl > dt {
|
||||
width: 8rem;
|
||||
margin-inline-end: 1rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
#app-install-dialog p {
|
||||
font-size: 1.4rem;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
border-top: none;
|
||||
}
|
||||
#app-install-dialog #system-addon-warning p + p {
|
||||
margin-top: 0;
|
||||
}
|
||||
#app-install-dialog span {
|
||||
font-size: 1.4rem;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
color: inherit;
|
||||
}
|
||||
#app-install-dialog #system-addon-icon {
|
||||
height: 3rem;
|
||||
width: 3rem;
|
||||
}
|
||||
html[dir="ltr"] #app-install-dialog #system-addon-icon {
|
||||
float: left;
|
||||
margin: 1.5rem 0 0 1.5rem;
|
||||
}
|
||||
html[dir="rtl"] #app-install-dialog #system-addon-icon {
|
||||
float: right;
|
||||
margin: 1.5rem 1.5rem 0 0;
|
||||
}
|
||||
|
||||
#app-install-author-url {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
#app-install-cancel-dialog small:first-child {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
/* ... end of dialog */
|
||||
|
||||
/* notification */
|
||||
#install-manager-notification-container > .fake-notification {
|
||||
position: relative;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
#install-manager-notification-container > .fake-notification > * {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#install-manager-notification-container [data-icon] {
|
||||
color: #9ab0c0;
|
||||
background-color: #edf1f4;
|
||||
}
|
||||
|
||||
#install-manager-notification-container .title-container {
|
||||
margin: 1.4rem 0 0;
|
||||
line-height: 3rem;
|
||||
}
|
||||
html[dir="ltr"] #install-manager-notification-container .title-container {
|
||||
margin-left: 3.7rem;
|
||||
}
|
||||
html[dir="rtl"] #install-manager-notification-container .title-container {
|
||||
margin-right: 3.7rem;
|
||||
}
|
||||
|
||||
#install-manager-notification-container progress {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 0.4rem;
|
||||
left: 0;
|
||||
top: 5.6rem;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#install-manager-notification-container progress::-moz-progress-bar {
|
||||
background: url(../shared/progress.gif) repeat-x;
|
||||
}
|
||||
|
||||
/* ... end of notification */
|
||||
|
||||
/* ... start of keyboard layout */
|
||||
ul#ime-list {
|
||||
padding-inline-start: 1.5rem;
|
||||
}
|
||||
|
||||
ul#ime-list > li {
|
||||
/* Positioning */
|
||||
position: relative;
|
||||
|
||||
/* Display & Box Model */
|
||||
width: 100%;
|
||||
height: 3rem;
|
||||
padding-top: 2rem;
|
||||
|
||||
/* Other */
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
ul#ime-list > li label {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/* ... end of keyboard layout */
|
||||
|
|
@ -57,6 +57,6 @@
|
|||
#os-logo { background:#071d35; display:flex; flex-direction:column; align-items:center; justify-content:center; }
|
||||
#os-logo::before { content:""; width:min(42vw,190px); aspect-ratio:1; flex:none; background:url('/shared/resources/branding/vulpes-symbol.png') center / contain no-repeat; animation:vulpes-boot 2s ease-in-out infinite alternate; }
|
||||
#os-logo::after { content:"VULPES\A Firefox OS Community Project"; white-space:pre-line; padding:12px 22px; color:#f5f8fa; font:500 20px/1.8 FiraSans,sans-serif; text-align:center; }
|
||||
#poweroff-splash { background:#071d35 url('/shared/resources/branding/vulpes-symbol.png') center / 190px 190px no-repeat; }
|
||||
#poweroff-splash { background:#071d35; }
|
||||
@keyframes vulpes-boot { from {opacity:.75} to {opacity:1} }
|
||||
@media (prefers-reduced-motion: reduce) { #os-logo::before {animation:none} }
|
||||
|
|
|
|||