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:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
143
gaia/apps/settings/js/panels/addon_details/addon_details.js
Executable file
143
gaia/apps/settings/js/panels/addon_details/addon_details.js
Executable file
|
|
@ -0,0 +1,143 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var ManifestHelper = require('shared/manifest_helper');
|
||||
var AddonManager = require('modules/addon_manager');
|
||||
|
||||
const PREFERRED_ICON_SIZE = 64 * (window.devicePixelRatio || 1);
|
||||
|
||||
/**
|
||||
* This module renders the information of an addon to the UI elements.
|
||||
*
|
||||
* @class AddonDetails
|
||||
* @requires module:shared/manifest_helper
|
||||
* @requires module:modules/addon_manager
|
||||
* @returns {AddonDetails}
|
||||
*/
|
||||
function AddonDetails(elements) {
|
||||
this._boundUpdateEnabledState = this._updateEnabledState.bind(this);
|
||||
this._elements = elements;
|
||||
this._curApp = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the enabled state of an addon.
|
||||
*
|
||||
* @access private
|
||||
* @memberOf AddonDetails.prototype
|
||||
* @param {Boolean} newState
|
||||
*/
|
||||
AddonDetails.prototype._updateEnabledState = function _update(newState) {
|
||||
this._elements.enabledState
|
||||
.setAttribute('data-l10n-id', newState ? 'enabled' : 'disabled');
|
||||
};
|
||||
|
||||
/**
|
||||
* Render details of an app to the UI elements.
|
||||
*
|
||||
* @access public
|
||||
* @memberOf AddonDetails.prototype
|
||||
* @param {Object} app Add-on to render
|
||||
*/
|
||||
AddonDetails.prototype.render = function render(app) {
|
||||
if (this._curApp !== null) {
|
||||
this._curApp.unobserve('enabled', this._boundUpdateEnabledState);
|
||||
}
|
||||
this._curApp = app;
|
||||
if (this._curApp) {
|
||||
this._curApp.observe('enabled', this._boundUpdateEnabledState);
|
||||
this._updateEnabledState(this._curApp.enabled);
|
||||
}
|
||||
|
||||
var l10n = document.l10n;
|
||||
var manifest =
|
||||
new ManifestHelper(app.instance.manifest || app.instance.updateManifest);
|
||||
|
||||
this.updateNames(manifest);
|
||||
|
||||
// Put an icon next to the description
|
||||
navigator.mozApps.mgmt.getIcon(app, PREFERRED_ICON_SIZE).then((blob) => {
|
||||
this._elements.icon.src = URL.createObjectURL(blob);
|
||||
}).catch(() => {
|
||||
this._elements.icon.src = '../style/images/default.png';
|
||||
});
|
||||
|
||||
// Display the add-on version
|
||||
if (manifest.version) {
|
||||
this._elements.version.textContent = 'v' + manifest.version;
|
||||
}
|
||||
|
||||
// Display the add-on description if there is one
|
||||
if (manifest.description) {
|
||||
// If we have a description, the ManifestHelper class returned the
|
||||
// best localized version from the manifest file.
|
||||
this._elements.description.removeAttribute('data-l10n-id');
|
||||
this._elements.description.textContent = manifest.description;
|
||||
} else {
|
||||
// If there is no description, then display "no description" or similar.
|
||||
this._elements.description
|
||||
.setAttribute('data-l10n-id', 'addon-no-description');
|
||||
}
|
||||
|
||||
// Display the add-on developer name if there is one
|
||||
var developerName = manifest.developer && manifest.developer.name;
|
||||
l10n.setAttributes(this._elements.developer, 'addon-developer-name', {
|
||||
developerName: developerName || ''
|
||||
});
|
||||
|
||||
// Old add-on format had 'customizations' field, it is now moved to
|
||||
// 'content_scripts' field
|
||||
var oldAddonFormat = !!manifest.customizations;
|
||||
if (oldAddonFormat) {
|
||||
l10n.setAttributes(this._elements.obsoleteStatusInfo,
|
||||
AddonManager.canDelete(app) ? 'addon-obsolete-can-delete' :
|
||||
'addon-obsolete');
|
||||
}
|
||||
this._elements.obsoleteStatus.hidden = !oldAddonFormat;
|
||||
|
||||
// Get the list of targeted apps
|
||||
this._elements.targetsList.textContent = ''; // Clear any old content here
|
||||
AddonManager.getAddonTargets(app).then((targets) => {
|
||||
var names = [];
|
||||
targets.forEach(function(target) {
|
||||
var manifest =
|
||||
new ManifestHelper(target.manifest || target.updateManifest);
|
||||
names.push(manifest.displayName);
|
||||
});
|
||||
|
||||
names.sort();
|
||||
|
||||
if (names.length < 1) {
|
||||
this._elements.targetsList
|
||||
.setAttribute('data-l10n-id', 'addon-no-targets');
|
||||
} else {
|
||||
this._elements.targetsList.textContent = names.join(', ');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Render app names where appropriate.
|
||||
*
|
||||
* @access public
|
||||
* @memberOf AddonDetails.prototype
|
||||
* @param {JSON} manifest
|
||||
*/
|
||||
AddonDetails.prototype.updateNames = function _updateNames(manifest) {
|
||||
// Display the name of the add-on in the panel header
|
||||
var appnameArgs = { appName: manifest.name };
|
||||
var l10n = document.l10n;
|
||||
|
||||
l10n.setAttributes(
|
||||
this._elements.header, 'addon-details-header1', appnameArgs);
|
||||
l10n.setAttributes(
|
||||
this._elements.name, 'addon-details-header1', appnameArgs);
|
||||
// Put text description for an icon
|
||||
l10n.setAttributes(
|
||||
this._elements.icon, 'accessibility-app-icon', appnameArgs);
|
||||
};
|
||||
|
||||
return function ctor_addon_details(panel) {
|
||||
return new AddonDetails(panel);
|
||||
};
|
||||
});
|
||||
130
gaia/apps/settings/js/panels/addon_details/panel.js
Executable file
130
gaia/apps/settings/js/panels/addon_details/panel.js
Executable file
|
|
@ -0,0 +1,130 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var SettingsPanel = require('modules/settings_panel');
|
||||
var AddonManager = require('modules/addon_manager');
|
||||
var AddonDetails = require('panels/addon_details/addon_details');
|
||||
var SettingsService = require('modules/settings_service');
|
||||
var Toaster = require('shared/toaster');
|
||||
|
||||
return function ctor_addon_details_panel() {
|
||||
return SettingsPanel({
|
||||
onInit: function(panel) {
|
||||
this._elements = {
|
||||
body: panel.querySelector('.addon-details-body'),
|
||||
header: panel.querySelector('.addon-details-header'),
|
||||
gaiaHeader: panel.querySelector('gaia-header'),
|
||||
enabledState: panel.querySelector('.addon-enabled details'),
|
||||
name: panel.querySelector('.addon-details-name'),
|
||||
icon: panel.querySelector('.addon-details-icon'),
|
||||
version: panel.querySelector('.addon-details-version'),
|
||||
description: panel.querySelector('.addon-description-text'),
|
||||
developer: panel.querySelector('.addon-developer'),
|
||||
targetsList: panel.querySelector('.addon-targets'),
|
||||
toggle: panel.querySelector('.addon-enabled'),
|
||||
deleteButton: panel.querySelector('.addon-delete'),
|
||||
obsoleteStatus: panel.querySelector('.addon-obsolete-status'),
|
||||
obsoleteStatusInfo: panel.querySelector('.addon-obsolete-info')
|
||||
};
|
||||
this._details = AddonDetails(this._elements);
|
||||
this._boundOnAppEnabledChange = this._onAppEnabledChange.bind(this);
|
||||
|
||||
// Hook up the enable/disable toggle button
|
||||
this._elements.toggle.onchange = this._onToggleChange.bind(this);
|
||||
// Hook up the delete button
|
||||
this._elements.deleteButton.onclick = this._onDelete.bind(this);
|
||||
},
|
||||
|
||||
onBeforeShow: function(panel, options) {
|
||||
return Promise.resolve((() => {
|
||||
if (options.addon) {
|
||||
return options.addon;
|
||||
} else if (options.manifestURL) {
|
||||
return AddonManager.findAddonByManifestURL(options.manifestURL);
|
||||
}
|
||||
})()).then((addon) => {
|
||||
this._curAddon = addon;
|
||||
|
||||
// set initial state
|
||||
if (this._curAddon) {
|
||||
this._details.render(this._curAddon);
|
||||
this._elements.toggle.checked =
|
||||
AddonManager.isEnabled(this._curAddon);
|
||||
this._curAddon.observe('enabled', this._boundOnAppEnabledChange);
|
||||
this._elements.deleteButton.disabled =
|
||||
!AddonManager.canDelete(this._curAddon);
|
||||
this._elements.body.hidden = false;
|
||||
} else {
|
||||
console.error('No valid add-on');
|
||||
this._elements.body.hidden = true;
|
||||
}
|
||||
|
||||
this._elements.gaiaHeader.hidden = false;
|
||||
});
|
||||
},
|
||||
|
||||
onHide: function() {
|
||||
// Scroll back to the top
|
||||
this._elements.body.scrollTop = 0;
|
||||
|
||||
if (this._curAddon) {
|
||||
this._curAddon.unobserve('enabled', this._boundOnAppEnabledChange);
|
||||
this._curAddon = null;
|
||||
}
|
||||
},
|
||||
|
||||
_showStepsRequired(type) {
|
||||
// If an addon injected a script then we have to restart any
|
||||
// affected apps. And if those apps are system apps, then we
|
||||
// need to reboot the device.
|
||||
if (type === 'reboot') {
|
||||
// XXX We could do a confirm dialog here asking the user if
|
||||
// they want to go ahead and reboot the device now.
|
||||
Toaster.showToast({
|
||||
messageL10nId: 'addon-reboot-required',
|
||||
latency: 3000,
|
||||
useTransition: true
|
||||
});
|
||||
} else if (type === 'restart') {
|
||||
Toaster.showToast({
|
||||
messageL10nId: 'addon-restart-apps-to-disable',
|
||||
latency: 3000,
|
||||
useTransition: true
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_onAppEnabledChange: function(enabled) {
|
||||
this._elements.toggle.checked = enabled;
|
||||
if (!enabled) {
|
||||
AddonManager.getAddonDisableType(this._curAddon).then(
|
||||
this._showStepsRequired);
|
||||
}
|
||||
},
|
||||
|
||||
_onToggleChange: function() {
|
||||
if (this._elements.toggle.checked) {
|
||||
AddonManager.enableAddon(this._curAddon);
|
||||
} else {
|
||||
AddonManager.disableAddon(this._curAddon);
|
||||
}
|
||||
},
|
||||
|
||||
_onDelete: function() {
|
||||
this._elements.deleteButton.disabled = true; // don't delete it twice!
|
||||
var disableType;
|
||||
AddonManager.getAddonDisableType(this._curAddon).then(type => {
|
||||
disableType = type;
|
||||
return AddonManager.deleteAddon(this._curAddon);
|
||||
}).then(() => {
|
||||
this._showStepsRequired(disableType);
|
||||
SettingsService.navigate('addons'); /* go back*/
|
||||
}).catch(reason => {
|
||||
console.error('Addon deletion failed:', reason);
|
||||
// If the user cancelled deletion, we need to reenable the button
|
||||
this._elements.deleteButton.disabled = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
Loading…
Reference in a new issue