зеркало из https://github.com/mozilla/gecko-dev.git
Bug 696532 - Basic add-on manager support [r=wesj]
This commit is contained in:
Родитель
ac1dca4d92
Коммит
f266ecdfc3
|
@ -0,0 +1,463 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" [
|
||||||
|
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
|
||||||
|
%brandDTD;
|
||||||
|
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd" >
|
||||||
|
%globalDTD;
|
||||||
|
<!ENTITY % aboutDTD SYSTEM "chrome://browser/locale/aboutAddons.dtd" >
|
||||||
|
%aboutDTD;
|
||||||
|
]>
|
||||||
|
|
||||||
|
<!-- ***** BEGIN LICENSE BLOCK *****
|
||||||
|
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
-
|
||||||
|
- The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
- 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
- the License. You may obtain a copy of the License at
|
||||||
|
- http://www.mozilla.org/MPL/
|
||||||
|
-
|
||||||
|
- Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
- for the specific language governing rights and limitations under the
|
||||||
|
- License.
|
||||||
|
-
|
||||||
|
- The Original Code is Mozilla Communicator client code, released
|
||||||
|
- March 31, 1998.
|
||||||
|
-
|
||||||
|
- The Initial Developer of the Original Code is
|
||||||
|
- Netscape Communications Corporation.
|
||||||
|
- Portions created by the Initial Developer are Copyright (C) 1998-1999
|
||||||
|
- the Initial Developer. All Rights Reserved.
|
||||||
|
-
|
||||||
|
- Contributor(s):
|
||||||
|
- Mark Finkle <mfinkle@mozilla.com>
|
||||||
|
-
|
||||||
|
- Alternatively, the contents of this file may be used under the terms of
|
||||||
|
- either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
- in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
- of those above. If you wish to allow use of your version of this file only
|
||||||
|
- under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
- use your version of this file under the terms of the MPL, indicate your
|
||||||
|
- decision by deleting the provisions above and replace them with the notice
|
||||||
|
- and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
- the provisions above, a recipient may use your version of this file under
|
||||||
|
- the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
-
|
||||||
|
- ***** END LICENSE BLOCK ***** -->
|
||||||
|
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<title>&aboutAddons.title;</title>
|
||||||
|
<meta name="viewport" content="width=480; initial-scale=.6667; user-scalable=0" />
|
||||||
|
<link rel="icon" type="image/png" href="chrome://branding/content/favicon32.png" />
|
||||||
|
<link rel="stylesheet" href="chrome://browser/skin/aboutAddons.css" type="text/css"/>
|
||||||
|
<style>
|
||||||
|
.hide-on-enable,
|
||||||
|
.show-on-error,
|
||||||
|
.show-on-uninstall,
|
||||||
|
.show-on-install,
|
||||||
|
.show-on-restart,
|
||||||
|
div[isDisabled="true"] .hide-on-disable {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div[error] .show-on-error,
|
||||||
|
div[opType="needs-restart"] .show-on-restart,
|
||||||
|
div[opType="needs-uninstall"] .show-on-uninstall,
|
||||||
|
div[opType="needs-install"] .show-on-install,
|
||||||
|
div[opType="needs-enable"] .show-on-enable,
|
||||||
|
div[opType="needs-disable"] .show-on-disable,
|
||||||
|
div[isDisabled="true"] .show-on-disable {
|
||||||
|
display: -moz-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
div[opType="needs-restart"] .hide-on-restart,
|
||||||
|
div[opType="needs-uninstall"] .hide-on-uninstall,
|
||||||
|
div[isDisabled="true"][opType="needs-uninstall"],
|
||||||
|
div[opType="needs-install"] .hide-on-install,
|
||||||
|
div[opType="needs-enable"] .hide-on-enable,
|
||||||
|
div[opType="needs-disable"] .hide-on-disable {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body dir="&locale.dir;" onload="init();" onunload="uninit();">
|
||||||
|
<div id="addons-header">
|
||||||
|
<div>&aboutAddons.header;</div>
|
||||||
|
</div>
|
||||||
|
<div id="addons-list" style="display: none;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="application/javascript;version=1.8"><![CDATA[
|
||||||
|
let Ci = Components.interfaces, Cc = Components.classes, Cu = Components.utils;
|
||||||
|
|
||||||
|
Cu.import("resource://gre/modules/Services.jsm")
|
||||||
|
Cu.import("resource://gre/modules/AddonManager.jsm");
|
||||||
|
|
||||||
|
let gStringBundle = Services.strings.createBundle("chrome://browser/locale/aboutAddons.properties");
|
||||||
|
|
||||||
|
let gChromeWin = null;
|
||||||
|
function getChromeWin() {
|
||||||
|
if (!gChromeWin) {
|
||||||
|
gChromeWin = window
|
||||||
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIWebNavigation)
|
||||||
|
.QueryInterface(Ci.nsIDocShellTreeItem)
|
||||||
|
.rootTreeItem
|
||||||
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIDOMWindow)
|
||||||
|
.QueryInterface(Ci.nsIDOMChromeWindow);
|
||||||
|
}
|
||||||
|
return gChromeWin;
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
AddonManager.addInstallListener(Addons);
|
||||||
|
Addons.getAddons();
|
||||||
|
}
|
||||||
|
|
||||||
|
function uninit() {
|
||||||
|
AddonManager.removeInstallListener(Addons);
|
||||||
|
}
|
||||||
|
|
||||||
|
var Addons = {
|
||||||
|
_createItem: function _createItem(aAddon) {
|
||||||
|
let outer = document.createElement("div");
|
||||||
|
outer.setAttribute("addonID", aAddon.id);
|
||||||
|
outer.className = "addon-item";
|
||||||
|
|
||||||
|
let img = document.createElement("img");
|
||||||
|
img.className = "favicon";
|
||||||
|
img.setAttribute("src", aAddon.iconURL);
|
||||||
|
outer.appendChild(img);
|
||||||
|
|
||||||
|
let inner = document.createElement("div");
|
||||||
|
inner.className = "inner";
|
||||||
|
|
||||||
|
let titlePart = document.createElement("span");
|
||||||
|
titlePart.textContent = aAddon.name;
|
||||||
|
titlePart.className = "title";
|
||||||
|
inner.appendChild(titlePart);
|
||||||
|
|
||||||
|
let versionPart = document.createElement("span");
|
||||||
|
versionPart.textContent = aAddon.version;
|
||||||
|
versionPart.className = "version";
|
||||||
|
inner.appendChild(versionPart);
|
||||||
|
|
||||||
|
if ("description" in aAddon) {
|
||||||
|
let descPart = document.createElement("div");
|
||||||
|
descPart.textContent = aAddon.description;
|
||||||
|
descPart.className = "description";
|
||||||
|
inner.appendChild(descPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
outer.appendChild(inner);
|
||||||
|
|
||||||
|
let buttons = document.createElement("div");
|
||||||
|
buttons.className = "buttons";
|
||||||
|
|
||||||
|
let optionsBtn = document.createElement("button");
|
||||||
|
optionsBtn.className = "options-btn";
|
||||||
|
optionsBtn.textContent = gStringBundle.GetStringFromName("addonAction.options");
|
||||||
|
optionsBtn.setAttribute("disabled", "true"); // TODO (bug 696533)
|
||||||
|
optionsBtn.addEventListener("click", function() {
|
||||||
|
this.toggleOptions(outer);
|
||||||
|
}.bind(this), false)
|
||||||
|
buttons.appendChild(optionsBtn);
|
||||||
|
|
||||||
|
let enableBtn = document.createElement("button");
|
||||||
|
enableBtn.className = "show-on-disable hide-on-enable hide-on-uninstall";
|
||||||
|
enableBtn.textContent = gStringBundle.GetStringFromName("addonAction.enable");
|
||||||
|
if (aAddon.appDisabled)
|
||||||
|
enableBtn.setAttribute("disabled", "true");
|
||||||
|
enableBtn.addEventListener("click", function() {
|
||||||
|
this.enable(outer);
|
||||||
|
}.bind(this), false)
|
||||||
|
buttons.appendChild(enableBtn);
|
||||||
|
|
||||||
|
let disableBtn = document.createElement("button");
|
||||||
|
disableBtn.className = "show-on-enable hide-on-disable hide-on-uninstall";
|
||||||
|
disableBtn.textContent = gStringBundle.GetStringFromName("addonAction.disable");
|
||||||
|
disableBtn.addEventListener("click", function() {
|
||||||
|
this.disable(outer);
|
||||||
|
}.bind(this), false)
|
||||||
|
buttons.appendChild(disableBtn);
|
||||||
|
|
||||||
|
let uninstallBtn = document.createElement("button");
|
||||||
|
uninstallBtn.className = "hide-on-uninstall";
|
||||||
|
uninstallBtn.textContent = gStringBundle.GetStringFromName("addonAction.uninstall");
|
||||||
|
if (aAddon.scope == AddonManager.SCOPE_APPLICATION)
|
||||||
|
uninstallBtn.setAttribute("disabled", "true");
|
||||||
|
uninstallBtn.addEventListener("click", function() {
|
||||||
|
this.uninstall(outer);
|
||||||
|
}.bind(this), false)
|
||||||
|
buttons.appendChild(uninstallBtn);
|
||||||
|
|
||||||
|
let cancelUninstallBtn = document.createElement("button");
|
||||||
|
cancelUninstallBtn.className = "show-on-uninstall";
|
||||||
|
cancelUninstallBtn.textContent = gStringBundle.GetStringFromName("addonAction.cancel");
|
||||||
|
cancelUninstallBtn.addEventListener("click", function() {
|
||||||
|
this.cancelUninstall(outer);
|
||||||
|
}.bind(this), false)
|
||||||
|
buttons.appendChild(cancelUninstallBtn);
|
||||||
|
|
||||||
|
outer.appendChild(buttons);
|
||||||
|
return outer;
|
||||||
|
},
|
||||||
|
|
||||||
|
_createItemForAddon: function _createItemForAddon(aAddon) {
|
||||||
|
let appManaged = (aAddon.scope == AddonManager.SCOPE_APPLICATION);
|
||||||
|
let opType = this._getOpTypeForOperations(aAddon.pendingOperations);
|
||||||
|
let updateable = (aAddon.permissions & AddonManager.PERM_CAN_UPGRADE) > 0;
|
||||||
|
let uninstallable = (aAddon.permissions & AddonManager.PERM_CAN_UNINSTALL) > 0;
|
||||||
|
|
||||||
|
let blocked = "";
|
||||||
|
switch(aAddon.blocklistState) {
|
||||||
|
case Ci.nsIBlocklistService.STATE_BLOCKED:
|
||||||
|
blocked = "blocked";
|
||||||
|
break;
|
||||||
|
case Ci.nsIBlocklistService.STATE_SOFTBLOCKED:
|
||||||
|
blocked = "softBlocked";
|
||||||
|
break;
|
||||||
|
case Ci.nsIBlocklistService.STATE_OUTDATED:
|
||||||
|
blocked = "outdated";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let item = this._createItem(aAddon);
|
||||||
|
item.setAttribute("isDisabled", !aAddon.isActive);
|
||||||
|
item.setAttribute("opType", opType);
|
||||||
|
item.setAttribute("updateable", updateable);
|
||||||
|
if (blocked)
|
||||||
|
item.setAttribute("blockedStatus", blocked);
|
||||||
|
item.setAttribute("optionsURL", aAddon.optionsURL || "");
|
||||||
|
item.addon = aAddon;
|
||||||
|
|
||||||
|
return item;
|
||||||
|
},
|
||||||
|
|
||||||
|
_getElementForAddon: function(aKey) {
|
||||||
|
let list = document.getElementById("addons-list");
|
||||||
|
let element = list.querySelector("div[addonID='" + aKey + "']");
|
||||||
|
return element;
|
||||||
|
},
|
||||||
|
|
||||||
|
getAddons: function getAddons() {
|
||||||
|
// Clear all content before filling the addons
|
||||||
|
let list = document.getElementById("addons-list");
|
||||||
|
list.innerHTML = "";
|
||||||
|
|
||||||
|
let self = this;
|
||||||
|
AddonManager.getAddonsByTypes(["extension", "theme", "locale"], function(aAddons) {
|
||||||
|
for (let i=0; i<aAddons.length; i++) {
|
||||||
|
let item = self._createItemForAddon(aAddons[i]);
|
||||||
|
list.appendChild(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
list.style.display = "block";
|
||||||
|
document.getElementById("addons-header").setAttribute("showlist", "true");
|
||||||
|
|
||||||
|
// Load the search engines
|
||||||
|
let defaults = Services.search.getDefaultEngines({ }).map(function (e) e.name);
|
||||||
|
function isDefault(aEngine)
|
||||||
|
defaults.indexOf(aEngine.name) != -1
|
||||||
|
|
||||||
|
let defaultDescription = gStringBundle.GetStringFromName("addonsSearchEngine.description");
|
||||||
|
|
||||||
|
let engines = Services.search.getEngines({ });
|
||||||
|
for (let e = 0; e < engines.length; e++) {
|
||||||
|
let engine = engines[e];
|
||||||
|
let addon = {};
|
||||||
|
addon.id = engine.name;
|
||||||
|
addon.type = "search";
|
||||||
|
addon.name = engine.name;
|
||||||
|
addon.version = "";
|
||||||
|
addon.description = engine.description || defaultDescription;
|
||||||
|
addon.iconURL = engine.iconURI ? engine.iconURI.spec : "";
|
||||||
|
addon.appDisabled = false;
|
||||||
|
addon.scope = isDefault(engine) ? AddonManager.SCOPE_APPLICATION : AddonManager.SCOPE_PROFILE;
|
||||||
|
addon.engine = engine;
|
||||||
|
|
||||||
|
let item = self._createItem(addon);
|
||||||
|
item.setAttribute("isDisabled", engine.hidden);
|
||||||
|
item.setAttribute("updateable", "false");
|
||||||
|
item.setAttribute("opType", "");
|
||||||
|
item.addon = addon;
|
||||||
|
list.appendChild(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_getOpTypeForOperations: function _getOpTypeForOperations(aOperations) {
|
||||||
|
if (aOperations & AddonManager.PENDING_UNINSTALL)
|
||||||
|
return "needs-uninstall";
|
||||||
|
if (aOperations & AddonManager.PENDING_ENABLE)
|
||||||
|
return "needs-enable";
|
||||||
|
if (aOperations & AddonManager.PENDING_DISABLE)
|
||||||
|
return "needs-disable";
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
|
||||||
|
enable: function enable(aItem) {
|
||||||
|
if (!aItem.addon)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let opType;
|
||||||
|
if (aItem.addon.type == "search") {
|
||||||
|
aItem.setAttribute("isDisabled", false);
|
||||||
|
aItem.addon.engine.hidden = false;
|
||||||
|
opType = "needs-enable";
|
||||||
|
} else if (aItem.addon.type == "theme") {
|
||||||
|
// We can have only one theme enabled, so disable the current one if any
|
||||||
|
let theme = null;
|
||||||
|
let list = document.getElementById("addons-list");
|
||||||
|
let item = list.firstElementChild;
|
||||||
|
while (item) {
|
||||||
|
if (item.addon && (item.addon.type == "theme") && (item.addon.isActive)) {
|
||||||
|
theme = item;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
item = item.nextSibling;
|
||||||
|
}
|
||||||
|
if (theme)
|
||||||
|
this.disable(theme);
|
||||||
|
|
||||||
|
aItem.addon.userDisabled = false;
|
||||||
|
aItem.setAttribute("isDisabled", false);
|
||||||
|
} else {
|
||||||
|
aItem.addon.userDisabled = false;
|
||||||
|
opType = this._getOpTypeForOperations(aItem.addon.pendingOperations);
|
||||||
|
|
||||||
|
if (aItem.addon.pendingOperations & AddonManager.PENDING_ENABLE) {
|
||||||
|
this.showRestart();
|
||||||
|
} else {
|
||||||
|
aItem.setAttribute("isDisabled", false);
|
||||||
|
if (aItem.getAttribute("opType") == "needs-disable")
|
||||||
|
this.hideRestart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aItem.setAttribute("opType", opType);
|
||||||
|
},
|
||||||
|
|
||||||
|
disable: function disable(aItem) {
|
||||||
|
if (!aItem.addon)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let opType;
|
||||||
|
if (aItem.addon.type == "search") {
|
||||||
|
aItem.setAttribute("isDisabled", true);
|
||||||
|
aItem.addon.engine.hidden = true;
|
||||||
|
opType = "needs-disable";
|
||||||
|
} else if (aItem.addon.type == "theme") {
|
||||||
|
aItem.addon.userDisabled = true;
|
||||||
|
aItem.setAttribute("isDisabled", true);
|
||||||
|
} else if (aItem.addon.type == "locale") {
|
||||||
|
aItem.addon.userDisabled = true;
|
||||||
|
aItem.setAttribute("isDisabled", true);
|
||||||
|
} else {
|
||||||
|
aItem.addon.userDisabled = true;
|
||||||
|
opType = this._getOpTypeForOperations(aItem.addon.pendingOperations);
|
||||||
|
|
||||||
|
if (aItem.addon.pendingOperations & AddonManager.PENDING_DISABLE) {
|
||||||
|
this.showRestart();
|
||||||
|
} else {
|
||||||
|
aItem.setAttribute("isDisabled", !aItem.addon.isActive);
|
||||||
|
if (aItem.getAttribute("opType") == "needs-enable")
|
||||||
|
this.hideRestart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aItem.setAttribute("opType", opType);
|
||||||
|
},
|
||||||
|
|
||||||
|
uninstall: function uninstall(aItem) {
|
||||||
|
let list = document.getElementById("addons-list");
|
||||||
|
if (!aItem.addon) {
|
||||||
|
list.removeChild(aItem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let opType;
|
||||||
|
if (aItem.addon.type == "search") {
|
||||||
|
// Make sure the engine isn't hidden before removing it, to make sure it's
|
||||||
|
// visible if the user later re-adds it (works around bug 341833)
|
||||||
|
aItem.addon.engine.hidden = false;
|
||||||
|
Services.search.removeEngine(aItem.addon.engine);
|
||||||
|
// the search-engine-modified observer in browser.js will take care of
|
||||||
|
// updating the list
|
||||||
|
} else {
|
||||||
|
aItem.addon.uninstall();
|
||||||
|
opType = this._getOpTypeForOperations(aItem.addon.pendingOperations);
|
||||||
|
|
||||||
|
if (aItem.addon.pendingOperations & AddonManager.PENDING_UNINSTALL) {
|
||||||
|
this.showRestart();
|
||||||
|
|
||||||
|
// A disabled addon doesn't need a restart so it has no pending ops and
|
||||||
|
// can't be cancelled
|
||||||
|
if (!aItem.addon.isActive && opType == "")
|
||||||
|
opType = "needs-uninstall";
|
||||||
|
|
||||||
|
aItem.setAttribute("opType", opType);
|
||||||
|
} else {
|
||||||
|
list.removeChild(aItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
cancelUninstall: function ev_cancelUninstall(aItem) {
|
||||||
|
if (!aItem.addon)
|
||||||
|
return;
|
||||||
|
|
||||||
|
aItem.addon.cancelUninstall();
|
||||||
|
this.hideRestart();
|
||||||
|
|
||||||
|
let opType = this._getOpTypeForOperations(aItem.addon.pendingOperations);
|
||||||
|
aItem.setAttribute("opType", opType);
|
||||||
|
},
|
||||||
|
|
||||||
|
showRestart: function showRestart(aMode) {
|
||||||
|
// TODO (bug 704406)
|
||||||
|
},
|
||||||
|
|
||||||
|
hideRestart: function hideRestart(aMode) {
|
||||||
|
// TODO (bug 704406)
|
||||||
|
},
|
||||||
|
|
||||||
|
onInstallEnded: function(aInstall, aAddon) {
|
||||||
|
let needsRestart = false;
|
||||||
|
if (aInstall.existingAddon && (aInstall.existingAddon.pendingOperations & AddonManager.PENDING_UPGRADE))
|
||||||
|
needsRestart = true;
|
||||||
|
else if (aAddon.pendingOperations & AddonManager.PENDING_INSTALL)
|
||||||
|
needsRestart = true;
|
||||||
|
|
||||||
|
let list = document.getElementById("addons-list");
|
||||||
|
let element = this._getElementForAddon(aAddon.id);
|
||||||
|
if (!element) {
|
||||||
|
element = this._createItemForAddon(aAddon);
|
||||||
|
list.insertBefore(element, list.firstElementChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsRestart)
|
||||||
|
element.setAttribute("opType", "needs-restart");
|
||||||
|
},
|
||||||
|
|
||||||
|
onInstallFailed: function(aInstall) {
|
||||||
|
},
|
||||||
|
|
||||||
|
onDownloadProgress: function xpidm_onDownloadProgress(aInstall) {
|
||||||
|
},
|
||||||
|
|
||||||
|
onDownloadFailed: function(aInstall) {
|
||||||
|
},
|
||||||
|
|
||||||
|
onDownloadCancelled: function(aInstall) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]]></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -43,8 +43,8 @@ let Cu = Components.utils;
|
||||||
let Cr = Components.results;
|
let Cr = Components.results;
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
|
||||||
Cu.import("resource://gre/modules/Services.jsm")
|
Cu.import("resource://gre/modules/Services.jsm")
|
||||||
|
Cu.import("resource://gre/modules/AddonManager.jsm");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyServiceGetter(this, "URIFixup",
|
XPCOMUtils.defineLazyServiceGetter(this, "URIFixup",
|
||||||
"@mozilla.org/docshell/urifixup;1", "nsIURIFixup");
|
"@mozilla.org/docshell/urifixup;1", "nsIURIFixup");
|
||||||
|
@ -166,9 +166,6 @@ var BrowserApp = {
|
||||||
Services.obs.addObserver(this, "FullScreen:Exit", false);
|
Services.obs.addObserver(this, "FullScreen:Exit", false);
|
||||||
Services.obs.addObserver(this, "Viewport:Change", false);
|
Services.obs.addObserver(this, "Viewport:Change", false);
|
||||||
|
|
||||||
Services.obs.addObserver(XPInstallObserver, "addon-install-blocked", false);
|
|
||||||
Services.obs.addObserver(XPInstallObserver, "addon-install-started", false);
|
|
||||||
|
|
||||||
function showFullScreenWarning() {
|
function showFullScreenWarning() {
|
||||||
NativeWindow.toast.show(Strings.browser.GetStringFromName("alertFullScreenToast"), "short");
|
NativeWindow.toast.show(Strings.browser.GetStringFromName("alertFullScreenToast"), "short");
|
||||||
}
|
}
|
||||||
|
@ -192,6 +189,7 @@ var BrowserApp = {
|
||||||
Downloads.init();
|
Downloads.init();
|
||||||
OfflineApps.init();
|
OfflineApps.init();
|
||||||
IndexedDB.init();
|
IndexedDB.init();
|
||||||
|
XPInstallObserver.init();
|
||||||
|
|
||||||
// Init LoginManager
|
// Init LoginManager
|
||||||
Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
|
Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
|
||||||
|
@ -245,16 +243,13 @@ var BrowserApp = {
|
||||||
let message = Strings.browser.formatStringFromName("telemetry.optin.message", [brandShortName], 1);
|
let message = Strings.browser.formatStringFromName("telemetry.optin.message", [brandShortName], 1);
|
||||||
NativeWindow.doorhanger.show(message, "telemetry-optin", buttons);
|
NativeWindow.doorhanger.show(message, "telemetry-optin", buttons);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
shutdown: function shutdown() {
|
shutdown: function shutdown() {
|
||||||
NativeWindow.uninit();
|
NativeWindow.uninit();
|
||||||
OfflineApps.uninit();
|
OfflineApps.uninit();
|
||||||
IndexedDB.uninit();
|
IndexedDB.uninit();
|
||||||
|
XPInstallObserver.uninit();
|
||||||
Services.obs.removeObserver(XPInstallObserver, "addon-install-blocked");
|
|
||||||
Services.obs.removeObserver(XPInstallObserver, "addon-install-started");
|
|
||||||
},
|
},
|
||||||
|
|
||||||
get tabs() {
|
get tabs() {
|
||||||
|
@ -2001,18 +1996,31 @@ var FormAssistant = {
|
||||||
}
|
}
|
||||||
|
|
||||||
var XPInstallObserver = {
|
var XPInstallObserver = {
|
||||||
|
init: function xpi_init() {
|
||||||
|
Services.obs.addObserver(XPInstallObserver, "addon-install-blocked", false);
|
||||||
|
Services.obs.addObserver(XPInstallObserver, "addon-install-started", false);
|
||||||
|
|
||||||
|
AddonManager.addInstallListener(XPInstallObserver);
|
||||||
|
},
|
||||||
|
|
||||||
|
uninit: function xpi_uninit() {
|
||||||
|
Services.obs.removeObserver(XPInstallObserver, "addon-install-blocked");
|
||||||
|
Services.obs.removeObserver(XPInstallObserver, "addon-install-started");
|
||||||
|
|
||||||
|
AddonManager.removeInstallListener(XPInstallObserver);
|
||||||
|
},
|
||||||
|
|
||||||
observe: function xpi_observer(aSubject, aTopic, aData) {
|
observe: function xpi_observer(aSubject, aTopic, aData) {
|
||||||
switch (aTopic) {
|
switch (aTopic) {
|
||||||
case "addon-install-started":
|
case "addon-install-started":
|
||||||
NativeWindow.toast.show(Strings.browser.GetStringFromName("alertAddonsDownloading"), "short");
|
NativeWindow.toast.show(Strings.browser.GetStringFromName("alertAddonsDownloading"), "short");
|
||||||
break;
|
break;
|
||||||
case "addon-install-blocked":
|
case "addon-install-blocked":
|
||||||
dump("XPInstallObserver addon-install-blocked");
|
|
||||||
let installInfo = aSubject.QueryInterface(Ci.amIWebInstallInfo);
|
let installInfo = aSubject.QueryInterface(Ci.amIWebInstallInfo);
|
||||||
let host = installInfo.originatingURI.host;
|
let host = installInfo.originatingURI.host;
|
||||||
|
|
||||||
let brandShortName = Strings.brand.GetStringFromName("brandShortName");
|
let brandShortName = Strings.brand.GetStringFromName("brandShortName");
|
||||||
let notificationName, buttons, messageString;
|
let notificationName, buttons, message;
|
||||||
let strings = Strings.browser;
|
let strings = Strings.browser;
|
||||||
let enabled = true;
|
let enabled = true;
|
||||||
try {
|
try {
|
||||||
|
@ -2023,10 +2031,10 @@ var XPInstallObserver = {
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
notificationName = "xpinstall-disabled";
|
notificationName = "xpinstall-disabled";
|
||||||
if (Services.prefs.prefIsLocked("xpinstall.enabled")) {
|
if (Services.prefs.prefIsLocked("xpinstall.enabled")) {
|
||||||
messageString = strings.GetStringFromName("xpinstallDisabledMessageLocked");
|
message = strings.GetStringFromName("xpinstallDisabledMessageLocked");
|
||||||
buttons = [];
|
buttons = [];
|
||||||
} else {
|
} else {
|
||||||
messageString = strings.formatStringFromName("xpinstallDisabledMessage2", [brandShortName, host], 2);
|
message = strings.formatStringFromName("xpinstallDisabledMessage2", [brandShortName, host], 2);
|
||||||
buttons = [{
|
buttons = [{
|
||||||
label: strings.GetStringFromName("xpinstallDisabledButton"),
|
label: strings.GetStringFromName("xpinstallDisabledButton"),
|
||||||
callback: function editPrefs() {
|
callback: function editPrefs() {
|
||||||
|
@ -2037,7 +2045,7 @@ var XPInstallObserver = {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
notificationName = "xpinstall";
|
notificationName = "xpinstall";
|
||||||
messageString = strings.formatStringFromName("xpinstallPromptWarning2", [brandShortName, host], 2);
|
message = strings.formatStringFromName("xpinstallPromptWarning2", [brandShortName, host], 2);
|
||||||
|
|
||||||
buttons = [{
|
buttons = [{
|
||||||
label: strings.GetStringFromName("xpinstallPromptAllowButton"),
|
label: strings.GetStringFromName("xpinstallPromptAllowButton"),
|
||||||
|
@ -2048,10 +2056,53 @@ var XPInstallObserver = {
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
NativeWindow.doorhanger.show(messageString, aTopic, buttons);
|
NativeWindow.doorhanger.show(message, aTopic, buttons);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onInstallEnded: function(aInstall, aAddon) {
|
||||||
|
let needsRestart = false;
|
||||||
|
if (aInstall.existingAddon && (aInstall.existingAddon.pendingOperations & AddonManager.PENDING_UPGRADE))
|
||||||
|
needsRestart = true;
|
||||||
|
else if (aAddon.pendingOperations & AddonManager.PENDING_INSTALL)
|
||||||
|
needsRestart = true;
|
||||||
|
|
||||||
|
if (needsRestart) {
|
||||||
|
buttons = [{
|
||||||
|
label: Strings.browser.GetStringFromName("notificationRestart.button"),
|
||||||
|
callback: function() {
|
||||||
|
// Notify all windows that an application quit has been requested
|
||||||
|
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
|
||||||
|
Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
|
||||||
|
|
||||||
|
// If nothing aborted, quit the app
|
||||||
|
if (cancelQuit.data == false) {
|
||||||
|
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
|
||||||
|
appStartup.quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
let message = Strings.browser.GetStringFromName("notificationRestart.normal");
|
||||||
|
NativeWindow.doorhanger.show(message, "addon-app-restart", buttons, BrowserApp.selectedTab.id, { persistence: -1 });
|
||||||
|
} else {
|
||||||
|
let message = Strings.browser.GetStringFromName("alertAddonsInstalledNoRestart");
|
||||||
|
NativeWindow.toast.show(message, "short");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onInstallFailed: function(aInstall) {
|
||||||
|
NativeWindow.toast.show(Strings.browser.GetStringFromName("alertAddonsFail"), "short");
|
||||||
|
},
|
||||||
|
|
||||||
|
onDownloadProgress: function xpidm_onDownloadProgress(aInstall) {},
|
||||||
|
|
||||||
|
onDownloadFailed: function(aInstall) {
|
||||||
|
this.onInstallFailed(aInstall);
|
||||||
|
},
|
||||||
|
|
||||||
|
onDownloadCancelled: function(aInstall) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,6 +5,7 @@ chrome.jar:
|
||||||
|
|
||||||
* content/about.xhtml (content/about.xhtml)
|
* content/about.xhtml (content/about.xhtml)
|
||||||
content/config.xhtml (content/config.xhtml)
|
content/config.xhtml (content/config.xhtml)
|
||||||
|
content/aboutAddons.xhtml (content/aboutAddons.xhtml)
|
||||||
content/aboutCertError.xhtml (content/aboutCertError.xhtml)
|
content/aboutCertError.xhtml (content/aboutCertError.xhtml)
|
||||||
content/aboutHome.xhtml (content/aboutHome.xhtml)
|
content/aboutHome.xhtml (content/aboutHome.xhtml)
|
||||||
* content/aboutRights.xhtml (content/aboutRights.xhtml)
|
* content/aboutRights.xhtml (content/aboutRights.xhtml)
|
||||||
|
@ -26,3 +27,4 @@ chrome.jar:
|
||||||
|
|
||||||
% override chrome://global/content/config.xul chrome://browser/content/config.xhtml
|
% override chrome://global/content/config.xul chrome://browser/content/config.xhtml
|
||||||
% override chrome://global/content/netError.xhtml chrome://browser/content/netError.xhtml
|
% override chrome://global/content/netError.xhtml chrome://browser/content/netError.xhtml
|
||||||
|
% override chrome://mozapps/content/extensions/extensions.xul chrome://browser/content/aboutAddons.xhtml
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
<!ENTITY aboutAddons.title "Add-ons Manager">
|
||||||
|
<!ENTITY aboutAddons.header "Add-ons">
|
|
@ -0,0 +1,6 @@
|
||||||
|
addonAction.enable=Enable
|
||||||
|
addonAction.disable=Disable
|
||||||
|
addonAction.uninstall=Uninstall
|
||||||
|
addonAction.cancel=Cancel
|
||||||
|
addonAction.options=Options
|
||||||
|
addonsSearchEngine.description=Integrated Search
|
|
@ -3,6 +3,8 @@
|
||||||
@AB_CD@.jar:
|
@AB_CD@.jar:
|
||||||
% locale browser @AB_CD@ %locale/@AB_CD@/browser/
|
% locale browser @AB_CD@ %locale/@AB_CD@/browser/
|
||||||
locale/@AB_CD@/browser/about.dtd (%chrome/about.dtd)
|
locale/@AB_CD@/browser/about.dtd (%chrome/about.dtd)
|
||||||
|
locale/@AB_CD@/browser/aboutAddons.dtd (%chrome/aboutAddons.dtd)
|
||||||
|
locale/@AB_CD@/browser/aboutAddons.properties (%chrome/aboutAddons.properties)
|
||||||
locale/@AB_CD@/browser/aboutCertError.dtd (%chrome/aboutCertError.dtd)
|
locale/@AB_CD@/browser/aboutCertError.dtd (%chrome/aboutCertError.dtd)
|
||||||
locale/@AB_CD@/browser/aboutHome.dtd (%chrome/aboutHome.dtd)
|
locale/@AB_CD@/browser/aboutHome.dtd (%chrome/aboutHome.dtd)
|
||||||
locale/@AB_CD@/browser/browser.dtd (%chrome/browser.dtd)
|
locale/@AB_CD@/browser/browser.dtd (%chrome/browser.dtd)
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is Mozilla Mobile Browser.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Mozilla Corporation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Mark Finkle <mfinkle@mozilla.com>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.addons-header {
|
||||||
|
border-bottom: 3px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.addon-item {
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
padding: 8px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.addon-item:last-child {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.addon-item:not([optionsURL]) .options-btn {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make room for the image */
|
||||||
|
.inner {
|
||||||
|
-moz-margin-start: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version {
|
||||||
|
/* The addon title is not localized, so keep the margin on the left side */
|
||||||
|
margin-left: 12px;
|
||||||
|
font-size: 18px;
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body[dir="ltr"] .favicon {
|
||||||
|
left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body[dir="ltr"] .favicon {
|
||||||
|
right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.favicon {
|
||||||
|
border: none;
|
||||||
|
top: 8;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
color: black;
|
||||||
|
font-size: 28px !important;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ chrome.jar:
|
||||||
# and honeycomb sections at the bottom of this file
|
# and honeycomb sections at the bottom of this file
|
||||||
skin/aboutPage.css (aboutPage.css)
|
skin/aboutPage.css (aboutPage.css)
|
||||||
skin/about.css (about.css)
|
skin/about.css (about.css)
|
||||||
|
skin/aboutAddons.css (aboutAddons.css)
|
||||||
skin/aboutHome.css (aboutHome.css)
|
skin/aboutHome.css (aboutHome.css)
|
||||||
* skin/browser.css (browser.css)
|
* skin/browser.css (browser.css)
|
||||||
* skin/content.css (content.css)
|
* skin/content.css (content.css)
|
||||||
|
@ -88,6 +89,7 @@ chrome.jar:
|
||||||
% skin browser gingerbread/1.0 %skin/gingerbread/
|
% skin browser gingerbread/1.0 %skin/gingerbread/
|
||||||
skin/gingerbread/aboutPage.css (aboutPage.css)
|
skin/gingerbread/aboutPage.css (aboutPage.css)
|
||||||
skin/gingerbread/about.css (about.css)
|
skin/gingerbread/about.css (about.css)
|
||||||
|
skin/gingerbread/aboutAddons.css (aboutAddons.css)
|
||||||
skin/gingerbread/aboutHome.css (aboutHome.css)
|
skin/gingerbread/aboutHome.css (aboutHome.css)
|
||||||
* skin/gingerbread/browser.css (gingerbread/browser.css)
|
* skin/gingerbread/browser.css (gingerbread/browser.css)
|
||||||
* skin/gingerbread/content.css (gingerbread/content.css)
|
* skin/gingerbread/content.css (gingerbread/content.css)
|
||||||
|
@ -165,6 +167,7 @@ chrome.jar:
|
||||||
% skin browser honeycomb/1.0 %skin/honeycomb/
|
% skin browser honeycomb/1.0 %skin/honeycomb/
|
||||||
skin/honeycomb/aboutPage.css (aboutPage.css)
|
skin/honeycomb/aboutPage.css (aboutPage.css)
|
||||||
skin/honeycomb/about.css (about.css)
|
skin/honeycomb/about.css (about.css)
|
||||||
|
skin/honeycomb/aboutAddons.css (aboutAddons.css)
|
||||||
skin/honeycomb/aboutHome.css (aboutHome.css)
|
skin/honeycomb/aboutHome.css (aboutHome.css)
|
||||||
* skin/honeycomb/browser.css (honeycomb/browser.css)
|
* skin/honeycomb/browser.css (honeycomb/browser.css)
|
||||||
* skin/honeycomb/content.css (content.css)
|
* skin/honeycomb/content.css (content.css)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче