296566: move extension update into extension manager. 1) add background update timer to check for updates to extensions on a regular basis 2) replace observer service notifications with a new interface nsIAddonUpdateCheckListener 3) rename nsIExtensionDownloadListener to nsIAddonUpdateListener 4) show extension update inline in the extension manager 5) update all UI clients to interfaces in 2 and 3 including mismatch UI etc. 6) remove unnecessary files r=rob_strong@exchangecode.com

This commit is contained in:
ben%bengoodger.com 2005-07-25 17:29:18 +00:00
Родитель 5266d258da
Коммит d86af497d1
27 изменённых файлов: 1080 добавлений и 545 удалений

Просмотреть файл

@ -8,9 +8,9 @@
<!ENTITY cmd.uninstall.label "Uninstall">
<!ENTITY cmd.uninstall.tooltip "Uninstalls the selected Extension">
<!ENTITY cmd.uninstall.accesskey "i">
<!ENTITY cmd.update.label "Update">
<!ENTITY cmd.update.label "Find Updates">
<!ENTITY cmd.update.accesskey "U">
<!ENTITY cmd.update.tooltip "Checks for Updates to your Extensions">
<!ENTITY cmd.update.tooltip "Finds Updates to your Extensions">
<!ENTITY cmd.useTheme.label "Use Theme">
<!ENTITY cmd.useTheme.accesskey "T">
<!ENTITY cmd.useTheme.tooltip "Changes &brandShortName;'s Theme">
@ -49,6 +49,8 @@
<!ENTITY about.tooltip "About">
<!ENTITY homepage.tooltip "Home Page">
<!ENTITY installNow.label "Update Now">
<!ENTITY getMoreExtensions.label "Get More Extensions">
<!ENTITY getMoreExtensions.tooltip "Get More Extensions from addons.mozilla.org">
<!ENTITY getMoreThemes.label "Get More Themes">

Просмотреть файл

@ -2,6 +2,8 @@ aboutWindowTitle=About %S
aboutWindowCloseButton=Close
aboutWindowVersionString=version %S
aboutExtension=About %S...
updatingMessage=Looking for updates to %S...
updateAvailableMessage=A new version of %S (%S) is available.
restartBeforeEnableTitle=Enable Extension
restartBeforeDisableTitle=Disable Extension
restartBeforeEnableMessage=%S will be enabled the next time you restart %S.
@ -85,6 +87,9 @@ cmdInstallTooltipTheme=Install a Theme
dssSwitchAfterRestart=Restart %S to use.
updateFailedMsg=Update failed for this item.
updateDisabledMsg=Update is disabled for this item.
# Default window size for extensions manager and themes manager
# Size in Pixel (e.g. '460')
extensionsManagerWidth=460
@ -94,5 +99,13 @@ themesManagerHeight=380
# The left column in themes manager
# Size in em (e.g. '20em')
# Note: here is the unit 'em' necessary
# Note: the unit string 'em' is necessary here!
themesManagerLeftColumn=20em
updatesAvailableMessage1=%S found updates to the following items:
updatesAvailableMessage2=Click Install Now to download and install the updates.
updatesAvailableAccept=Install Now
updatesAvailableCancel=Later
updatesAvailableTitle=Updates Found
itemFormat=%S %S (New version: %S)

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -79,9 +79,6 @@
<!ENTITY resolveMaxVersion.title "Checking for Compatible Extensions and Themes...">
<!ENTITY resolveMaxVersion.intro1.label "&brandShortName; is checking for compatibility updates to your Extensions and Themes...">
<!ENTITY restart.title "Upgrade Complete">
<!ENTITY restart.updated.label "&brandShortName; successfully downloaded and installed updates. You will have to restart &brandShortName; to complete the update.">
<!ENTITY resetHomepage.label "Use &brandShortName; Start as my Home Page">
<!ENTITY resetHomepage.accesskey "H">
<!ENTITY versioninfo.title "Compatibility Updates">
<!ENTITY versioninfo.intro "Checking for compatibility updates to your Extensions...">

Просмотреть файл

@ -75,7 +75,6 @@
locale/@AB_CD@/mozapps/extensions/extensions.dtd (%chrome/mozapps/extensions/extensions.dtd)
locale/@AB_CD@/mozapps/extensions/extensions.properties (%chrome/mozapps/extensions/extensions.properties)
locale/@AB_CD@/mozapps/extensions/about.dtd (%chrome/mozapps/extensions/about.dtd)
locale/@AB_CD@/mozapps/extensions/finalize.dtd (%chrome/mozapps/extensions/finalize.dtd)
locale/@AB_CD@/mozapps/extensions/update.dtd (%chrome/mozapps/extensions/update.dtd)
locale/@AB_CD@/mozapps/extensions/update.properties (%chrome/mozapps/extensions/update.properties)
locale/@AB_CD@/mozapps/plugins/plugins.dtd (%chrome/mozapps/plugins/plugins.dtd)

Просмотреть файл

@ -69,11 +69,13 @@ const OP_NEEDS_UNINSTALL = "needs-uninstall";
const OP_NEEDS_ENABLE = "needs-enable";
const OP_NEEDS_DISABLE = "needs-disable";
const URI_EXTENSION_UPDATE_DIALOG = "chrome://mozapps/content/extensions/update.xul";
///////////////////////////////////////////////////////////////////////////////
// Utility Functions
function LOG(msg) {
dump("*** " + msg + "\n");
}
function getIDFromResourceURI(aURI)
{
if (aURI.substring(0, PREFIX_ITEM_URI.length) == PREFIX_ITEM_URI)
@ -136,6 +138,13 @@ function onExtensionSelect(aEvent)
aEvent.target.removeAttribute("last-selected");
}
function onExtensionUpdateNow(aEvent)
{
var item = gExtensionManager.getItemForID(getIDFromResourceURI(
aEvent.target.id));
gExtensionManager.addDownloads([item], 1);
}
///////////////////////////////////////////////////////////////////////////////
// Startup, Shutdown
function Startup()
@ -161,6 +170,7 @@ function Startup()
// This persists the last-selected extension
gExtensionsView.addEventListener("select", onExtensionSelect, false);
gExtensionsView.addEventListener("extension-updatenow", onExtensionUpdateNow, false);
// Finally, update the UI.
gExtensionsView.database.AddDataSource(gExtensionManager.datasource);
@ -227,14 +237,17 @@ function Startup()
.getService(Components.interfaces.nsIObserverService);
os.addObserver(gDownloadManager, "xpinstall-download-started", false);
gObserverIndex = gExtensionManager.addDownloadListener(gDownloadManager);
gObserverIndex = gExtensionManager.addUpdateListener(gDownloadManager);
if ("arguments" in window) {
try {
var params = window.arguments[0].QueryInterface(Components.interfaces.nsIDialogParamBlock);
gDownloadManager.addDownloads(params);
}
catch (e) { }
catch (e) {
if (window.arguments[0] == "updatecheck")
performUpdate();
}
}
// Set the tooltips
@ -253,10 +266,11 @@ function Shutdown()
gExtensionsView.removeEventListener("select", onThemeSelect, false);
gExtensionsView.removeEventListener("select", onExtensionSelect, false);
gExtensionsView.removeEventListener("extension-updatenow", onExtensionUpdateNow, false);
gExtensionsView.database.RemoveDataSource(gExtensionManager.datasource);
gExtensionManager.removeDownloadListenerAt(gObserverIndex);
gExtensionManager.removeUpdateListenerAt(gObserverIndex);
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
@ -333,17 +347,20 @@ XPInstallDownloadManager.prototype = {
gExtensionsView.scrollBoxObject.ensureElementIsVisible(gExtensionsView.lastChild);
},
removeDownload: function (aEvent)
getElementForAddon: function(aAddon)
{
var element = document.getElementById(PREFIX_ITEM_URI + aAddon.id);
if (aAddon.id == aAddon.xpiURL)
element = document.getElementById(aAddon.xpiURL);
return element;
},
/////////////////////////////////////////////////////////////////////////////
// nsIExtensionDownloadListener
onStateChange: function (aURL, aState, aValue)
// nsIAddonUpdateListener
onStateChange: function (aAddon, aState, aValue)
{
const nsIXPIProgressDialog = Components.interfaces.nsIXPIProgressDialog;
var element = document.getElementById(aURL);
var element = this.getElementForAddon(aAddon);
if (!element) return;
switch (aState) {
case nsIXPIProgressDialog.DOWNLOAD_START:
@ -366,7 +383,7 @@ XPInstallDownloadManager.prototype = {
extensionsStrings.getString("installInstalling"));
break;
case nsIXPIProgressDialog.INSTALL_DONE:
dump("*** state change = " + aURL + ", state = " + aState + ", value = " + aValue + "\n");
dump("*** state change = " + aAddon.xpiURL + ", state = " + aState + ", value = " + aValue + "\n");
element.setAttribute("state", "done");
extensionsStrings = document.getElementById("extensionsStrings");
element.setAttribute("description",
@ -387,7 +404,7 @@ XPInstallDownloadManager.prototype = {
var brandStrings = sbs.createBundle("chrome://branding/locale/brand.properties");
var brandShortName = brandStrings.GetStringFromName("brandShortName");
var params = [brandShortName, aURL, msg];
var params = [brandShortName, aAddon.xpiURL, msg];
var message = extensionStrings.formatStringFromName("errorInstallMsg", params, params.length);
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
@ -395,10 +412,11 @@ XPInstallDownloadManager.prototype = {
ps.alert(window, title, message);
element.setAttribute("status", msg);
}
// Remove the dummy, since we installed successfully
// Remove the dummy, since we installed successfully (only if we're a URL,
// not a download operation on an existing item.
var type = gWindowState == "extensions" ? nsIUpdateItem.TYPE_EXTENSION
: nsIUpdateItem.TYPE_THEME;
gExtensionManager.removeDownload(aURL);
gExtensionManager.removeDownload(aAddon.xpiURL);
break;
case nsIXPIProgressDialog.DIALOG_CLOSE:
break;
@ -406,13 +424,13 @@ XPInstallDownloadManager.prototype = {
},
_urls: { },
onProgress: function (aURL, aValue, aMaxValue)
onProgress: function (aAddon, aValue, aMaxValue)
{
var element = document.getElementById(aURL);
var element = this.getElementForAddon(aAddon);
if (!element) return;
var percent = Math.round((aValue / aMaxValue) * 100);
if (percent > 1 && !(aURL in this._urls)) {
this._urls[aURL] = true;
if (percent > 1 && !(aAddon.xpiURL in this._urls)) {
this._urls[aAddon.xpiURL] = true;
element.setAttribute("state", "downloading");
}
element.setAttribute("progress", percent);
@ -467,13 +485,119 @@ XPInstallDownloadManager.prototype = {
// nsISupports
QueryInterface: function (aIID)
{
if (!aIID.equals(Components.interfaces.nsIExtensionDownloadListener) &&
if (!aIID.equals(Components.interfaces.nsIAddonUpdateListener) &&
!aIID.equals(Components.interfaces.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
///////////////////////////////////////////////////////////////////////////////
//
// Update Listener
//
function UpdateCheckListener() {
this._addons = [];
}
UpdateCheckListener.prototype = {
/**
* A list of addons we've found updates to in this update check transaction.
*/
_addons: [],
/**
* See nsIExtensionManager.idl
*/
onUpdateStarted: function() {
LOG("Update Started");
var command = document.getElementById("cmd_update");
command.setAttribute("disabled", "true");
},
/**
* See nsIExtensionManager.idl
*/
onUpdateEnded: function() {
LOG("Update Ended");
var command = document.getElementById("cmd_update");
gExtensionsViewController.updateCommand(command);
// Show message to user listing extensions for which updates are available
// and prompt to install now.
if (this._addons.length > 1) {
var strings = document.getElementById("extensionsStrings");
var brandName = document.getElementById("brandStrings").getString("brandShortName");
var params = {
message1: strings.getFormattedString("updatesAvailableMessage1",
[brandName]),
message2: strings.getString("updatesAvailableMessage2"),
title: strings.getString("updatesAvailableTitle"),
buttons: {
accept: { label: strings.getString("updatesAvailableAccept"),
focused: true },
cancel: { label: strings.getString("updatesAvailableCancel") }
}
}
var names = [];
for (var i = 0; i < this._addons.length; ++i) {
var addon = this._addons[i];
var existingItem = gExtensionManager.getItemForID(addon.id);
var name = strings.getFormattedString("itemFormat",
[this._addons[i].name,
existingItem.version,
this._addons[i].version]);
names.push(name);
}
openDialog("chrome://mozapps/content/extensions/list.xul", "",
"titlebar,modal", names, params);
if (params.result == "accept")
gExtensionManager.addDownloads(this._addons, this._addons.length);
}
},
/**
* See nsIExtensionManager.idl
*/
onAddonUpdateStarted: function(addon) {
LOG("Addon Update Started: " + addon.id);
var element = document.getElementById(PREFIX_ITEM_URI + addon.id);
element.setAttribute("loading", "true");
},
/**
* See nsIExtensionManager.idl
*/
onAddonUpdateEnded: function(addon, status) {
LOG("Addon Update Ended: " + addon.id + ", status: " + status);
var element = document.getElementById(PREFIX_ITEM_URI + addon.id);
element.removeAttribute("loading");
const nsIAUCL = Components.interfaces.nsIAddonUpdateCheckListener;
var strings = document.getElementById("extensionsStrings");
switch (status) {
case nsIAUCL.STATUS_UPDATE:
this._addons.push(addon);
break;
case nsIAUCL.STATUS_FAILURE:
element.setAttribute("description", strings.getString("updateFailedMsg"));
break;
case nsIAUCL.STATUS_DISABLED:
element.setAttribute("description", strings.getString("updateDisabledMsg"));
break;
}
},
/**
* See nsISupports.idl
*/
QueryInterface: function(iid) {
if (!iid.equals(Components.interfaces.nsIAddonUpdateCheckListener) &&
!iid.equals(Components.interfaces.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
///////////////////////////////////////////////////////////////////////////////
//
// View Event Handlers
@ -712,6 +836,10 @@ function canWriteToLocation(element)
return installLocation ? installLocation.canAccess : false;
}
function performUpdate()
{
gExtensionsViewController.commands.cmd_update(null);
}
var gExtensionsViewController = {
supportsCommand: function (aCommand)
@ -810,13 +938,16 @@ var gExtensionsViewController = {
onCommandUpdate: function ()
{
var extensionsCommands = document.getElementById("extensionsCommands");
for (var i = 0; i < extensionsCommands.childNodes.length; ++i) {
var command = extensionsCommands.childNodes[i];
for (var i = 0; i < extensionsCommands.childNodes.length; ++i)
this.updateCommand(extensionsCommands.childNodes[i]);
},
updateCommand: function (command)
{
if (this.isCommandEnabled(command.id))
command.removeAttribute("disabled");
else
command.setAttribute("disabled", "true");
}
},
commands: {
@ -913,29 +1044,15 @@ var gExtensionsViewController = {
cmd_update: function (aSelectedItem)
{
var id = aSelectedItem ? getIDFromResourceURI(aSelectedItem.id) : null;
var itemType = gWindowState == "extensions" ? nsIUpdateItem.TYPE_EXTENSION : nsIUpdateItem.TYPE_THEME;
var items = id ? [gExtensionManager.getItemForID(id)] : [];
var ary = Components.classes["@mozilla.org/supports-array;1"]
.createInstance(Components.interfaces.nsISupportsArray);
var updateTypes = Components.classes["@mozilla.org/supports-PRUint8;1"]
.createInstance(Components.interfaces.nsISupportsPRUint8);
updateTypes.data = itemType;
ary.AppendElement(updateTypes);
var sourceEvent = Components.classes["@mozilla.org/supports-PRBool;1"]
.createInstance(Components.interfaces.nsISupportsPRBool);
sourceEvent.data = false;
ary.AppendElement(sourceEvent);
for (var i = 0; i < items.length; ++i)
ary.AppendElement(items[i]);
var features = "chrome,centerscreen,dialog,titlebar";
// This *must* be modal so as not to break startup! This code is invoked before
// the main event loop is initiated (via checkForMismatches).
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher);
ww.openWindow(window, URI_EXTENSION_UPDATE_DIALOG, "", features, ary);
var items = [];
if (!aSelectedItem)
items = gExtensionManager.getItemList(gItemType, { });
else {
var id = getIDFromResourceURI(aSelectedItem.id);
items = [gExtensionManager.getItemForID(id)];
}
var listener = new UpdateCheckListener();
gExtensionManager.update(items, items.length, false, listener);
},
cmd_uninstall: function (aSelectedItem)

Просмотреть файл

@ -73,19 +73,41 @@
<binding id="extension" extends="chrome://mozapps/content/extensions/extensions.xml#extension-base">
<content>
<xul:hbox flex="1">
<xul:vbox pack="start">
<xul:stack class="extension-icon-stack">
<xul:vbox pack="start" align="start">
<xul:image class="extension-icon" xbl:inherits="src=image"
style="width: 32px; max-width: 32px; height: 32px; max-height: 32px;"/>
</xul:vbox>
<xul:vbox pack="end" align="end">
<xul:image class="extension-badge"/>
</xul:vbox>
</xul:stack>
<xul:vbox pack="start" flex="1">
<xul:hbox>
<xul:label class="extension-item-name" xbl:inherits="value=name" crop="center"/>
<xul:label class="extension-item-version" xbl:inherits="value=version"/>
</xul:hbox>
<xul:label class="extension-item-description" xbl:inherits="value=description" crop="right"/>
<xul:hbox>
<xul:image class=""/>
<xul:label class="extension-item-description" xbl:inherits="value=description" crop="right" flex="1"/>
</xul:hbox>
</xul:vbox>
<xul:vbox class="extension-install-button-box" pack="end">
<xul:button anonid="extension-install-button" class="extension-install-button" label="&installNow.label;"/>
</xul:vbox>
</xul:hbox>
</content>
<implementation>
<field name="eventPrefix">"extension-"</field>
</implementation>
<handlers>
<handler event="command">
<![CDATA[
if (event.originalTarget.getAttribute("anonid") == "extension-install-button")
this.fireEvent("updatenow");
]]>
</handler>
</handlers>
</binding>
<binding id="extension-downloading" extends="chrome://mozapps/content/extensions/extensions.xml#extension-base">

Просмотреть файл

@ -219,6 +219,9 @@
<binding subject="?extension"
predicate="http://www.mozilla.org/2004/em-rdf#incompatibleUpdate"
object="?incompatibleUpdate"/>
<binding subject="?extension"
predicate="http://www.mozilla.org/2004/em-rdf#availableUpdateURL"
object="?available-update-url"/>
<binding subject="?extension"
predicate="http://www.mozilla.org/2004/em-rdf#updateable"
object="?updateable"/>
@ -233,6 +236,7 @@
compatible="?compatible" hidden="?hidden"
optionsURL="?options-url" homepageURL="?homepage-url"
aboutURL="?about-url" updateURL="?update-url"
availableUpdateURL="?available-update-url"
previewImage="?previewImage" internalName="?internalName"
opType="?opType" downloadURL="?downloadURL"
state="?state" progress="?progress" status="?status"

Просмотреть файл

Просмотреть файл

@ -0,0 +1,120 @@
# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
# 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 the Extension List UI.
#
# The Initial Developer of the Original Code is Google Inc.
# Portions created by the Initial Developer are Copyright (C) 2005
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Ben Goodger <ben@mozilla.org>
#
# 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 *****
const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
/**
* Initialize the dialog from the parameters supplied via window.arguments
*
* This dialog must be opened modally, the caller can inspect the user action
* after the dialog closes by inspecting the value of the |result| parameter
* on this object which is set to the dlgtype of the button used to close
* the dialog.
*
* window.arguments[0] is an array of strings to display
* window.arguments[1] a JS Object with the following properties:
*
* title: A title string, to be displayed in the title bar of the dialog.
* message1: A message string, displayed above the addon list
* message2: A message string, displayed below the addon list
* message3: A bolded message string, displayed below the addon list
* If no value is supplied for the message, it is not displayed.
* buttons: {
* accept: { label: "A Label for the Accept button",
* focused: true },
* cancel: { label: "A Label for the Cancel button" },
* ...
* },
*
* result: The dlgtype of button that was used to dismiss the dialog.
*/
function init() {
// Fill the addons list
var items = window.arguments[0];
var addons = document.getElementById("addonsChildren");
for (var i = 0; i < items.length; ++i) {
var treeitem = document.createElementNS(kXULNS, "treeitem");
var treerow = document.createElementNS(kXULNS, "treerow");
var treecell = document.createElementNS(kXULNS, "treecell");
treecell.setAttribute("label", items[i]);
treerow.appendChild(treecell);
treeitem.appendChild(treerow);
addons.appendChild(treeitem);
}
var de = document.documentElement;
var params = window.arguments[1];
// Set the messages
var messages = ["message1", "message2", "message3"];
for (var i = 0; i < messages.length; ++i) {
if (messages[i] in params) {
var message = document.getElementById(messages[i]);
message.hidden = false;
message.appendChild(document.createTextNode(params[messages[i]]));
}
}
// Set the window title
if ("title" in params)
document.title = params.title;
// Set up the buttons
if ("buttons" in params) {
var buttons = params.buttons;
var buttonString = "";
for (var buttonType in buttons)
buttonString += "," + buttonType;
dump("*** de.toSource = " + de.localName + "\n");
de.buttons = buttonString.substr(1);
for (buttonType in buttons) {
var button = de.getButton(buttonType);
button.label = buttons[buttonType].label;
if (buttons[buttonType].focused)
button.focus();
button.addEventListener("command", handleButtonCommand, false);
}
}
}
/**
* Watch for the user hitting one of the buttons to dismiss the dialog
* and report the result back to the caller through the |result| property on
* the arguments object.
*/
function handleButtonCommand(event) {
window.arguments[1].result = event.target.getAttribute("dlgtype");
}

Просмотреть файл

@ -0,0 +1,66 @@
<?xml version="1.0"?>
# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
# ***** 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 the Extension List UI.
#
# The Initial Developer of the Original Code is Google Inc.
# Portions created by the Initial Developer are Copyright (C) 2005
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Ben Goodger <ben@mozilla.org>
#
# 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 *****
<?xml-stylesheet href="chrome://global/skin/"?>
<dialog id="addonList" windowtype="Addons:List"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
style="width: 35em;"
buttons="accept,cancel" onload="init();">
<script type="application/x-javascript"
src="chrome://mozapps/content/extensions/list.js"/>
<stringbundle id="extensionsBundle"
src="chrome://mozapps/locale/extensions/extensions.properties"/>
<label id="message1" hidden="true"/>
<separator class="thin"/>
<tree rows="10" hidecolumnpicker="true">
<treecols>
<treecol flex="1" id="nameColumn" hideheader="true"/>
</treecols>
<treechildren id="addonsChildren"/>
</tree>
<separator class="thin"/>
<label id="message2" hidden="true"/>
<separator class="thin"/>
<label class="bold" id="message3" hidden="true"/>
</dialog>

Просмотреть файл

@ -36,7 +36,7 @@
# ***** END LICENSE BLOCK *****
//
// window.arguments[1...] is an array of nsIUpdateItem implementing objects
// window.arguments[...] is an array of nsIUpdateItem implementing objects
// that are to be updated.
// * if the array is empty, all items are updated (like a background update
// check)
@ -66,13 +66,10 @@
//
const nsIUpdateItem = Components.interfaces.nsIUpdateItem;
const nsIAUCL = Components.interfaces.nsIAddonUpdateCheckListener;
const PREF_UPDATE_EXTENSIONS_ENABLED = "extensions.update.enabled";
const PREF_UPDATE_EXTENSIONS_AUTOUPDATEENABLED = "extensions.update.autoUpdateEnabled";
const PREF_UPDATE_EXTENSIONS_COUNT = "extensions.update.count";
const PREF_UPDATE_EXTENSIONS_SEVERITY_THRESHOLD = "extensions.update.severity.threshold";
const PREF_UPDATE_SEVERITY = "update.severity";
var gShowMismatch = null;
var gUpdateTypes = null;
@ -94,35 +91,22 @@ var gUpdateWizard = {
init: function ()
{
gUpdateTypes = window.arguments[0];
gShowMismatch = window.arguments[1];
var items = window.arguments;
if (window.arguments.length == 2) {
this.items = window.arguments;
if (this.items.length == 0) {
var em = Components.classes["@mozilla.org/extensions/manager;1"]
.getService(Components.interfaces.nsIExtensionManager);
items = [0,0].concat(em.getUpdateableItemList(gUpdateTypes, { }));
this.items = em.getUpdateableItemList(nsIUpdateItem.TYPE_ADDON, { });
}
for (var i = 2; i < items.length; ++i)
this.items.push(items[i].QueryInterface(nsIUpdateItem));
var pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
this.shouldSuggestAutoChecking = gShowMismatch &&
var pref =
Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
this.shouldSuggestAutoChecking =
gShowMismatch &&
!pref.getBoolPref(PREF_UPDATE_EXTENSIONS_AUTOUPDATEENABLED);
if (gShowMismatch)
gMismatchPage.init();
else
document.documentElement.advance();
},
uninit: function ()
{
// Ensure all observers are unhooked, just in case something goes wrong or the
// user aborts.
gUpdatePage.uninit();
document.documentElement.currentPage =
document.getElementById("versioninfo");
},
onWizardFinish: function ()
@ -131,24 +115,6 @@ var gUpdateWizard = {
.getService(Components.interfaces.nsIPrefBranch);
if (this.shouldSuggestAutoChecking)
pref.setBoolPref(PREF_EXTENSIONS_UPDATE_ENABLED, this.shouldAutoCheck);
if (this.succeeded) {
// Downloading and Installed Extension
this.clearExtensionUpdatePrefs();
}
// Send an event to refresh any FE notification components.
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
os.notifyObservers(null, "Update:Ended", "1");
},
clearExtensionUpdatePrefs: function ()
{
var pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
if (pref.prefHasUserValue(PREF_UPDATE_EXTENSIONS_COUNT))
pref.clearUserPref(PREF_UPDATE_EXTENSIONS_COUNT);
},
_setUpButton: function (aButtonID, aButtonKey, aDisabled)
@ -211,36 +177,89 @@ var gUpdateWizard = {
}
};
var gMismatchPage = {
init: function ()
var gVersionInfoPage = {
_completeCount: 0,
_totalCount: 0,
onPageShow: function ()
{
var incompatible = document.getElementById("mismatch.incompatible");
for (var i = 0; i < gUpdateWizard.items.length; ++i) {
var item = gUpdateWizard.items[i];
var listitem = document.createElement("listitem");
listitem.setAttribute("label", item.name + " " + item.version);
incompatible.appendChild(listitem);
gUpdateWizard.setButtonLabels(null, true,
"nextButtonText", true,
"cancelButtonText", false);
var em = Components.classes["@mozilla.org/extensions/manager;1"]
.getService(Components.interfaces.nsIExtensionManager);
em.update(gUpdateWizard.items, gUpdateWizard.items.length, true, this);
},
/////////////////////////////////////////////////////////////////////////////
// nsIAddonUpdateCheckListener
onUpdateStarted: function() {
this._totalCount = gUpdateWizard.items.length;
},
onUpdateEnded: function() {
if (gUpdateWizard.items.length > 0) {
// There are still incompatible addons, inform the user.
document.documentElement.currentPage =
document.getElementById("mismatch");
}
else {
// VersionInfo compatibility updates resolved all compatibility problems,
// close this window and continue starting the application...
close();
}
},
onAddonUpdateStarted: function(addon) {
},
onAddonUpdateEnded: function(addon, status) {
if (status == nsIAUCL.STATUS_VERSIONINFO) {
for (var i = 0; i < gUpdateWizard.items.length; ++i) {
var item = gUpdateWizard.items[i].QueryInterface(nsIUpdateItem);
if (addon.id == item.id) {
gUpdateWizard.items.splice(i, 1);
break;
}
}
}
++this._completeCount;
// Update the status text and progress bar
var progress = document.getElementById("versioninfo.progress");
progress.mode = "normal";
progress.value = Math.ceil((this._completeCount / this._totalCount) * 100);
},
/////////////////////////////////////////////////////////////////////////////
// nsISupports
QueryInterface: function(iid) {
if (!iid.equals(Components.interfaces.nsIAddonUpdateCheckListener) &&
!iid.equals(Components.interfaces.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
var gMismatchPage = {
onPageShow: function ()
{
gUpdateWizard.setButtonLabels(null, true,
"mismatchCheckNow", false,
"mismatchDontCheck", false);
document.documentElement.getButton("next").focus();
var incompatible = document.getElementById("mismatch.incompatible");
for (var i = 0; i < gUpdateWizard.items.length; ++i) {
var item = gUpdateWizard.items[i].QueryInterface(nsIUpdateItem);
var listitem = document.createElement("listitem");
listitem.setAttribute("label", item.name + " " + item.version);
incompatible.appendChild(listitem);
}
}
};
var gUpdatePage = {
_completeCount: 0,
_messages: ["Update:Extension:Started",
"Update:Extension:Ended",
"Update:Extension:Item-Started",
"Update:Extension:Item-Ended",
"Update:Extension:Item-Error",
"Update:Ended"],
onPageShow: function ()
{
gUpdateWizard.setButtonLabels(null, true,
@ -248,105 +267,53 @@ var gUpdatePage = {
"cancelButtonText", false);
document.documentElement.getButton("next").focus();
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
for (var i = 0; i < this._messages.length; ++i)
os.addObserver(this, this._messages[i], false);
gUpdateWizard.errorItems = [];
var em = Components.classes["@mozilla.org/extensions/manager;1"]
.getService(Components.interfaces.nsIExtensionManager);
em.update(gUpdateWizard.items, gUpdateWizard.items.length, false);
em.update(gUpdateWizard.items, gUpdateWizard.items.length, false, this);
},
_destroyed: false,
uninit: function ()
{
if (this._destroyed)
return;
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
for (var i = 0; i < this._messages.length; ++i)
os.removeObserver(this, this._messages[i]);
this._destroyed = true;
/////////////////////////////////////////////////////////////////////////////
// nsIAddonUpdateCheckListener
onUpdateStarted: function() {
},
_totalCount: 0,
get totalCount()
{
if (!this._totalCount) {
this._totalCount = gUpdateWizard.items.length;
if (this._totalCount == 0) {
var em = Components.classes["@mozilla.org/extensions/manager;1"]
.getService(Components.interfaces.nsIExtensionManager);
if (!gUpdateTypes)
gUpdateTypes = nsIUpdateItem.TYPE_ADDON;
this._totalCount = em.getUpdateableItemList(gUpdateTypes, {}).length;
}
}
return this._totalCount;
onUpdateEnded: function() {
var nextPage = document.getElementById("noupdates");
if (gUpdateWizard.itemsToUpdate.length > 0)
nextPage = document.getElementById("found");
document.documentElement.currentPage = nextPage;
},
observe: function (aSubject, aTopic, aData)
{
var canFinish = false;
switch (aTopic) {
case "Update:Extension:Started":
break;
case "Update:Extension:Item-Started":
break;
case "Update:Extension:Item-Ended":
var item = aSubject.QueryInterface(Components.interfaces.nsIUpdateItem);
if (aData == "update-check-success")
gUpdateWizard.itemsToUpdate.push(item);
onAddonUpdateStarted: function(addon) {
},
onAddonUpdateEnded: function(addon, status) {
if (status == nsIAUCL.STATUS_UPDATE)
gUpdateWizard.itemsToUpdate.push(addon);
else if (status == nsIAUCL.STATE_ERROR)
gUpdateWizard.errorItems.push(addon);
++this._completeCount;
// Update the status text and progress bar
var updateStrings = document.getElementById("updateStrings");
var status = document.getElementById("checking.status");
var statusString = updateStrings.getFormattedString("checkingPrefix", [item.name]);
var statusString = updateStrings.getFormattedString("checkingPrefix", [addon.name]);
status.setAttribute("value", statusString);
var progress = document.getElementById("checking.progress");
progress.value = Math.ceil((this._completeCount / this.totalCount) * 100);
progress.value = Math.ceil((this._completeCount / gUpdateWizard.items.length) * 100);
},
break;
case "Update:Extension:Item-Error":
var item = aSubject.QueryInterface(Components.interfaces.nsIUpdateItem);
gUpdateWizard.errorItems.push(item);
++this._completeCount;
// Update the status text and progress bar
var updateStrings = document.getElementById("updateStrings");
var status = document.getElementById("checking.status");
var statusString = updateStrings.getFormattedString("checkingPrefix", [item.name]);
status.setAttribute("value", statusString);
var progress = document.getElementById("checking.progress");
progress.value = Math.ceil((this._completeCount / this.totalCount) * 100);
break;
case "Update:Extension:Ended":
canFinish = gUpdateWizard.items.length > 0;
break;
case "Update:Ended":
// If we're doing a general update check, (that is, no specific extensions/themes
// were passed in for us to check for updates to), this notification means both
// extension and app updates have completed.
canFinish = true;
break;
}
if (canFinish) {
gUpdatePage.uninit();
if ((gUpdateTypes & nsIUpdateItem.TYPE_ADDON && gUpdateWizard.itemsToUpdate.length > 0))
document.getElementById("checking").setAttribute("next", "found");
document.documentElement.advance();
}
/////////////////////////////////////////////////////////////////////////////
// nsISupports
QueryInterface: function(iid) {
if (!iid.equals(Components.interfaces.nsIAddonUpdateCheckListener) &&
!iid.equals(Components.interfaces.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
@ -396,10 +363,7 @@ var gFoundPage = {
var updates = document.getElementById("found.updates");
if (!this._initialized) {
this._initialized = true;
updates.computeSizes();
if (gUpdateTypes & nsIUpdateItem.TYPE_ADDON)
this.buildAddons();
}

Просмотреть файл

@ -53,7 +53,6 @@
title="&updateWizard.title;"
windowtype="Update:Wizard"
onload="gUpdateWizard.init();"
onunload="gUpdateWizard.uninit();"
onwizardfinish="gUpdateWizard.onWizardFinish();"
onclose="return gUpdateWizard.onWizardClose(event);"
style="width: 47em; min-height: 35em;"
@ -66,6 +65,19 @@
<stringbundle id="updateStrings" src="chrome://mozapps/locale/extensions/update.properties"/>
</stringbundleset>
<wizardpage id="dummy" pageid="dummy"/>
<wizardpage id="versioninfo" pageid="versioninfo" next="mismatch"
label="&versioninfo.title;"
onpageshow="gVersionInfoPage.onPageShow();">
<progressmeter id="versioninfo.progress" mode="undetermined"/>
<hbox align="center">
<image id="versioninfo.throbber" class="throbber"/>
<label flex="1" crop="right">&versioninfo.intro;</label>
</hbox>
<separator/>
</wizardpage>
<wizardpage id="mismatch" pageid="mismatch" next="checking"
label="&mismatch.title;"
onpageshow="gMismatchPage.onPageShow();">

Просмотреть файл

@ -4,10 +4,12 @@ toolkit.jar:
* content/mozapps/extensions/extensions.js (content/extensions.js)
* content/mozapps/extensions/extensions.xml (content/extensions.xml)
* content/mozapps/extensions/extensions.css (content/extensions.css)
* content/mozapps/extensions/update.xul (content/update.xul)
* content/mozapps/extensions/update.xml (content/update.xml)
* content/mozapps/extensions/update.js (content/update.js)
content/mozapps/extensions/update.css (content/update.css)
* content/mozapps/extensions/about.xul (content/about.xul)
* content/mozapps/extensions/about.js (content/about.js)
* content/mozapps/extensions/finalize.xul (content/finalize.xul)
* content/mozapps/extensions/list.xul (content/list.xul)
* content/mozapps/extensions/list.js (content/list.js)
* content/mozapps/extensions/update.xul (content/update.xul)
* content/mozapps/extensions/update.js (content/update.js)
* content/mozapps/extensions/update.xml (content/update.xml)
* content/mozapps/extensions/update.css (content/update.css)

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -41,6 +41,8 @@
interface nsIFile;
interface nsIRDFDataSource;
interface nsIUpdateItem;
interface nsIAddonUpdateListener;
interface nsIAddonUpdateCheckListener;
interface nsICommandLine;
interface nsISimpleEnumerator;
interface nsIDirectoryEnumerator;
@ -156,37 +158,6 @@ interface nsIInstallLocation : nsISupports
boolean itemIsManagedIndependently(in AString id);
};
/**
* Interface for handling download and install notifications for Extensions
* and Themes.
*/
[scriptable, uuid(9048223f-ec50-49e5-9866-80ee8f26179d)]
interface nsIExtensionDownloadListener : nsISupports
{
/**
* Install/Download state has changed
* @param url
* The url that state changed for
* @param state
* The new state. States are defined in nsIXPIProgressDialog
* @param value
* Some data about the new state
*/
void onStateChange(in AString url, in short state, in long value);
/**
* Progress occurred in the download/install operation
* @param url
* The url that progress occurred for
* @param value
* The value of the current progress
* @param maxValue
* The maximum value |value| can reach
*/
void onProgress(in AString url, in unsigned long value,
in unsigned long maxValue);
};
/**
* Interface representing a system for the installation and management of
* Extensions, Themes etc.
@ -283,10 +254,14 @@ interface nsIExtensionManager : nsISupports
* false if this check should find the newest versions available,
* true if it should only find newer target application compatibility
* information for the currently installed version.
* @param listener
* An nsIAddonUpdateCheckListener object which will be notified during
* the update check process.
*/
void update([array, size_is(itemCount)] in nsIUpdateItem items,
in unsigned long itemCount,
in unsigned long versionUpdateOnly);
in unsigned long versionUpdateOnly,
in nsIAddonUpdateCheckListener listener);
/**
* Gets a nsIUpdateItem for the item with the specified id.
@ -383,14 +358,14 @@ interface nsIExtensionManager : nsISupports
* The listener to add
* @returns the index of the added listen in the listener list.
*/
long addDownloadListener(in nsIExtensionDownloadListener listener);
long addUpdateListener(in nsIAddonUpdateListener listener);
/**
* Removes a download progress listener.
* @param index
* The index of the listener to remove.
*/
void removeDownloadListenerAt(in long index);
void removeUpdateListenerAt(in long index);
/**
* Move an Item to the index of another item in its container.
@ -402,40 +377,6 @@ interface nsIExtensionManager : nsISupports
void moveToIndexOf(in AString movingID, in AString destinationID);
};
/**
* Interface representing an object that can update a set of Extensions,
* Themes etc.
*/
[scriptable, uuid(c0b7517f-0b3a-41a2-bde8-ba3ac8a5af47)]
interface nsIExtensionItemUpdater : nsISupports
{
/**
* Checks for updates to a list of items.
* @param items
* An array of nsIUpdateItems to check for updates for.
* @param itemCount
* The length of |items|
* @param versionUpdateOnly
* false if this check should find the newest versions available,
* true if it should only find newer target application compatibility
* information for the currently installed version.
*/
void checkForUpdates([array, size_is(itemCount)] in nsIUpdateItem items,
in unsigned long itemCount,
in boolean versionUpdateOnly);
/**
* The event that spawned the update check. Types defined in
* nsIUpdateService
*/
readonly attribute unsigned short sourceEvent;
/**
* The nsIUpdateItem types being checked for updates to.
*/
readonly attribute unsigned long updateTypes;
};
/**
* An item managed by the Extension System. Contains metadata that describes
* the item.
@ -521,6 +462,79 @@ interface nsIUpdateItem : nsISupports
readonly attribute AString objectSource;
};
/**
* Interface for handling download and install progress notifications for
* addons.
*/
[scriptable, uuid(bb86037c-98c1-4c22-8e03-1e4c9fc89a8e)]
interface nsIAddonUpdateListener : nsISupports
{
/**
* Install/Download state has changed
* @param addon
* The addon that state changed for
* @param state
* The new state. States are defined in nsIXPIProgressDialog
* @param value
* Some data about the new state
*/
void onStateChange(in nsIUpdateItem addon, in short state, in long value);
/**
* Progress occurred in the download/install operation
* @param addon
* The addon that progress occurred for
* @param value
* The value of the current progress
* @param maxValue
* The maximum value |value| can reach
*/
void onProgress(in nsIUpdateItem addon, in unsigned long value,
in unsigned long maxValue);
};
/**
* Interface for handling notifications during the addon update check process.
*/
[scriptable, uuid(c946119f-9e7c-41aa-a794-803148045350)]
interface nsIAddonUpdateCheckListener : nsISupports
{
/**
* Addon update has begun
*/
void onUpdateStarted();
const unsigned long STATUS_NONE = 0;
const unsigned long STATUS_UPDATE = 1;
const unsigned long STATUS_VERSIONINFO = 2;
const unsigned long STATUS_DATA_FOUND =
STATUS_UPDATE + STATUS_VERSIONINFO;
const unsigned long STATUS_FAILURE = 4;
const unsigned long STATUS_NO_UPDATE = 8;
const unsigned long STATUS_DISABLED = 16;
/**
* Addon update has ended
*/
void onUpdateEnded();
/**
* Update for an individual addon has begun
* @param addon
* A nsIUpdateItem object representing the addon being updated
*/
void onAddonUpdateStarted(in nsIUpdateItem addon);
/**
* Update for an individual addon has ended
* @param addon
* A nsIUpdateItem object representing the addon being updated
* @param status
* The success or failure code of the update operation
*/
void onAddonUpdateEnded(in nsIUpdateItem addon, in long status);
};
%{ C++
/**
* Install Location Key for Application-Global Items

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

Просмотреть файл

@ -89,10 +89,10 @@ extension[selected="true"] {
}
extension {
padding-top: 13px;
padding-bottom: 13px;
-moz-padding-start: 13px;
-moz-padding-end: 10px;
padding-top: 7px;
padding-bottom: 7px;
-moz-padding-start: 7px;
-moz-padding-end: 7px;
min-height: 25px;
border-bottom: 1px dotted #C0C0C0;
background-image: url("chrome://mozapps/skin/shared/itemFader.png");
@ -121,7 +121,7 @@ extension[disabled="true"] .extension-icon {
}
.extension-icon {
-moz-margin-end: 10px;
-moz-margin-end: 2px;
}
.previewText {
@ -150,3 +150,41 @@ extension[itemType="theme"] .extension-icon {
-moz-margin-end: 10px;
}
extension[availableUpdateURL="none"] .extension-badge {
display: none;
}
extension[loading="true"] .extension-badge {
display: -moz-box;
width: 16px;
height: 16px;
margin-bottom: -3px;
-moz-margin-end: -2px;
list-style-image: url("chrome://global/skin/throbber/Throbber-small.gif") !important;
}
.extension-badge {
display: -moz-box;
width: 16px;
height: 16px;
margin-bottom: -3px;
-moz-margin-end: -2px;
list-style-image: url("chrome://mozapps/skin/update/extensionalert.png");
-moz-image-region: rect(0px 48px 16px 32px);
}
extension[availableUpdateURL="none"] .extension-install-button-box {
display: none;
}
.extension-install-button-box {
display: -moz-box;
margin: 0px;
}
.throbber {
width: 16px;
height: 16px;
list-style-image: url("chrome://global/skin/throbber/Throbber-small.gif") !important;
}