Bug 404024: Add AMO integration pane. r=robstrong
|
@ -68,6 +68,15 @@ pref("extensions.logging.enabled", false);
|
|||
// Hides the install button in the add-ons mgr
|
||||
pref("extensions.hideInstallButton", true);
|
||||
|
||||
// Preferences for the Get Add-ons pane
|
||||
pref("extensions.getAddons.showPane", true);
|
||||
pref("extensions.getAddons.browseAddons", "https://%LOCALE%.add-ons.mozilla.com/%LOCALE%/%APP%");
|
||||
pref("extensions.getAddons.maxResults", 5);
|
||||
pref("extensions.getAddons.recommended.browseURL", "https://%LOCALE%.add-ons.mozilla.com/%LOCALE%/%APP%/recommended");
|
||||
pref("extensions.getAddons.recommended.url", "https://services.addons.mozilla.org/%LOCALE%/%APP%/api/list/featured/all/10");
|
||||
pref("extensions.getAddons.search.browseURL", "https://%LOCALE%.add-ons.mozilla.com/%LOCALE%/%APP%/search?q=%TERMS%");
|
||||
pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/%APP%/api/search/%TERMS%");
|
||||
|
||||
// Blocklist preferences
|
||||
pref("extensions.blocklist.enabled", true);
|
||||
pref("extensions.blocklist.interval", 86400);
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
# -*- 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 Manager.
|
||||
#
|
||||
# The Initial Developer of the Original Code is mozilla.org
|
||||
# Portions created by the Initial Developer are Copyright (C) 2008
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Dave Townsend <dtownsend@oxymoronical.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 *****
|
||||
|
||||
function Startup() {
|
||||
var bundle = document.getElementById("extensionsStrings");
|
||||
var label = document.createTextNode(bundle.getFormattedString("eulaHeader", [window.arguments[0].name]));
|
||||
document.getElementById("heading").appendChild(label);
|
||||
document.getElementById("eula").appendChild(document.createTextNode(window.arguments[0].text));
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
<?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 Manager.
|
||||
#
|
||||
# The Initial Developer of the Original Code is mozilla.org
|
||||
# Portions created by the Initial Developer are Copyright (C) 2008
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Dave Townsend <dtownsend@oxymoronical.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 *****
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mozapps/skin/extensions/eula.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
|
||||
%brandDTD;
|
||||
<!ENTITY % extensionsDTD SYSTEM "chrome://mozapps/locale/extensions/extensions.dtd">
|
||||
%extensionsDTD;
|
||||
]>
|
||||
|
||||
<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="&eula.title;" width="&eula.width;" height="&eula.height;"
|
||||
buttons="accept,cancel" buttonlabelaccept="&eula.accept;"
|
||||
ondialogaccept="window.arguments[0].accepted = true"
|
||||
onload="Startup();">
|
||||
|
||||
<script type="application/javascript" src="chrome://mozapps/content/extensions/eula.js"/>
|
||||
|
||||
<stringbundleset id="extensionsSet">
|
||||
<stringbundle id="extensionsStrings" src="chrome://mozapps/locale/extensions/extensions.properties"/>
|
||||
</stringbundleset>
|
||||
|
||||
<label id="heading"/>
|
||||
|
||||
<vbox id="scrollbox" flex="1">
|
||||
<description id="eula"/>
|
||||
</vbox>
|
||||
|
||||
</dialog>
|
|
@ -10,6 +10,46 @@ richlistitem[selected="true"] {
|
|||
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#addon-selected");
|
||||
}
|
||||
|
||||
richlistitem[typeName="searchResult"] {
|
||||
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#searchresult");
|
||||
}
|
||||
|
||||
richlistitem[typeName="searchResult"][selected="true"] {
|
||||
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#searchresult-selected");
|
||||
}
|
||||
|
||||
vbox[typeName="status"][type="search-failure"] {
|
||||
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#status-search-failure");
|
||||
}
|
||||
|
||||
vbox[typeName="status"][type="recommended-failure"] {
|
||||
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#status-recommended-failure");
|
||||
}
|
||||
|
||||
vbox[typeName="status"][type="header-recommended"] {
|
||||
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#status-header-recommended");
|
||||
}
|
||||
|
||||
vbox[typeName="status"][type="footer-recommended"] {
|
||||
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#status-footer-recommended");
|
||||
}
|
||||
|
||||
vbox[typeName="status"][type="footer-search"] {
|
||||
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#status-footer-search");
|
||||
}
|
||||
|
||||
vbox[typeName="status"][type="footer-search"][count="0"] {
|
||||
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#status-footer-search-empty");
|
||||
}
|
||||
|
||||
vbox[typeName="status"][type="retrieve-search"] {
|
||||
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#status-retrieve-search");
|
||||
}
|
||||
|
||||
vbox[typeName="status"][type="retrieve-recommended"] {
|
||||
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#status-retrieve-recommended");
|
||||
}
|
||||
|
||||
richlistitem[typeName="update"] {
|
||||
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#update-found");
|
||||
}
|
||||
|
@ -99,6 +139,10 @@ richlistitem[opType="needs-disable"] hbox.addon-description {
|
|||
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#addon-needs-disable");
|
||||
}
|
||||
|
||||
#searchbox {
|
||||
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#search-textbox");
|
||||
}
|
||||
|
||||
#viewGroup radio {
|
||||
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#viewbutton");
|
||||
-moz-box-orient: vertical;
|
||||
|
@ -148,3 +192,36 @@ richlistitem:not([plugin]) .pluginIcon ,
|
|||
richlistitem[plugin] .addonIcon:not(.pluginIcon) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
richlistitem[action] .addonInstallButton {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.searchResultInstalling, .searchResultFailed, .searchResultInstalled {
|
||||
display: none;
|
||||
}
|
||||
|
||||
richlistitem[action="installing"] .searchResultInstalling {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
richlistitem[action="failed"] .searchResultFailed,
|
||||
richlistitem[action="failed"] .addonInstallButton {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
richlistitem[action="installed"] .searchResultInstalled {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
richlistitem .addonType {
|
||||
display: none;
|
||||
}
|
||||
|
||||
richlistitem[addonType="2"] .addonTypeExtension {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
richlistitem[addonType="4"] .addonTypeTheme {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
|
|
@ -67,6 +67,13 @@ var gInstallCount = 0;
|
|||
var gPendingActions = false;
|
||||
var gPlugins = null;
|
||||
var gPluginsDS = null;
|
||||
var gSearchDS = null;
|
||||
var gAddonRepository = null;
|
||||
var gShowGetAddonsPane = false;
|
||||
var gRetrievedResults = false;
|
||||
var gRecommendedAddons = null;
|
||||
var gRDF = null;
|
||||
var gPendingInstalls = [];
|
||||
|
||||
const PREF_EM_CHECK_COMPATIBILITY = "extensions.checkCompatibility";
|
||||
const PREF_EM_CHECK_UPDATE_SECURITY = "extensions.checkUpdateSecurity";
|
||||
|
@ -79,6 +86,9 @@ const PREF_EXTENSIONS_HIDE_INSTALL_BTN = "extensions.hideInstallButton";
|
|||
const PREF_EM_LAST_SELECTED_SKIN = "extensions.lastSelectedSkin";
|
||||
const PREF_GENERAL_SKINS_SELECTEDSKIN = "general.skins.selectedSkin";
|
||||
const PREF_UPDATE_NOTIFYUSER = "extensions.update.notifyUser";
|
||||
const PREF_GETADDONS_SHOWPANE = "extensions.getAddons.showPane";
|
||||
const PREF_GETADDONS_REPOSITORY = "extensions.getAddons.repository";
|
||||
const PREF_GETADDONS_MAXRESULTS = "extensions.getAddons.maxResults";
|
||||
|
||||
const URI_GENERIC_ICON_XPINSTALL = "chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png";
|
||||
const URI_GENERIC_ICON_THEME = "chrome://mozapps/skin/extensions/themeGeneric.png";
|
||||
|
@ -108,6 +118,14 @@ function setElementDisabledByID(aID, aDoDisable) {
|
|||
}
|
||||
}
|
||||
|
||||
function isSafeURI(aURI) {
|
||||
try {
|
||||
var uri = makeURI(aURI);
|
||||
var scheme = uri.scheme;
|
||||
} catch (ex) {}
|
||||
return (uri && (scheme == "http" || scheme == "https" || scheme == "ftp"));
|
||||
}
|
||||
|
||||
function getBrandShortName() {
|
||||
var brandStrings = document.getElementById("brandStrings");
|
||||
return brandStrings.getString("brandShortName");
|
||||
|
@ -158,23 +176,17 @@ function showMessage(aIconURL, aMessage, aButtonLabel, aButtonAccesskey,
|
|||
|
||||
// dynamically creates a template
|
||||
var AddonsViewBuilder = {
|
||||
_bindingList: null,
|
||||
_actionList: null,
|
||||
|
||||
// if aActionList is null aBindingList will be used to generate actions
|
||||
updateView: function(aRulesList, aURI, aBindingList, aActionList)
|
||||
updateView: function(aRulesList, aURIList, aBindingList, aActionList)
|
||||
{
|
||||
this._bindingList = aBindingList;
|
||||
this._actionList = aActionList ? aActionList : aBindingList;
|
||||
var actionList = aActionList ? aActionList : aBindingList;
|
||||
|
||||
this.clearChildren(gExtensionsView);
|
||||
var template = document.createElementNS(kXULNSURI, "template");
|
||||
gExtensionsView.appendChild(template);
|
||||
for (var i = 0; i < aRulesList.length; ++i)
|
||||
template.appendChild(this.createRule(aRulesList[i], aURI));
|
||||
template.appendChild(this.createRule(aRulesList[i], aURIList[i], aBindingList[i], actionList[i]));
|
||||
|
||||
this._bindingList = null;
|
||||
this._actionList = null;
|
||||
gExtensionsView.builder.rebuild();
|
||||
},
|
||||
|
||||
|
@ -184,7 +196,7 @@ var AddonsViewBuilder = {
|
|||
aEl.removeChild(aEl.lastChild);
|
||||
},
|
||||
|
||||
createRule: function(aTriplesList, aURI)
|
||||
createRule: function(aTriplesList, aURI, aBindingList, aActionList)
|
||||
{
|
||||
var rule = document.createElementNS(kXULNSURI, "rule");
|
||||
var conditions = document.createElementNS(kXULNSURI, "conditions");
|
||||
|
@ -202,16 +214,16 @@ var AddonsViewBuilder = {
|
|||
|
||||
var bindings = document.createElementNS(kXULNSURI, "bindings");
|
||||
rule.appendChild(bindings);
|
||||
for (i = 0; i < this._bindingList.length; ++i)
|
||||
bindings.appendChild(this.createBinding(this._bindingList[i], aURI));
|
||||
for (i = 0; i < aBindingList.length; ++i)
|
||||
bindings.appendChild(this.createBinding(aBindingList[i], aURI));
|
||||
|
||||
var action = document.createElementNS(kXULNSURI, "action");
|
||||
rule.appendChild(action);
|
||||
var extension = document.createElementNS(kXULNSURI, aURI);
|
||||
action.appendChild(extension);
|
||||
extension.setAttribute("uri", "?" + aURI);
|
||||
for (i = 0; i < this._actionList.length; ++i)
|
||||
extension.setAttribute(this._actionList[i][0], this._actionList[i][1]);
|
||||
for (i = 0; i < aActionList.length; ++i)
|
||||
extension.setAttribute(aActionList[i][0], aActionList[i][1]);
|
||||
|
||||
return rule;
|
||||
},
|
||||
|
@ -256,31 +268,32 @@ function showView(aView) {
|
|||
// Using disabled to represent add-on state in regards to the EM causes evil
|
||||
// focus behavior when used as an element attribute when the element isn't
|
||||
// really disabled.
|
||||
var bindingList = [ ["aboutURL", "?aboutURL"],
|
||||
["addonID", "?addonID"],
|
||||
["availableUpdateURL", "?availableUpdateURL"],
|
||||
["availableUpdateVersion", "?availableUpdateVersion"],
|
||||
["blocklisted", "?blocklisted"],
|
||||
["compatible", "?compatible"],
|
||||
["description", "?description"],
|
||||
["downloadURL", "?downloadURL"],
|
||||
["isDisabled", "?isDisabled"],
|
||||
["hidden", "?hidden"],
|
||||
["homepageURL", "?homepageURL"],
|
||||
["iconURL", "?iconURL"],
|
||||
["internalName", "?internalName"],
|
||||
["locked", "?locked"],
|
||||
["name", "?name"],
|
||||
["optionsURL", "?optionsURL"],
|
||||
["opType", "?opType"],
|
||||
["plugin", "?plugin"],
|
||||
["previewImage", "?previewImage"],
|
||||
["satisfiesDependencies", "?satisfiesDependencies"],
|
||||
["providesUpdatesSecurely", "?providesUpdatesSecurely"],
|
||||
["type", "?type"],
|
||||
["updateable", "?updateable"],
|
||||
["updateURL", "?updateURL"],
|
||||
["version", "?version"] ];
|
||||
var bindingList = [ [ ["aboutURL", "?aboutURL"],
|
||||
["addonID", "?addonID"],
|
||||
["availableUpdateURL", "?availableUpdateURL"],
|
||||
["availableUpdateVersion", "?availableUpdateVersion"],
|
||||
["blocklisted", "?blocklisted"],
|
||||
["compatible", "?compatible"],
|
||||
["description", "?description"],
|
||||
["downloadURL", "?downloadURL"],
|
||||
["isDisabled", "?isDisabled"],
|
||||
["hidden", "?hidden"],
|
||||
["homepageURL", "?homepageURL"],
|
||||
["iconURL", "?iconURL"],
|
||||
["internalName", "?internalName"],
|
||||
["locked", "?locked"],
|
||||
["name", "?name"],
|
||||
["optionsURL", "?optionsURL"],
|
||||
["opType", "?opType"],
|
||||
["plugin", "?plugin"],
|
||||
["previewImage", "?previewImage"],
|
||||
["satisfiesDependencies", "?satisfiesDependencies"],
|
||||
["providesUpdatesSecurely", "?providesUpdatesSecurely"],
|
||||
["type", "?type"],
|
||||
["updateable", "?updateable"],
|
||||
["updateURL", "?updateURL"],
|
||||
["version", "?version"] ] ];
|
||||
var displays = [ "richlistitem" ];
|
||||
|
||||
var prefURL;
|
||||
var showInstallFile = true;
|
||||
|
@ -293,9 +306,35 @@ function showView(aView) {
|
|||
var showSkip = false;
|
||||
var showContinue = false;
|
||||
switch (aView) {
|
||||
case "search":
|
||||
var bindingList = [ [ ["action", "?action"],
|
||||
["addonID", "?addonID"],
|
||||
["description", "?description"],
|
||||
["eula", "?eula"],
|
||||
["homepageURL", "?homepageURL"],
|
||||
["iconURL", "?iconURL"],
|
||||
["name", "?name"],
|
||||
["previewImage", "?previewImage"],
|
||||
["rating", "?rating"],
|
||||
["addonType", "?addonType"],
|
||||
["thumbnailURL", "?thumbnailURL"],
|
||||
["version", "?version"],
|
||||
["xpiHash", "?xpiHash"],
|
||||
["xpiURL", "?xpiURL"],
|
||||
["typeName", "searchResult"] ],
|
||||
[ ["type", "?type"],
|
||||
["typeName", "status"],
|
||||
["count", "?count"],
|
||||
["link", "?link" ] ] ];
|
||||
var types = [ [ ["searchResult", "true", null] ],
|
||||
[ ["statusMessage", "true", null] ] ];
|
||||
var displays = [ "richlistitem", "vbox" ];
|
||||
showCheckUpdatesAll = false;
|
||||
document.getElementById("searchbox").disabled = isOffline("offlineSearchMsg");
|
||||
break;
|
||||
case "extensions":
|
||||
prefURL = PREF_EXTENSIONS_GETMOREEXTENSIONSURL;
|
||||
var types = [ [ ["type", nsIUpdateItem.TYPE_EXTENSION, "Integer"] ] ];
|
||||
types = [ [ ["type", nsIUpdateItem.TYPE_EXTENSION, "Integer"] ] ];
|
||||
break;
|
||||
case "themes":
|
||||
prefURL = PREF_EXTENSIONS_GETMORETHEMESURL;
|
||||
|
@ -315,24 +354,24 @@ function showView(aView) {
|
|||
showInstallUpdatesAll = true;
|
||||
if (gUpdatesOnly)
|
||||
showSkip = true;
|
||||
bindingList = [ ["aboutURL", "?aboutURL"],
|
||||
["availableUpdateURL", "?availableUpdateURL"],
|
||||
["availableUpdateVersion", "?availableUpdateVersion"],
|
||||
["availableUpdateInfo", "?availableUpdateInfo"],
|
||||
["blocklisted", "?blocklisted"],
|
||||
["homepageURL", "?homepageURL"],
|
||||
["iconURL", "?iconURL"],
|
||||
["internalName", "?internalName"],
|
||||
["locked", "?locked"],
|
||||
["name", "?name"],
|
||||
["opType", "?opType"],
|
||||
["previewImage", "?previewImage"],
|
||||
["satisfiesDependencies", "?satisfiesDependencies"],
|
||||
["providesUpdatesSecurely", "?providesUpdatesSecurely"],
|
||||
["type", "?type"],
|
||||
["updateURL", "?updateURL"],
|
||||
["version", "?version"],
|
||||
["typeName", "update"] ];
|
||||
bindingList = [ [ ["aboutURL", "?aboutURL"],
|
||||
["availableUpdateURL", "?availableUpdateURL"],
|
||||
["availableUpdateVersion", "?availableUpdateVersion"],
|
||||
["availableUpdateInfo", "?availableUpdateInfo"],
|
||||
["blocklisted", "?blocklisted"],
|
||||
["homepageURL", "?homepageURL"],
|
||||
["iconURL", "?iconURL"],
|
||||
["internalName", "?internalName"],
|
||||
["locked", "?locked"],
|
||||
["name", "?name"],
|
||||
["opType", "?opType"],
|
||||
["previewImage", "?previewImage"],
|
||||
["satisfiesDependencies", "?satisfiesDependencies"],
|
||||
["providesUpdatesSecurely", "?providesUpdatesSecurely"],
|
||||
["type", "?type"],
|
||||
["updateURL", "?updateURL"],
|
||||
["version", "?version"],
|
||||
["typeName", "update"] ] ];
|
||||
types = [ [ ["availableUpdateVersion", "?availableUpdateVersion", null],
|
||||
["updateable", "true", null] ] ];
|
||||
break;
|
||||
|
@ -343,40 +382,40 @@ function showView(aView) {
|
|||
showInstallUpdatesAll = false;
|
||||
if (gUpdatesOnly)
|
||||
showContinue = true;
|
||||
bindingList = [ ["aboutURL", "?aboutURL"],
|
||||
["addonID", "?addonID"],
|
||||
["availableUpdateURL", "?availableUpdateURL"],
|
||||
["availableUpdateVersion", "?availableUpdateVersion"],
|
||||
["blocklisted", "?blocklisted"],
|
||||
["compatible", "?compatible"],
|
||||
["description", "?description"],
|
||||
["downloadURL", "?downloadURL"],
|
||||
["incompatibleUpdate", "?incompatibleUpdate"],
|
||||
["isDisabled", "?isDisabled"],
|
||||
["hidden", "?hidden"],
|
||||
["homepageURL", "?homepageURL"],
|
||||
["iconURL", "?iconURL"],
|
||||
["internalName", "?internalName"],
|
||||
["locked", "?locked"],
|
||||
["name", "?name"],
|
||||
["optionsURL", "?optionsURL"],
|
||||
["opType", "?opType"],
|
||||
["previewImage", "?previewImage"],
|
||||
["progress", "?progress"],
|
||||
["state", "?state"],
|
||||
["type", "?type"],
|
||||
["updateable", "?updateable"],
|
||||
["updateURL", "?updateURL"],
|
||||
["version", "?version"],
|
||||
["newVersion", "?newVersion"],
|
||||
["typeName", "install"] ];
|
||||
bindingList = [ [ ["aboutURL", "?aboutURL"],
|
||||
["addonID", "?addonID"],
|
||||
["availableUpdateURL", "?availableUpdateURL"],
|
||||
["availableUpdateVersion", "?availableUpdateVersion"],
|
||||
["blocklisted", "?blocklisted"],
|
||||
["compatible", "?compatible"],
|
||||
["description", "?description"],
|
||||
["downloadURL", "?downloadURL"],
|
||||
["incompatibleUpdate", "?incompatibleUpdate"],
|
||||
["isDisabled", "?isDisabled"],
|
||||
["hidden", "?hidden"],
|
||||
["homepageURL", "?homepageURL"],
|
||||
["iconURL", "?iconURL"],
|
||||
["internalName", "?internalName"],
|
||||
["locked", "?locked"],
|
||||
["name", "?name"],
|
||||
["optionsURL", "?optionsURL"],
|
||||
["opType", "?opType"],
|
||||
["previewImage", "?previewImage"],
|
||||
["progress", "?progress"],
|
||||
["state", "?state"],
|
||||
["type", "?type"],
|
||||
["updateable", "?updateable"],
|
||||
["updateURL", "?updateURL"],
|
||||
["version", "?version"],
|
||||
["newVersion", "?newVersion"],
|
||||
["typeName", "install"] ] ];
|
||||
types = [ [ ["state", "?state", null] ] ];
|
||||
break;
|
||||
}
|
||||
|
||||
var showGetMore = false;
|
||||
var getMore = document.getElementById("getMore");
|
||||
if (prefURL) {
|
||||
if (prefURL && !gShowGetAddonsPane) {
|
||||
try {
|
||||
getMore.setAttribute("value", getMore.getAttribute("value" + aView));
|
||||
var getMoreURL = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
|
||||
|
@ -409,8 +448,9 @@ function showView(aView) {
|
|||
document.getElementById("themeSplitter").hidden = !isThemes;
|
||||
document.getElementById("showUpdateInfoButton").hidden = aView != "updates";
|
||||
document.getElementById("hideUpdateInfoButton").hidden = true;
|
||||
document.getElementById("searchPanel").hidden = aView != "search";
|
||||
|
||||
AddonsViewBuilder.updateView(types, "richlistitem", bindingList, null);
|
||||
AddonsViewBuilder.updateView(types, displays, bindingList, null);
|
||||
|
||||
if (aView == "updates" || aView == "installs")
|
||||
gExtensionsView.selectedItem = gExtensionsView.children[0];
|
||||
|
@ -524,6 +564,268 @@ function setRestartMessage(aItem)
|
|||
aItem.setAttribute("description", restartMessage);
|
||||
}
|
||||
|
||||
// Removes any assertions in the datasource about a given resource
|
||||
function cleanResource(ds, resource) {
|
||||
// Remove outward arcs
|
||||
var arcs = ds.ArcLabelsOut(resource);
|
||||
while (arcs.hasMoreElements()) {
|
||||
var arc = arcs.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
|
||||
var targets = ds.GetTargets(resource, arc, true);
|
||||
while (targets.hasMoreElements()) {
|
||||
var value = targets.getNext().QueryInterface(Components.interfaces.nsIRDFNode);
|
||||
if (value)
|
||||
ds.Unassert(resource, arc, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wipes the datasource clean of assertions
|
||||
function cleanDataSource(ds, rootctr) {
|
||||
// Remove old entries from the list
|
||||
var nodes = rootctr.GetElements();
|
||||
while (nodes.hasMoreElements()) {
|
||||
var node = nodes.getNext()
|
||||
.QueryInterface(Components.interfaces.nsIRDFResource);
|
||||
rootctr.RemoveElement(node, false);
|
||||
cleanResource(ds, node);
|
||||
}
|
||||
}
|
||||
|
||||
// Displays the search status message
|
||||
function displaySearchThrobber(aKey) {
|
||||
var rdfCU = Components.classes["@mozilla.org/rdf/container-utils;1"]
|
||||
.getService(Components.interfaces.nsIRDFContainerUtils);
|
||||
var rootctr = rdfCU.MakeSeq(gSearchDS, gRDF.GetResource(RDFURI_ITEM_ROOT));
|
||||
|
||||
cleanDataSource(gSearchDS, rootctr);
|
||||
|
||||
var labelNode = gRDF.GetResource("urn:mozilla:addons:search:status:header");
|
||||
rootctr.AppendElement(labelNode);
|
||||
gSearchDS.Assert(labelNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "statusMessage"),
|
||||
gRDF.GetLiteral("true"),
|
||||
true);
|
||||
gSearchDS.Assert(labelNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "type"),
|
||||
gRDF.GetLiteral(aKey),
|
||||
true);
|
||||
}
|
||||
|
||||
// Clears the search box and updates the result list
|
||||
function resetSearch() {
|
||||
var searchbox = document.getElementById("searchbox");
|
||||
searchbox.value = "";
|
||||
retrieveRepositoryAddons("");
|
||||
}
|
||||
|
||||
// Searches for results
|
||||
function retrieveRepositoryAddons(aTerms) {
|
||||
if (gAddonRepository.isSearching)
|
||||
gAddonRepository.cancelSearch();
|
||||
if (aTerms) {
|
||||
displaySearchThrobber("retrieve-search");
|
||||
gAddonRepository.searchAddons(aTerms,
|
||||
gPref.getIntPref(PREF_GETADDONS_MAXRESULTS),
|
||||
AddonSearchResults);
|
||||
}
|
||||
else {
|
||||
if (gRecommendedAddons) {
|
||||
displaySearchResults(gRecommendedAddons, -1, true);
|
||||
}
|
||||
else {
|
||||
displaySearchThrobber("retrieve-recommended");
|
||||
gAddonRepository.retrieveRecommendedAddons(gPref.getIntPref(PREF_GETADDONS_MAXRESULTS),
|
||||
RecommendedSearchResults);
|
||||
}
|
||||
}
|
||||
gRetrievedResults = true;
|
||||
}
|
||||
|
||||
// Puts search results into the search datasource
|
||||
function displaySearchResults(addons, count, isRecommended) {
|
||||
var rdfCU = Components.classes["@mozilla.org/rdf/container-utils;1"]
|
||||
.getService(Components.interfaces.nsIRDFContainerUtils);
|
||||
var rootctr = rdfCU.MakeSeq(gSearchDS, gRDF.GetResource(RDFURI_ITEM_ROOT));
|
||||
|
||||
gSearchDS.beginUpdateBatch();
|
||||
|
||||
cleanDataSource(gSearchDS, rootctr);
|
||||
|
||||
if (isRecommended) {
|
||||
var labelNode = gRDF.GetResource("urn:mozilla:addons:search:status:header");
|
||||
rootctr.AppendElement(labelNode);
|
||||
gSearchDS.Assert(labelNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "statusMessage"),
|
||||
gRDF.GetLiteral("true"),
|
||||
true);
|
||||
gSearchDS.Assert(labelNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "type"),
|
||||
gRDF.GetLiteral("header-recommended"),
|
||||
true);
|
||||
|
||||
// Case insensitive sort
|
||||
function compare(a, b) {
|
||||
if (a.name.toLowerCase() < b.name.toLowerCase())
|
||||
return -1;
|
||||
if (a.name.toLowerCase() > b.name.toLowerCase())
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
addons.sort(compare);
|
||||
}
|
||||
|
||||
var urlproperties = [ "iconURL", "homepageURL", "thumbnailURL", "xpiURL" ];
|
||||
var properties = [ "name", "eula", "iconURL", "homepageURL", "thumbnailURL", "xpiURL", "xpiHash" ];
|
||||
for (var i = 0; i < addons.length; i++) {
|
||||
var addon = addons[i];
|
||||
// Strip out any items with potentially unsafe urls
|
||||
var unsafe = false;
|
||||
for (var j = 0; j < urlproperties.length; j++) {
|
||||
if (!isSafeURI(addon[urlproperties[j]])) {
|
||||
unsafe = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (unsafe)
|
||||
continue;
|
||||
|
||||
var resultNode = gRDF.GetResource("urn:mozilla:addons:search:" + addon.xpiURL);
|
||||
gSearchDS.Assert(resultNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "addonID"),
|
||||
gRDF.GetLiteral(addon.id),
|
||||
true);
|
||||
// Use the short summary for our "description"
|
||||
gSearchDS.Assert(resultNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "description"),
|
||||
gRDF.GetLiteral(addon.summary),
|
||||
true);
|
||||
gSearchDS.Assert(resultNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "addonType"),
|
||||
gRDF.GetIntLiteral(addon.type),
|
||||
true);
|
||||
if (addon.rating >= 0) {
|
||||
gSearchDS.Assert(resultNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "rating"),
|
||||
gRDF.GetIntLiteral(addon.rating),
|
||||
gRDF.GetIntLiteral(3),
|
||||
true);
|
||||
}
|
||||
|
||||
for (var j = 0; j < properties.length; j++) {
|
||||
gSearchDS.Assert(resultNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + properties[j]),
|
||||
gRDF.GetLiteral(addon[properties[j]]),
|
||||
true);
|
||||
}
|
||||
gSearchDS.Assert(resultNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "searchResult"),
|
||||
gRDF.GetLiteral("true"),
|
||||
true);
|
||||
rootctr.AppendElement(resultNode);
|
||||
}
|
||||
|
||||
labelNode = gRDF.GetResource("urn:mozilla:addons:search:status:footer");
|
||||
rootctr.AppendElement(labelNode);
|
||||
gSearchDS.Assert(labelNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "statusMessage"),
|
||||
gRDF.GetLiteral("true"),
|
||||
true);
|
||||
if (isRecommended) {
|
||||
gSearchDS.Assert(labelNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "type"),
|
||||
gRDF.GetLiteral("footer-recommended"),
|
||||
true);
|
||||
var url = gAddonRepository.getRecommendedURL();
|
||||
}
|
||||
else {
|
||||
gSearchDS.Assert(labelNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "type"),
|
||||
gRDF.GetLiteral("footer-search"),
|
||||
true);
|
||||
gSearchDS.Assert(labelNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "count"),
|
||||
gRDF.GetIntLiteral(count),
|
||||
true);
|
||||
var searchbox = document.getElementById("searchbox");
|
||||
// The value attribute will be the persisted value of the last search run
|
||||
url = gAddonRepository.getSearchURL(searchbox.getAttribute("value"));
|
||||
}
|
||||
gSearchDS.Assert(labelNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "link"),
|
||||
gRDF.GetLiteral(url),
|
||||
true);
|
||||
|
||||
gSearchDS.endUpdateBatch();
|
||||
}
|
||||
|
||||
// Displays the search failure status message
|
||||
function displaySearchFailure(isRecommended) {
|
||||
var rdfCU = Components.classes["@mozilla.org/rdf/container-utils;1"]
|
||||
.getService(Components.interfaces.nsIRDFContainerUtils);
|
||||
var rootctr = rdfCU.MakeSeq(gSearchDS, gRDF.GetResource(RDFURI_ITEM_ROOT));
|
||||
|
||||
cleanDataSource(gSearchDS, rootctr);
|
||||
|
||||
var labelNode = gRDF.GetResource("urn:mozilla:addons:search:status:header");
|
||||
rootctr.AppendElement(labelNode);
|
||||
gSearchDS.Assert(labelNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "statusMessage"),
|
||||
gRDF.GetLiteral("true"),
|
||||
true);
|
||||
gSearchDS.Assert(labelNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "type"),
|
||||
gRDF.GetLiteral(isRecommended ? "recommended-failure" : "search-failure"),
|
||||
true);
|
||||
}
|
||||
|
||||
// nsIAddonSearchResultsCallback for the recommended search
|
||||
var RecommendedSearchResults = {
|
||||
searchSucceeded: function(aAddons, aAddonCount, aTotalResults) {
|
||||
gRecommendedAddons = aAddons;
|
||||
displaySearchResults(aAddons, aTotalResults, true);
|
||||
},
|
||||
|
||||
searchFailed: function() {
|
||||
displaySearchFailure(true);
|
||||
}
|
||||
}
|
||||
|
||||
// nsIAddonSearchResultsCallback for a standard search
|
||||
var AddonSearchResults = {
|
||||
searchSucceeded: function(aAddons, aAddonCount, aTotalResults) {
|
||||
displaySearchResults(aAddons, aTotalResults, false);
|
||||
},
|
||||
|
||||
searchFailed: function() {
|
||||
displaySearchFailure(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialises the search repository and the results datasource
|
||||
function initSearchDS() {
|
||||
var repository = "@mozilla.org/extensions/addon-repository;1";
|
||||
try {
|
||||
var repo = gPref.getCharPref(PREF_GETADDONS_REPOSITORY);
|
||||
if (repo in Components.classes)
|
||||
repository = repo;
|
||||
} catch (e) { }
|
||||
gAddonRepository = Components.classes[repository]
|
||||
.createInstance(Components.interfaces.nsIAddonRepository);
|
||||
var browseAddons = document.getElementById("browseAddons");
|
||||
var homepage = gAddonRepository.homepageURL;
|
||||
if (homepage)
|
||||
browseAddons.setAttribute("homepageURL", homepage);
|
||||
else
|
||||
browseAddons.hidden = true;
|
||||
gSearchDS = Components.classes["@mozilla.org/rdf/datasource;1?name=in-memory-datasource"]
|
||||
.createInstance(Components.interfaces.nsIRDFDataSource);
|
||||
gExtensionsView.database.AddDataSource(gSearchDS);
|
||||
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(nsIIOService);
|
||||
if (!ioService.offline)
|
||||
retrieveRepositoryAddons(document.getElementById("searchbox").value);
|
||||
}
|
||||
|
||||
function initPluginsDS()
|
||||
{
|
||||
gPluginsDS = Components.classes["@mozilla.org/rdf/datasource;1?name=in-memory-datasource"]
|
||||
|
@ -536,23 +838,15 @@ function rebuildPluginsDS()
|
|||
var phs = Components.classes["@mozilla.org/plugin/host;1"]
|
||||
.getService(Components.interfaces.nsIPluginHost);
|
||||
var plugins = phs.getPluginTags({ });
|
||||
var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"]
|
||||
.getService(Components.interfaces.nsIRDFService);
|
||||
var rdfCU = Components.classes["@mozilla.org/rdf/container-utils;1"]
|
||||
.getService(Components.interfaces.nsIRDFContainerUtils);
|
||||
var rootctr = rdfCU.MakeSeq(gPluginsDS, rdf.GetResource(RDFURI_ITEM_ROOT));
|
||||
var rootctr = rdfCU.MakeSeq(gPluginsDS, gRDF.GetResource(RDFURI_ITEM_ROOT));
|
||||
gPlugins = { };
|
||||
|
||||
// Running in a batch stops the template builder from running
|
||||
gPluginsDS.beginUpdateBatch();
|
||||
|
||||
// Remove old entries from the list
|
||||
var nodes = rootctr.GetElements();
|
||||
while (nodes.hasMoreElements()) {
|
||||
var node = nodes.getNext()
|
||||
.QueryInterface(Components.interfaces.nsIRDFResource);
|
||||
rootctr.RemoveElement(node, false);
|
||||
}
|
||||
cleanDataSource(gPluginsDS, rootctr);
|
||||
|
||||
// Case insensitive sort
|
||||
function compare(a, b) {
|
||||
|
@ -592,40 +886,40 @@ function rebuildPluginsDS()
|
|||
for (var pluginName in gPlugins) {
|
||||
for (var pluginDesc in gPlugins[pluginName]) {
|
||||
plugin = gPlugins[pluginName][pluginDesc];
|
||||
var pluginNode = rdf.GetResource(PREFIX_ITEM_URI + plugin.filename);
|
||||
var pluginNode = gRDF.GetResource(PREFIX_ITEM_URI + plugin.filename);
|
||||
rootctr.AppendElement(pluginNode);
|
||||
gPluginsDS.Assert(pluginNode,
|
||||
rdf.GetResource(PREFIX_NS_EM + "name"),
|
||||
rdf.GetLiteral(pluginName),
|
||||
gRDF.GetResource(PREFIX_NS_EM + "name"),
|
||||
gRDF.GetLiteral(pluginName),
|
||||
true);
|
||||
gPluginsDS.Assert(pluginNode,
|
||||
rdf.GetResource(PREFIX_NS_EM + "addonID"),
|
||||
rdf.GetLiteral(plugin.filename),
|
||||
gRDF.GetResource(PREFIX_NS_EM + "addonID"),
|
||||
gRDF.GetLiteral(plugin.filename),
|
||||
true);
|
||||
gPluginsDS.Assert(pluginNode,
|
||||
rdf.GetResource(PREFIX_NS_EM + "description"),
|
||||
rdf.GetLiteral(pluginDesc),
|
||||
gRDF.GetResource(PREFIX_NS_EM + "description"),
|
||||
gRDF.GetLiteral(pluginDesc),
|
||||
true);
|
||||
if (plugin.homepageURL)
|
||||
gPluginsDS.Assert(pluginNode,
|
||||
rdf.GetResource(PREFIX_NS_EM + "homepageURL"),
|
||||
rdf.GetLiteral(plugin.homepageURL),
|
||||
gRDF.GetResource(PREFIX_NS_EM + "homepageURL"),
|
||||
gRDF.GetLiteral(plugin.homepageURL),
|
||||
true);
|
||||
gPluginsDS.Assert(pluginNode,
|
||||
rdf.GetResource(PREFIX_NS_EM + "isDisabled"),
|
||||
rdf.GetLiteral(plugin.disabled ? "true" : "false"),
|
||||
gRDF.GetResource(PREFIX_NS_EM + "isDisabled"),
|
||||
gRDF.GetLiteral(plugin.disabled ? "true" : "false"),
|
||||
true);
|
||||
gPluginsDS.Assert(pluginNode,
|
||||
rdf.GetResource(PREFIX_NS_EM + "blocklisted"),
|
||||
rdf.GetLiteral(plugin.blocklisted ? "true" : "false"),
|
||||
gRDF.GetResource(PREFIX_NS_EM + "blocklisted"),
|
||||
gRDF.GetLiteral(plugin.blocklisted ? "true" : "false"),
|
||||
true);
|
||||
gPluginsDS.Assert(pluginNode,
|
||||
rdf.GetResource(PREFIX_NS_EM + "compatible"),
|
||||
rdf.GetLiteral("true"),
|
||||
gRDF.GetResource(PREFIX_NS_EM + "compatible"),
|
||||
gRDF.GetLiteral("true"),
|
||||
true);
|
||||
gPluginsDS.Assert(pluginNode,
|
||||
rdf.GetResource(PREFIX_NS_EM + "plugin"),
|
||||
rdf.GetLiteral("true"),
|
||||
gRDF.GetResource(PREFIX_NS_EM + "plugin"),
|
||||
gRDF.GetLiteral("true"),
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
@ -639,12 +933,10 @@ function togglePluginDisabled(aName, aDesc)
|
|||
plugin.disabled = !plugin.disabled;
|
||||
for (var i = 0; i < plugin.plugins.length; ++i)
|
||||
plugin.plugins[i].disabled = plugin.disabled;
|
||||
var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"]
|
||||
.getService(Components.interfaces.nsIRDFService);
|
||||
gPluginsDS.Change(rdf.GetResource(PREFIX_ITEM_URI + plugin.filename),
|
||||
rdf.GetResource(PREFIX_NS_EM + "isDisabled"),
|
||||
rdf.GetLiteral(plugin.disabled ? "false" : "true"),
|
||||
rdf.GetLiteral(plugin.disabled ? "true" : "false"));
|
||||
gPluginsDS.Change(gRDF.GetResource(PREFIX_ITEM_URI + plugin.filename),
|
||||
gRDF.GetResource(PREFIX_NS_EM + "isDisabled"),
|
||||
gRDF.GetLiteral(plugin.disabled ? "false" : "true"),
|
||||
gRDF.GetLiteral(plugin.disabled ? "true" : "false"));
|
||||
gExtensionsViewController.onCommandUpdate();
|
||||
gExtensionsView.selectedItem.focus();
|
||||
}
|
||||
|
@ -681,16 +973,27 @@ function Startup()
|
|||
gCheckUpdateSecurity = gPref.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY);
|
||||
} catch(e) { }
|
||||
|
||||
try {
|
||||
gShowGetAddonsPane = gPref.getBoolPref(PREF_GETADDONS_SHOWPANE);
|
||||
} catch(e) { }
|
||||
|
||||
// Sort on startup and anytime an add-on is installed or upgraded.
|
||||
gExtensionManager.sortTypeByProperty(nsIUpdateItem.TYPE_ADDON, "name", true);
|
||||
// Extension Command Updating is handled by a command controller.
|
||||
gExtensionsView.controllers.appendController(gExtensionsViewController);
|
||||
gExtensionsView.addEventListener("select", onAddonSelect, false);
|
||||
|
||||
gRDF = Components.classes["@mozilla.org/rdf/rdf-service;1"]
|
||||
.getService(Components.interfaces.nsIRDFService);
|
||||
|
||||
initPluginsDS();
|
||||
gExtensionsView.database.AddDataSource(gPluginsDS);
|
||||
if (gShowGetAddonsPane)
|
||||
initSearchDS();
|
||||
gExtensionsView.database.AddDataSource(gExtensionManager.datasource);
|
||||
gExtensionsView.setAttribute("ref", RDFURI_ITEM_ROOT);
|
||||
|
||||
document.getElementById("search-view").hidden = !gShowGetAddonsPane;
|
||||
updateOptionalViews();
|
||||
|
||||
var viewGroup = document.getElementById("viewGroup");
|
||||
|
@ -744,7 +1047,6 @@ function Startup()
|
|||
try {
|
||||
var params = window.arguments[0].QueryInterface(Components.interfaces.nsIDialogParamBlock);
|
||||
var manager = window.arguments[1].QueryInterface(Components.interfaces.nsIObserver);
|
||||
showView("installs");
|
||||
gDownloadManager.addDownloads(params, manager);
|
||||
}
|
||||
catch (e) {
|
||||
|
@ -768,6 +1070,7 @@ function Startup()
|
|||
}
|
||||
}
|
||||
else if (viewGroup.hasAttribute("last-selected") &&
|
||||
document.getElementById(viewGroup.getAttribute("last-selected") + "-view") &&
|
||||
!document.getElementById(viewGroup.getAttribute("last-selected") + "-view").hidden)
|
||||
showView(viewGroup.getAttribute("last-selected"));
|
||||
else
|
||||
|
@ -784,6 +1087,10 @@ function Startup()
|
|||
|
||||
function Shutdown()
|
||||
{
|
||||
if (gAddonRepository && gAddonRepository.isSearching)
|
||||
gAddonRepository.cancelSearch();
|
||||
|
||||
gRDF = null;
|
||||
gPref = null;
|
||||
gExtensionsView.removeEventListener("select", onAddonSelect, false);
|
||||
gExtensionsView.database.RemoveDataSource(gExtensionManager.datasource);
|
||||
|
@ -830,7 +1137,6 @@ XPInstallDownloadManager.prototype = {
|
|||
{
|
||||
switch (aTopic) {
|
||||
case "xpinstall-download-started":
|
||||
showView("installs");
|
||||
var params = aSubject.QueryInterface(Components.interfaces.nsISupportsArray);
|
||||
var paramBlock = params.GetElementAt(0).QueryInterface(Components.interfaces.nsISupportsInterfacePointer);
|
||||
paramBlock = paramBlock.data.QueryInterface(Components.interfaces.nsIDialogParamBlock);
|
||||
|
@ -845,6 +1151,7 @@ XPInstallDownloadManager.prototype = {
|
|||
{
|
||||
var numXPInstallItems = aParams.GetInt(1);
|
||||
var items = [];
|
||||
var switchPane = false;
|
||||
for (var i = 0; i < numXPInstallItems;) {
|
||||
var displayName = aParams.GetString(i++);
|
||||
var url = aParams.GetString(i++);
|
||||
|
@ -865,11 +1172,22 @@ XPInstallDownloadManager.prototype = {
|
|||
|
||||
// Advance the enumerator
|
||||
var certName = aParams.GetString(i++);
|
||||
|
||||
// Check whether the install was triggered from the Get Add-ons pane.
|
||||
var pos = gPendingInstalls.indexOf(url);
|
||||
if (pos >= 0)
|
||||
gPendingInstalls.splice(pos, 1);
|
||||
else
|
||||
switchPane = true;
|
||||
}
|
||||
|
||||
gExtensionManager.addDownloads(items, items.length, aManager);
|
||||
updateOptionalViews();
|
||||
updateGlobalCommands();
|
||||
// Only switch to the installs pane if there was an not started by the
|
||||
// Get Add-ons pane
|
||||
if (switchPane)
|
||||
showView("installs");
|
||||
},
|
||||
|
||||
getElementForAddon: function(aAddon)
|
||||
|
@ -1169,11 +1487,7 @@ function onAddonSelect(aEvent)
|
|||
previewImageDeck.selectedIndex = 3;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
var uri = makeURI(gExtensionsView.selectedItem.getAttribute("availableUpdateInfo"));
|
||||
var scheme = uri.scheme;
|
||||
} catch (ex) {}
|
||||
if (uri && (scheme == "http" || scheme == "https"))
|
||||
if (isSafeURI(gExtensionsView.selectedItem.getAttribute("availableUpdateInfo")))
|
||||
UpdateInfoLoader.loadInfo(uri.spec);
|
||||
else
|
||||
previewImageDeck.selectedIndex = 4;
|
||||
|
@ -1552,6 +1866,11 @@ const gAddonsMsgObserver = {
|
|||
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(nsIIOService);
|
||||
ioService.offline = false;
|
||||
// If no results have been retrieved start pulling some
|
||||
if (!gRetrievedResults)
|
||||
retrieveRepositoryAddons(document.getElementById("searchbox").value);
|
||||
if (gView == "search")
|
||||
document.getElementById("searchbox").disabled = false;
|
||||
break;
|
||||
case "addons-message-dismiss":
|
||||
break;
|
||||
|
@ -1861,6 +2180,38 @@ function confirmOperation(aName, aTitle, aQueryMsg, aAcceptBtn, aCancelBtn,
|
|||
return params.result == "accept";
|
||||
}
|
||||
|
||||
function installCallback(item, status) {
|
||||
var resultNode = gRDF.GetResource(item.id);
|
||||
|
||||
// Strip out old status
|
||||
gSearchDS.Unassert(resultNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "action"),
|
||||
gRDF.GetLiteral("installing"),
|
||||
true);
|
||||
|
||||
if (status == -210) {
|
||||
// User cancelled
|
||||
var pos = gPendingInstalls.indexOf(item.getAttribute("xpiURL"));
|
||||
if (pos >= 0)
|
||||
gPendingInstalls.splice(pos, 1);
|
||||
return;
|
||||
}
|
||||
if (status < 0) {
|
||||
// Some other failure
|
||||
gSearchDS.Assert(resultNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "action"),
|
||||
gRDF.GetLiteral("failed"),
|
||||
true);
|
||||
}
|
||||
else {
|
||||
// Success
|
||||
gSearchDS.Assert(resultNode,
|
||||
gRDF.GetResource(PREFIX_NS_EM + "action"),
|
||||
gRDF.GetLiteral("installed"),
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
var gExtensionsViewController = {
|
||||
supportsCommand: function (aCommand)
|
||||
{
|
||||
|
@ -1881,6 +2232,8 @@ var gExtensionsViewController = {
|
|||
return false;
|
||||
}
|
||||
switch (aCommand) {
|
||||
case "cmd_installSearchResult":
|
||||
return true;
|
||||
case "cmd_useTheme":
|
||||
return selectedItem.type == nsIUpdateItem.TYPE_THEME &&
|
||||
!selectedItem.isDisabled &&
|
||||
|
@ -1969,6 +2322,41 @@ var gExtensionsViewController = {
|
|||
},
|
||||
|
||||
commands: {
|
||||
cmd_installSearchResult: function (aSelectedItem)
|
||||
{
|
||||
if (!isXPInstallEnabled())
|
||||
return;
|
||||
|
||||
if (aSelectedItem.hasAttribute("eula")) {
|
||||
var eula = {
|
||||
name: aSelectedItem.getAttribute("name"),
|
||||
text: aSelectedItem.getAttribute("eula"),
|
||||
accepted: false
|
||||
};
|
||||
window.openDialog("chrome://mozapps/content/extensions/eula.xul", "_blank",
|
||||
"chrome,dialog,modal,centerscreen,resizable=no", eula);
|
||||
if (!eula.accepted)
|
||||
return;
|
||||
}
|
||||
|
||||
var details = {
|
||||
URL: aSelectedItem.getAttribute("xpiURL"),
|
||||
Hash: aSelectedItem.getAttribute("xpiHash"),
|
||||
IconURL: aSelectedItem.getAttribute("iconURL"),
|
||||
toString: function () { return this.URL; }
|
||||
};
|
||||
var params = [];
|
||||
params[aSelectedItem.getAttribute("name")] = details;
|
||||
|
||||
gSearchDS.Assert(gRDF.GetResource(aSelectedItem.id),
|
||||
gRDF.GetResource(PREFIX_NS_EM + "action"),
|
||||
gRDF.GetLiteral("installing"),
|
||||
true);
|
||||
// Remember that we don't want to change panes for this install
|
||||
gPendingInstalls.push(details.URL);
|
||||
InstallTrigger.install(params, function(url, status) { installCallback(aSelectedItem, status); });
|
||||
},
|
||||
|
||||
cmd_close: function (aSelectedItem)
|
||||
{
|
||||
closeWindow(true);
|
||||
|
@ -2035,11 +2423,7 @@ var gExtensionsViewController = {
|
|||
if (!aSelectedItem) return;
|
||||
var homepageURL = aSelectedItem.getAttribute("homepageURL");
|
||||
// only allow http(s) homepages
|
||||
try {
|
||||
var uri = makeURI(homepageURL);
|
||||
var scheme = uri.scheme;
|
||||
} catch (ex) {}
|
||||
if (uri && (scheme == "http" || scheme == "https"))
|
||||
if (isSafeURI(homepageURL))
|
||||
openURL(uri.spec);
|
||||
},
|
||||
|
||||
|
|
|
@ -385,6 +385,250 @@
|
|||
</handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
<binding id="searchresult" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
|
||||
<resources>
|
||||
<stylesheet src="chrome://mozapps/skin/extensions/extensions.css"/>
|
||||
</resources>
|
||||
|
||||
<content>
|
||||
<xul:hbox flex="1">
|
||||
<xul:vbox class="addon-icon" xbl:inherits="iconURL"/>
|
||||
<xul:vbox flex="1" class="addonTextBox">
|
||||
<xul:hbox align="center">
|
||||
<xul:hbox anonid="addonNameVersion" class="addon-name-version" xbl:inherits="name, version"/>
|
||||
<xul:spacer flex="1"/>
|
||||
<xul:image class="addonRating" xbl:inherits="rating"/>
|
||||
</xul:hbox>
|
||||
<xul:hbox anonid="addonDescription" class="addon-description" xbl:inherits="description, opType"/>
|
||||
</xul:vbox>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
|
||||
<implementation extends="nsIAccessibleProvider">
|
||||
<constructor>
|
||||
if (!this.hasAttribute("thumbnailURL"))
|
||||
return this._hideImage();
|
||||
|
||||
if (this.hasAttribute("thumbwidth"))
|
||||
return this._displayImage();
|
||||
|
||||
var image = new Image();
|
||||
var id = this.id;
|
||||
image.onload = function() {
|
||||
document.getElementById(id)._imageLoaded(image);
|
||||
};
|
||||
image.onerror = function() {
|
||||
document.getElementById(id)._hideImage();
|
||||
};
|
||||
image.src = this.getAttribute("thumbnailURL");
|
||||
</constructor>
|
||||
|
||||
<field name="_maxSize">125</field>
|
||||
|
||||
<method name="_displayImage">
|
||||
<body>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="_hideImage">
|
||||
<body>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="_imageLoaded">
|
||||
<parameter name="image"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
if ((this._maxSize >= image.width) &&
|
||||
(this._maxSize >= image.height)) {
|
||||
var width = image.width;
|
||||
var height = image.height;
|
||||
}
|
||||
else if (image.width > image.height) {
|
||||
width = this._maxSize;
|
||||
height = (this._maxSize / image.width) * image.height;
|
||||
}
|
||||
else {
|
||||
height = this._maxSize;
|
||||
width = (this._maxSize / image.height) * image.width;
|
||||
}
|
||||
|
||||
this.setAttribute("thumbwidth", width);
|
||||
this.setAttribute("thumbheight", height);
|
||||
this._displayImage();
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
</implementation>
|
||||
</binding>
|
||||
|
||||
<binding id="searchresult-selected" extends="chrome://mozapps/content/extensions/extensions.xml#searchresult">
|
||||
<content>
|
||||
<xul:hbox flex="1">
|
||||
<xul:vbox class="addon-icon" xbl:inherits="iconURL"/>
|
||||
<xul:vbox flex="1" class="addonTextBox">
|
||||
<xul:hbox align="center">
|
||||
<xul:hbox anonid="addonNameVersion" class="addon-name-version" xbl:inherits="name, version"/>
|
||||
<xul:spacer flex="1"/>
|
||||
<xul:image class="addonRating" xbl:inherits="rating"/>
|
||||
</xul:hbox>
|
||||
<xul:hbox flex="1" align="stretch" class="addon-search-details">
|
||||
<xul:vbox pack="start">
|
||||
<xul:deck class="addonThumbnailContainer" selectedIndex="0">
|
||||
<xul:vbox flex="1" align="center" pack="center">
|
||||
<xul:image class="addonThrobber"/>
|
||||
</xul:vbox>
|
||||
<xul:vbox flex="1" align="center" pack="center">
|
||||
<xul:image class="addonThumbnail"/>
|
||||
</xul:vbox>
|
||||
<xul:vbox flex="1" align="center" pack="center">
|
||||
<xul:label class="addonMissingThumbnail" value="&missingThumbnail.label;"/>
|
||||
</xul:vbox>
|
||||
</xul:deck>
|
||||
</xul:vbox>
|
||||
<xul:vbox flex="1">
|
||||
<xul:label anonid="addonDescriptionWrap" class="descriptionWrap"
|
||||
xbl:inherits="xbl:text=description"/>
|
||||
<xul:label class="addonLearnMore text-link" xbl:inherits="homepageURL"
|
||||
value="&searchResultHomepage.value;"
|
||||
onclick="openURL(this.getAttribute('homepageURL'));"/>
|
||||
<xul:spacer flex="1"/>
|
||||
<xul:hbox anonid="selectedButtons" class="selectedButtons">
|
||||
<xul:hbox align="center" class="addonType addonTypeExtension">
|
||||
<xul:image/>
|
||||
<xul:label value="&addonTypeExtension.label;"/>
|
||||
</xul:hbox>
|
||||
<xul:hbox align="center" class="addonType addonTypeTheme">
|
||||
<xul:image/>
|
||||
<xul:label value="&addonTypeTheme.label;"/>
|
||||
</xul:hbox>
|
||||
<xul:spacer flex="1"/>
|
||||
<xul:hbox align="center" class="searchResultInstalling">
|
||||
<xul:image class="addonThrobber"/>
|
||||
<xul:label value="&searchResultInstalling.label;"/>
|
||||
</xul:hbox>
|
||||
<xul:hbox align="center" class="searchResultFailed">
|
||||
<xul:label value="&searchResultFailed.label;"/>
|
||||
</xul:hbox>
|
||||
<xul:hbox align="center" class="searchResultInstalled">
|
||||
<xul:label value="&searchResultInstalled.label;"/>
|
||||
</xul:hbox>
|
||||
<xul:button class="addonInstallButton"
|
||||
label="&cmd.installSearchResult.label;"
|
||||
accesskey="&cmd.installSearchResult.accesskey;"
|
||||
tooltiptext="&cmd.installSearchResult.tooltip;"
|
||||
command="cmd_installSearchResult"/>
|
||||
</xul:hbox>
|
||||
</xul:vbox>
|
||||
</xul:hbox>
|
||||
</xul:vbox>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
|
||||
<implementation implements="nsIAccessibleProvider">
|
||||
<field name="_thumbnailContainer">
|
||||
document.getAnonymousElementByAttribute(this, "class", "addonThumbnailContainer");
|
||||
</field>
|
||||
<field name="_thumbnail">
|
||||
document.getAnonymousElementByAttribute(this, "class", "addonThumbnail");
|
||||
</field>
|
||||
|
||||
<method name="_displayImage">
|
||||
<body>
|
||||
this._thumbnail.style.width = this.getAttribute("thumbwidth") + "px";
|
||||
this._thumbnail.style.height = this.getAttribute("thumbheight") + "px";
|
||||
this._thumbnail.src = this.getAttribute("thumbnailURL");
|
||||
this._thumbnailContainer.selectedIndex = 1;
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="_hideImage">
|
||||
<body>
|
||||
this._thumbnailContainer.selectedIndex = 2;
|
||||
</body>
|
||||
</method>
|
||||
</implementation>
|
||||
</binding>
|
||||
|
||||
<binding id="status-search-failure">
|
||||
<content align="center">
|
||||
<xul:hbox align="center" pack="center">
|
||||
<xul:image class="addonFailure"/>
|
||||
<xul:label value="&searchFailed.label;"/>
|
||||
</xul:hbox>
|
||||
<xul:button command="cmd_resetSearch" label="&cancelSearch.button;"/>
|
||||
</content>
|
||||
</binding>
|
||||
|
||||
<binding id="status-recommended-failure">
|
||||
<content>
|
||||
<xul:hbox align="center" pack="center">
|
||||
<xul:image class="addonFailure"/>
|
||||
<xul:label value="&searchFailed.label;"/>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
</binding>
|
||||
|
||||
<binding id="status-header-recommended">
|
||||
<content>
|
||||
<xul:label value="&recommendedHeader.label;"/>
|
||||
</content>
|
||||
</binding>
|
||||
|
||||
<binding id="status-footer-recommended">
|
||||
<content align="end">
|
||||
<xul:label class="text-link" xbl:inherits="searchURL=link" value="&recommendedResults.label;"
|
||||
onclick="openURL(this.getAttribute('homepageURL'));"/>
|
||||
</content>
|
||||
</binding>
|
||||
|
||||
<binding id="status-footer-search">
|
||||
<content align="stretch">
|
||||
<xul:hbox align="center">
|
||||
<xul:label class="text-link" xbl:inherits="searchURL=link" anonid="searchLink"
|
||||
onclick="openURL(this.getAttribute('searchURL'));"/>
|
||||
<xul:spacer flex="1"/>
|
||||
<xul:button command="cmd_resetSearch" label="&resetSearch.label;"/>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
|
||||
<implementation>
|
||||
<constructor>
|
||||
var strings = [this.getAttribute("count")];
|
||||
var text = document.getElementById("extensionsStrings")
|
||||
.getFormattedString("searchResults", strings);
|
||||
var label = document.getAnonymousElementByAttribute(this, "anonid", "searchLink");
|
||||
label.value = text;
|
||||
</constructor>
|
||||
</implementation>
|
||||
</binding>
|
||||
|
||||
<binding id="status-footer-search-empty">
|
||||
<content align="center">
|
||||
<xul:label value="&searchEmpty.label;"/>
|
||||
<xul:button command="cmd_resetSearch" label="&searchEmpty.button;"/>
|
||||
</content>
|
||||
</binding>
|
||||
|
||||
<binding id="status-retrieve-search">
|
||||
<content align="center">
|
||||
<xul:hbox align="center" pack="center">
|
||||
<xul:image class="addonThrobber"/>
|
||||
<xul:label value="&searchThrobber.label;"/>
|
||||
</xul:hbox>
|
||||
<xul:button command="cmd_resetSearch" label="&cancelSearch.button;"/>
|
||||
</content>
|
||||
</binding>
|
||||
|
||||
<binding id="status-retrieve-recommended">
|
||||
<content>
|
||||
<xul:hbox align="center" pack="center">
|
||||
<xul:image class="addonThrobber"/>
|
||||
<xul:label value="&recommendedThrobber.label;"/>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
</binding>
|
||||
|
||||
<binding id="addon-icon">
|
||||
<content>
|
||||
|
@ -599,6 +843,104 @@
|
|||
</content>
|
||||
</binding>
|
||||
|
||||
<binding id="search-textbox" extends="xul:box">
|
||||
<resources>
|
||||
<stylesheet src="chrome://global/skin/textbox.css"/>
|
||||
</resources>
|
||||
|
||||
<content align="center">
|
||||
<xul:image class="searchbox-image" xbl:inherits="src=image"/>
|
||||
<xul:textbox class="plain"
|
||||
xbl:inherits="emptyText,onfocus,onblur,spellcheck,value,maxlength,disabled,size,readonly,tabindex,accesskey"/>
|
||||
<xul:button class="searchbox-search" xbl:inherits="disabled" oncommand="this.parentNode.startSearch()"/>
|
||||
<xul:button class="searchbox-cancel" xbl:inherits="disabled" hidden="true" oncommand="this.parentNode.clearSearch()"/>
|
||||
</content>
|
||||
|
||||
<implementation>
|
||||
<field name="textbox">
|
||||
document.getAnonymousNodes(this)[1];
|
||||
</field>
|
||||
|
||||
<field name="_searchButton">
|
||||
document.getAnonymousElementByAttribute(this, "class", "searchbox-search");
|
||||
</field>
|
||||
|
||||
<field name="_cancelButton">
|
||||
document.getAnonymousElementByAttribute(this, "class", "searchbox-cancel");
|
||||
</field>
|
||||
|
||||
<property name="value" onget="return this.textbox.value"
|
||||
onset="this.textbox.value = val"/>
|
||||
|
||||
<property name="disabled" onget="return this.textbox.disabled">
|
||||
<setter>
|
||||
if (val)
|
||||
this.setAttribute("disabled", "true");
|
||||
else
|
||||
this.removeAttribute("disabled");
|
||||
</setter>
|
||||
</property>
|
||||
|
||||
<constructor>
|
||||
if (this.value) {
|
||||
this._cancelButton.hidden = false;
|
||||
this._searchButton.hidden = true;
|
||||
}
|
||||
</constructor>
|
||||
|
||||
<method name="startSearch">
|
||||
<body>
|
||||
if (this.value) {
|
||||
this._cancelButton.hidden = false;
|
||||
this._searchButton.hidden = true;
|
||||
}
|
||||
this.setAttribute("value", this.value);
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="clearSearch">
|
||||
<body>
|
||||
this.value = "";
|
||||
this.setAttribute("value", "");
|
||||
this._cancelButton.hidden = true;
|
||||
this._searchButton.hidden = false;
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="_dispatchCommandEvent">
|
||||
<parameter name="aEvent"/>
|
||||
<body>
|
||||
var event = document.createEvent("commandevent");
|
||||
event.initCommandEvent("command", true, true, window, null,
|
||||
false, false, false, false, aEvent);
|
||||
this.dispatchEvent(event);
|
||||
</body>
|
||||
</method>
|
||||
</implementation>
|
||||
|
||||
<handlers>
|
||||
<handler event="keypress" keycode="VK_ENTER">
|
||||
if (event.originalTarget == this.textbox.inputField) {
|
||||
this.startSearch();
|
||||
this._dispatchCommandEvent(event);
|
||||
}
|
||||
</handler>
|
||||
|
||||
<handler event="keypress" keycode="VK_RETURN">
|
||||
if (event.originalTarget == this.textbox.inputField) {
|
||||
this.startSearch();
|
||||
this._dispatchCommandEvent(event);
|
||||
}
|
||||
</handler>
|
||||
|
||||
<handler event="input">
|
||||
this._cancelButton.hidden = true;
|
||||
this._searchButton.hidden = false;
|
||||
</handler>
|
||||
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
<!-- based on preferences.xml paneButton -->
|
||||
<binding id="viewbutton" extends="chrome://global/content/bindings/radio.xml#radio">
|
||||
<resources>
|
||||
|
|
|
@ -104,6 +104,7 @@
|
|||
<command id="cmd_enable"/>
|
||||
<command id="cmd_disable"/>
|
||||
<command id="cmd_useTheme"/>
|
||||
<command id="cmd_installSearchResult"/>
|
||||
</commandset>
|
||||
|
||||
<commandset id="globalCommands">
|
||||
|
@ -114,6 +115,7 @@
|
|||
<command id="cmd_close" oncommand="closeEM();"/>
|
||||
<command id="cmd_showUpdateInfo" oncommand="showUpdateInfo();"/>
|
||||
<command id="cmd_hideUpdateInfo" oncommand="hideUpdateInfo();"/>
|
||||
<command id="cmd_resetSearch" oncommand="resetSearch();"/>
|
||||
</commandset>
|
||||
|
||||
<vbox id="addonContextMenuPalette" hidden="true">
|
||||
|
@ -156,6 +158,7 @@
|
|||
<stack id="topStackBar">
|
||||
<radiogroup id="viewGroup" xhtml:role="listbox" persist="last-selected"
|
||||
class="viewSelector chromeclass-toolbar" orient="horizontal">
|
||||
<radio id="search-view" label="&search.label;" oncommand="showView('search');" persist="last-selected"/>
|
||||
<radio id="extensions-view" label="&extensions.label;" oncommand="showView('extensions');" persist="last-selected"/>
|
||||
<radio id="themes-view" label="&themes.label;" oncommand="showView('themes');" persist="last-selected"/>
|
||||
<radio id="locales-view" label="&locales.label;" oncommand="showView('locales');" persist="last-selected"/>
|
||||
|
@ -174,46 +177,57 @@
|
|||
</vbox>
|
||||
</stack>
|
||||
<notificationbox id="addonsMsg" flex="1">
|
||||
<hbox id="extensionsBox" flex="1">
|
||||
<richlistbox id="extensionsView" flex="1"
|
||||
datasources="rdf:null" context="addonContextMenu"
|
||||
ondragenter="nsDragAndDrop.dragEnter(event, gExtensionsDNDObserver);"
|
||||
ondragover="nsDragAndDrop.dragOver(event, gExtensionsDNDObserver);"
|
||||
ondragdrop="nsDragAndDrop.drop(event, gExtensionsDNDObserver);"
|
||||
ondblclick="onViewDoubleClick(event);"/>
|
||||
|
||||
<splitter id="themeSplitter" hidden="true" collapse="after" persist="state"/>
|
||||
|
||||
<vbox id="themePreviewArea" hidden="true" width="220" persist="width">
|
||||
<deck id="previewImageDeck" flex="1">
|
||||
<vbox id="noThemeSelected" pack="center" align="center">
|
||||
<label class="previewText">&previewNoThemeSelected.label;</label>
|
||||
</vbox>
|
||||
<vbox id="noPreviewImage" pack="center" align="center">
|
||||
<label class="previewText">&previewNoPreviewImage.label;</label>
|
||||
</vbox>
|
||||
<vbox id="previewImageContainer" align="center" pack="center">
|
||||
<description>
|
||||
<image id="previewImage"/>
|
||||
</description>
|
||||
</vbox>
|
||||
<vbox id="infoNoAddonSelected" align="center" pack="center">
|
||||
<label class="previewText">&infoNoAddonSelected.label;</label>
|
||||
</vbox>
|
||||
<vbox id="infoNoUpdateInfo" align="center" pack="center">
|
||||
<label class="previewText">&infoNoUpdateInfo.label;</label>
|
||||
</vbox>
|
||||
<vbox id="infoLoadingInfo" align="center" pack="center">
|
||||
<image class="addonThrobber"/>
|
||||
</vbox>
|
||||
<vbox id="infoUpdateInfoError" align="center" pack="center">
|
||||
<label class="previewText">&infoUpdateInfoError.label;</label>
|
||||
</vbox>
|
||||
<vbox id="infoDisplay">
|
||||
</vbox>
|
||||
</deck>
|
||||
</vbox>
|
||||
</hbox>
|
||||
<vbox id="extensionsBox" flex="1">
|
||||
<hbox id="searchPanel" align="center">
|
||||
<textbox id="searchbox" emptyText="&searchAddons.label;"
|
||||
oncommand="retrieveRepositoryAddons(this.value);"
|
||||
persist="value"/>
|
||||
<spacer flex="1"/>
|
||||
<label id="browseAddons" class="text-link" value="&browseAddons.label;"
|
||||
onclick="openURL(this.getAttribute('homepageURL'));"/>
|
||||
</hbox>
|
||||
|
||||
<hbox flex="1">
|
||||
<richlistbox id="extensionsView" flex="1"
|
||||
datasources="rdf:null" context="addonContextMenu"
|
||||
ondragenter="nsDragAndDrop.dragEnter(event, gExtensionsDNDObserver);"
|
||||
ondragover="nsDragAndDrop.dragOver(event, gExtensionsDNDObserver);"
|
||||
ondragdrop="nsDragAndDrop.drop(event, gExtensionsDNDObserver);"
|
||||
ondblclick="onViewDoubleClick(event);"/>
|
||||
|
||||
<splitter id="themeSplitter" hidden="true" collapse="after" persist="state"/>
|
||||
|
||||
<vbox id="themePreviewArea" hidden="true" width="220" persist="width">
|
||||
<deck id="previewImageDeck" flex="1">
|
||||
<vbox id="noThemeSelected" pack="center" align="center">
|
||||
<label class="previewText">&previewNoThemeSelected.label;</label>
|
||||
</vbox>
|
||||
<vbox id="noPreviewImage" pack="center" align="center">
|
||||
<label class="previewText">&previewNoPreviewImage.label;</label>
|
||||
</vbox>
|
||||
<vbox id="previewImageContainer" align="center" pack="center">
|
||||
<description>
|
||||
<image id="previewImage"/>
|
||||
</description>
|
||||
</vbox>
|
||||
<vbox id="infoNoAddonSelected" align="center" pack="center">
|
||||
<label class="previewText">&infoNoAddonSelected.label;</label>
|
||||
</vbox>
|
||||
<vbox id="infoNoUpdateInfo" align="center" pack="center">
|
||||
<label class="previewText">&infoNoUpdateInfo.label;</label>
|
||||
</vbox>
|
||||
<vbox id="infoLoadingInfo" align="center" pack="center">
|
||||
<image class="addonThrobber"/>
|
||||
</vbox>
|
||||
<vbox id="infoUpdateInfoError" align="center" pack="center">
|
||||
<label class="previewText">&infoUpdateInfoError.label;</label>
|
||||
</vbox>
|
||||
<vbox id="infoDisplay">
|
||||
</vbox>
|
||||
</deck>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</notificationbox>
|
||||
<vbox>
|
||||
<hbox id="commandBarBottom" align="center">
|
||||
|
|
|
@ -11,4 +11,5 @@ toolkit.jar:
|
|||
* 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/eula.xul (content/eula.xul)
|
||||
* content/mozapps/extensions/eula.js (content/eula.js)
|
||||
|
|
|
@ -44,7 +44,11 @@ include $(DEPTH)/config/autoconf.mk
|
|||
MODULE = extensions
|
||||
XPIDL_MODULE = extensions
|
||||
|
||||
XPIDLSRCS = nsIExtensionManager.idl nsIBlocklistService.idl
|
||||
XPIDLSRCS = \
|
||||
nsIExtensionManager.idl \
|
||||
nsIBlocklistService.idl \
|
||||
nsIAddonRepository.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** 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 Manager.
|
||||
*
|
||||
* The Initial Developer of the Original Code is mozilla.org
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Townsend <dtownsend@oxymoronical.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 ***** */
|
||||
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(a549a714-2ada-4bb9-8a47-be26e73d49a5)]
|
||||
interface nsIAddonSearchResult : nsISupports
|
||||
{
|
||||
/**
|
||||
* The ID of the add-on
|
||||
*/
|
||||
readonly attribute AString id;
|
||||
|
||||
/**
|
||||
* The name of the add-on
|
||||
*/
|
||||
readonly attribute AString name;
|
||||
|
||||
/**
|
||||
* The version of the add-on
|
||||
*/
|
||||
readonly attribute AString version;
|
||||
|
||||
/**
|
||||
* A short summary of the add-on
|
||||
*/
|
||||
readonly attribute AString summary;
|
||||
|
||||
/**
|
||||
* The full description of the add-on
|
||||
*/
|
||||
readonly attribute AString description;
|
||||
|
||||
/**
|
||||
* The rating of the add-on, 0-10 or -1 if unrated.
|
||||
*/
|
||||
readonly attribute long rating;
|
||||
|
||||
/**
|
||||
* The url of the add-ons icon or empty if there is no icon.
|
||||
*/
|
||||
readonly attribute AString iconURL;
|
||||
|
||||
/**
|
||||
* The url of a thumbnail for the add-on
|
||||
*/
|
||||
readonly attribute AString thumbnailURL;
|
||||
|
||||
/**
|
||||
* The homepage for the add-on
|
||||
*/
|
||||
readonly attribute AString homepageURL;
|
||||
|
||||
/**
|
||||
* A EULA that must be accepted before install.
|
||||
*/
|
||||
readonly attribute AString eula;
|
||||
|
||||
/**
|
||||
* The add-on type (see nsIUpdateItem).
|
||||
*/
|
||||
readonly attribute unsigned long type;
|
||||
|
||||
/**
|
||||
* The url of the xpi for this add-on
|
||||
*/
|
||||
readonly attribute AString xpiURL;
|
||||
|
||||
/**
|
||||
* The hash for the xpi.
|
||||
*/
|
||||
readonly attribute AString xpiHash;
|
||||
};
|
||||
|
||||
[scriptable, uuid(a6f70917-dd30-4eb6-8b3d-453204f96f33)]
|
||||
interface nsIAddonSearchResultsCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
* Called when a search has suceeded.
|
||||
*
|
||||
* @param aAddons an array of the add-on results. In the case of
|
||||
* searching for specific terms the ordering of results
|
||||
* may be determined by the search provider.
|
||||
* @param aAddonCount The length of aAddons
|
||||
* @param aTotalResults The total results actually available in the
|
||||
* repository
|
||||
*/
|
||||
void searchSucceeded([array, size_is(aAddonCount)] in nsIAddonSearchResult aAddons,
|
||||
in unsigned long aAddonCount,
|
||||
in unsigned long aTotalResults);
|
||||
|
||||
/**
|
||||
* Called when an error occured when performing a search.
|
||||
*/
|
||||
void searchFailed();
|
||||
};
|
||||
|
||||
/**
|
||||
* The add-on repository is a source of add-ons that can be installed. It can
|
||||
* be searched in two ways. One returns a list of add-ons that come highly
|
||||
* recommended, this list should change frequently. The other way is to
|
||||
* search for specific search terms entered by the user. Searches are
|
||||
* asynchronous and results should be passed to the provided callback object
|
||||
* when complete. The results passed to the callback should only include add-ons
|
||||
* that are compatible with the current application and are not already
|
||||
* installed. Searches are always asynchronous and should be passed to the
|
||||
* callback object provided.
|
||||
*/
|
||||
[scriptable, uuid(c4d2ac29-6edc-43cd-8dc8-e4cf213aa1be)]
|
||||
interface nsIAddonRepository : nsISupports
|
||||
{
|
||||
/**
|
||||
* The homepage for visiting this repository. This may be null or an empty
|
||||
* string.
|
||||
*/
|
||||
readonly attribute AString homepageURL;
|
||||
|
||||
/**
|
||||
* Returns whether this instance is currently performing a search. New
|
||||
* searches will not be performed while this is the case.
|
||||
*/
|
||||
readonly attribute boolean isSearching;
|
||||
|
||||
/**
|
||||
* The url that can be visited to see recommended add-ons in this repository.
|
||||
*/
|
||||
AString getRecommendedURL();
|
||||
|
||||
/**
|
||||
* Retrieves the url that can be visited to see search results for the given
|
||||
* terms.
|
||||
*
|
||||
* @param aSearchTerms search terms used to search the repository
|
||||
*/
|
||||
AString getSearchURL(in AString aSearchTerms);
|
||||
|
||||
/**
|
||||
* Begins a search for recommended add-ons in this repository. Results will
|
||||
* be passed to the given callback.
|
||||
*
|
||||
* @param aMaxResults the maximum number of results to return
|
||||
* @param aCallback the callback to pass results to
|
||||
*/
|
||||
void retrieveRecommendedAddons(in unsigned long aMaxResults,
|
||||
in nsIAddonSearchResultsCallback aCallback);
|
||||
|
||||
/**
|
||||
* Begins a search for add-ons in this repository. Results will be passed to
|
||||
* the given callback.
|
||||
*
|
||||
* @param aSearchTerms the terms to search for
|
||||
* @param aMaxResults the maximum number of results to return
|
||||
* @param aCallback the callback to pass results to
|
||||
*/
|
||||
void searchAddons(in AString aSearchTerms, in unsigned long aMaxResults,
|
||||
in nsIAddonSearchResultsCallback aCallback);
|
||||
|
||||
/**
|
||||
* Cancels the search in progress. If there is no search in progress this
|
||||
* does nothing.
|
||||
*/
|
||||
void cancelSearch();
|
||||
};
|
|
@ -45,7 +45,11 @@ include $(DEPTH)/config/autoconf.mk
|
|||
MODULE = extensions
|
||||
|
||||
EXTRA_COMPONENTS = nsExtensionManager.js
|
||||
EXTRA_PP_COMPONENTS = nsBlocklistService.js
|
||||
EXTRA_PP_COMPONENTS = \
|
||||
nsBlocklistService.js \
|
||||
nsAddonRepository.js \
|
||||
$(NULL)
|
||||
|
||||
GARBAGE += nsExtensionManager.js
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -0,0 +1,367 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
# ***** 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 Manager.
|
||||
#
|
||||
# The Initial Developer of the Original Code is mozilla.org
|
||||
# Portions created by the Initial Developer are Copyright (C) 2008
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Dave Townsend <dtownsend@oxymoronical.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 *****
|
||||
*/
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const PREF_GETADDONS_BROWSEADDONS = "extensions.getAddons.browseAddons";
|
||||
const PREF_GETADDONS_BROWSERECOMMENDED = "extensions.getAddons.recommended.browseURL";
|
||||
const PREF_GETADDONS_GETRECOMMENDED = "extensions.getAddons.recommended.url";
|
||||
const PREF_GETADDONS_BROWSESEARCHRESULTS = "extensions.getAddons.search.browseURL";
|
||||
const PREF_GETADDONS_GETSEARCHRESULTS = "extensions.getAddons.search.url";
|
||||
|
||||
const XMLURI_PARSE_ERROR = "http://www.mozilla.org/newlayout/xml/parsererror.xml"
|
||||
|
||||
function AddonSearchResult() {
|
||||
}
|
||||
|
||||
AddonSearchResult.prototype = {
|
||||
id: null,
|
||||
name: null,
|
||||
version: null,
|
||||
summary: null,
|
||||
description: null,
|
||||
rating: null,
|
||||
iconURL: null,
|
||||
thumbnailURL: null,
|
||||
homepageURL: null,
|
||||
eula: null,
|
||||
type: null,
|
||||
xpiURL: null,
|
||||
xpiHash: null,
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAddonSearchResult])
|
||||
}
|
||||
|
||||
function AddonRepository() {
|
||||
}
|
||||
|
||||
AddonRepository.prototype = {
|
||||
// The current set of results
|
||||
_addons: [],
|
||||
|
||||
// Whether we are currently searching or not
|
||||
_searching: false,
|
||||
|
||||
// Is this a search for recommended add-ons
|
||||
_recommended: false,
|
||||
|
||||
// XHR associated with the current request
|
||||
_request: null,
|
||||
|
||||
// How many times in succession has a search yielded no new results. Stops
|
||||
// us trying to find more results indefinately
|
||||
_emptyCount: null,
|
||||
|
||||
// Callback object to notify on completion
|
||||
_callback: null,
|
||||
|
||||
// The uri to pull results from
|
||||
_retrieveURI: null,
|
||||
|
||||
// Maximum number of results to return
|
||||
_maxResults: null,
|
||||
|
||||
get homepageURL() {
|
||||
return Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
|
||||
.getService(Components.interfaces.nsIURLFormatter)
|
||||
.formatURLPref(PREF_GETADDONS_BROWSEADDONS);
|
||||
},
|
||||
|
||||
get isSearching() {
|
||||
return this._searching;
|
||||
},
|
||||
|
||||
getRecommendedURL: function() {
|
||||
var urlf = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
|
||||
.getService(Components.interfaces.nsIURLFormatter);
|
||||
|
||||
return urlf.formatURLPref(PREF_GETADDONS_BROWSERECOMMENDED);
|
||||
},
|
||||
|
||||
getSearchURL: function(aSearchTerms) {
|
||||
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch);
|
||||
var urlf = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
|
||||
.getService(Components.interfaces.nsIURLFormatter);
|
||||
|
||||
var url = prefs.getCharPref(PREF_GETADDONS_BROWSESEARCHRESULTS);
|
||||
url = url.replace(/%TERMS%/g, encodeURIComponent(aSearchTerms));
|
||||
return urlf.formatURL(url);
|
||||
},
|
||||
|
||||
cancelSearch: function() {
|
||||
this._searching = false;
|
||||
if (this._request) {
|
||||
this._request.abort();
|
||||
this._request = null;
|
||||
}
|
||||
},
|
||||
|
||||
retrieveRecommendedAddons: function(aMaxResults, aCallback) {
|
||||
if (this._searching)
|
||||
return;
|
||||
|
||||
this._searching = true;
|
||||
this._addons = [];
|
||||
this._callback = aCallback;
|
||||
this._recommended = true;
|
||||
this._emptyCount = 0;
|
||||
this._maxResults = aMaxResults;
|
||||
|
||||
var urlf = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
|
||||
.getService(Components.interfaces.nsIURLFormatter);
|
||||
|
||||
this._retrieveURI = urlf.formatURLPref(PREF_GETADDONS_GETRECOMMENDED);
|
||||
this._loadList();
|
||||
},
|
||||
|
||||
searchAddons: function(aSearchTerms, aMaxResults, aCallback) {
|
||||
if (this._searching)
|
||||
return;
|
||||
|
||||
this._searching = true;
|
||||
this._addons = [];
|
||||
this._callback = aCallback;
|
||||
this._recommended = false;
|
||||
this._emptyCount = 0;
|
||||
this._maxResults = aMaxResults;
|
||||
|
||||
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch);
|
||||
var urlf = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
|
||||
.getService(Components.interfaces.nsIURLFormatter);
|
||||
|
||||
this._retrieveURI = prefs.getCharPref(PREF_GETADDONS_GETSEARCHRESULTS);
|
||||
this._retrieveURI = this._retrieveURI.replace(/%TERMS%/g, encodeURIComponent(aSearchTerms));
|
||||
this._retrieveURI = urlf.formatURL(this._retrieveURI);
|
||||
this._loadList();
|
||||
},
|
||||
|
||||
// Posts results to the callback
|
||||
_reportSuccess: function(aCount) {
|
||||
this._searching = false;
|
||||
this._request = null;
|
||||
this._callback.searchSucceeded(this._addons, this._addons.length,
|
||||
this._recommended ? -1 : aCount);
|
||||
},
|
||||
|
||||
// Notifies the callback of a failure
|
||||
_reportFailure: function(aEvent) {
|
||||
this._searching = false;
|
||||
this._request = null;
|
||||
this._callback.searchFailed();
|
||||
},
|
||||
|
||||
// Parses an add-on entry from an <addon> element
|
||||
_parseAddon: function(element) {
|
||||
var em = Cc["@mozilla.org/extensions/manager;1"].
|
||||
getService(Ci.nsIExtensionManager);
|
||||
var app = Cc["@mozilla.org/xre/app-info;1"].
|
||||
getService(Ci.nsIXULAppInfo).
|
||||
QueryInterface(Ci.nsIXULRuntime);
|
||||
|
||||
var guid = element.getElementsByTagName("guid");
|
||||
if (guid.length != 1)
|
||||
return;
|
||||
|
||||
// Ignore add-ons already seen in the results
|
||||
for (var i = 0; i < this._addons.length; i++)
|
||||
if (this._addons[i].id == guid[0].textContent)
|
||||
return;
|
||||
|
||||
// Ignore installed add-ons
|
||||
if (em.getItemForID(guid[0].textContent) != null)
|
||||
return;
|
||||
|
||||
// Ignore sandboxed add-ons
|
||||
var status = element.getElementsByTagName("status");
|
||||
// The status element has a unique id for each status type. 4 is Public.
|
||||
if (status.length != 1 || status[0].getAttribute("id") != 4)
|
||||
return;
|
||||
|
||||
// Ignore add-ons not compatible with this OS
|
||||
var compatible = false;
|
||||
var os = element.getElementsByTagName("compatible_os");
|
||||
var i = 0;
|
||||
while (i < os.length && !compatible) {
|
||||
if (os[i].textContent == "ALL" || os[i].textContent == app.OS) {
|
||||
compatible = true;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (!compatible)
|
||||
return;
|
||||
|
||||
// Ignore add-ons not compatible with this Application
|
||||
compatible = false;
|
||||
var tags = element.getElementsByTagName("compatible_applications");
|
||||
if (tags.length != 1)
|
||||
return;
|
||||
var vc = Cc["@mozilla.org/xpcom/version-comparator;1"].
|
||||
getService(Ci.nsIVersionComparator);
|
||||
var apps = tags[0].getElementsByTagName("name");
|
||||
var i = 0;
|
||||
while (i < apps.length) {
|
||||
if (apps[i].textContent.toLowerCase() == app.name.toLowerCase()) {
|
||||
var minversion = apps[i].parentNode.getElementsByTagName("min_version")[0].textContent;
|
||||
var maxversion = apps[i].parentNode.getElementsByTagName("max_version")[0].textContent;
|
||||
if ((vc.compare(minversion, app.version) > 0) ||
|
||||
(vc.compare(app.version, maxversion) > 0))
|
||||
return;
|
||||
compatible = true;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (!compatible)
|
||||
return;
|
||||
|
||||
var addon = new AddonSearchResult();
|
||||
addon.id = guid[0].textContent;
|
||||
addon.rating = -1;
|
||||
var node = element.firstChild;
|
||||
while (node) {
|
||||
if (node instanceof Ci.nsIDOMElement) {
|
||||
switch (node.localName) {
|
||||
case "name":
|
||||
case "version":
|
||||
case "summary":
|
||||
case "description":
|
||||
case "eula":
|
||||
addon[node.localName] = node.textContent;
|
||||
break;
|
||||
case "rating":
|
||||
if (node.textContent.length > 0)
|
||||
addon.rating = parseInt(node.textContent);
|
||||
break;
|
||||
case "thumbnail":
|
||||
addon.thumbnailURL = node.textContent;
|
||||
break;
|
||||
case "icon":
|
||||
addon.iconURL = node.textContent;
|
||||
break;
|
||||
case "learnmore":
|
||||
addon.homepageURL = node.textContent;
|
||||
break;
|
||||
case "type":
|
||||
// The type element has an id attribute that is the id from AMO's
|
||||
// database. This doesn't match our type values to perform a mapping
|
||||
if (node.getAttribute("id") == 2)
|
||||
addon.type = Ci.nsIUpdateItem.TYPE_THEME;
|
||||
else
|
||||
addon.type = Ci.nsIUpdateItem.TYPE_EXTENSION;
|
||||
break;
|
||||
case "install":
|
||||
addon.xpiURL = node.textContent;
|
||||
if (node.hasAttribute("hash"))
|
||||
addon.xpiHash = node.getAttribute("hash");
|
||||
break;
|
||||
}
|
||||
}
|
||||
node = node.nextSibling;
|
||||
}
|
||||
|
||||
this._addons.push(addon);
|
||||
},
|
||||
|
||||
// Called when a single request has completed, parses out any add-ons and
|
||||
// either notifies the callback or does a new request for more results
|
||||
_listLoaded: function(aEvent) {
|
||||
var request = aEvent.target;
|
||||
var responseXML = request.responseXML;
|
||||
|
||||
if (!responseXML || responseXML.documentElement.namespaceURI == XMLURI_PARSE_ERROR ||
|
||||
(request.status != 200 && request.status != 0)) {
|
||||
this._reportFailure();
|
||||
return;
|
||||
}
|
||||
var elements = responseXML.documentElement.getElementsByTagName("addon");
|
||||
var oldcount = this._addons.length;
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
this._parseAddon(elements[i]);
|
||||
|
||||
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch);
|
||||
if (this._addons.length == this._maxResults) {
|
||||
this._reportSuccess(elements.length);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We didn't find any new add-ons this pass
|
||||
if (oldcount == this._addons.length)
|
||||
this._emptyCount++;
|
||||
else
|
||||
this._emptyCount = 0;
|
||||
|
||||
/* We should keep trying to find new recommended add-ons, but bail if we
|
||||
don't get a new result for a few passes. */
|
||||
if (this._recommended && this._emptyCount < 5)
|
||||
this._loadList();
|
||||
else
|
||||
this._reportSuccess(elements.length);
|
||||
},
|
||||
|
||||
// Performs a new request for results
|
||||
_loadList: function() {
|
||||
this._request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
|
||||
createInstance(Ci.nsIXMLHttpRequest);
|
||||
this._request.open("GET", this._retrieveURI, true);
|
||||
this._request.overrideMimeType("text/xml");
|
||||
|
||||
var self = this;
|
||||
this._request.onerror = function(event) { self._reportFailure(event); };
|
||||
this._request.onload = function(event) { self._listLoaded(event); };
|
||||
this._request.send(null);
|
||||
},
|
||||
|
||||
classDescription: "Addon Repository",
|
||||
contractID: "@mozilla.org/extensions/addon-repository;1",
|
||||
classID: Components.ID("{8eaaf524-7d6d-4f7d-ae8b-9277b324008d}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAddonRepository])
|
||||
}
|
||||
|
||||
function NSGetModule(aCompMgr, aFileSpec) {
|
||||
return XPCOMUtils.generateModule([AddonRepository]);
|
||||
}
|
|
@ -6215,13 +6215,11 @@ RDFItemUpdater.prototype = {
|
|||
uri.spec + ", item = " + aItem.objectSource);
|
||||
|
||||
var request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
|
||||
createInstance(Ci.nsIXMLHttpRequest).
|
||||
QueryInterface(Ci.nsIJSXMLHttpRequest);
|
||||
createInstance(Ci.nsIXMLHttpRequest);
|
||||
request.open("GET", uri.spec, true);
|
||||
request.channel.notificationCallbacks = new BadCertHandler();
|
||||
request.overrideMimeType("text/xml");
|
||||
request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
|
||||
request.QueryInterface(Ci.nsIJSXMLHttpRequest);
|
||||
|
||||
var self = this;
|
||||
request.onerror = function(event) { self.onXMLError(event, aItem); };
|
||||
|
|
|
@ -264,6 +264,131 @@ richlistitem[opType="needs-uninstall"] .notifyBadge {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.addon-search-details {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
-moz-margin-start: 6px;
|
||||
-moz-margin-end: 0;
|
||||
}
|
||||
|
||||
.addonThumbnailContainer {
|
||||
background: window;
|
||||
padding: 5px;
|
||||
border: 2px solid ActiveBorder;
|
||||
width: 135px;
|
||||
min-height: 104px;
|
||||
-moz-margin-end: 5px;
|
||||
}
|
||||
|
||||
.addonMissingThumbnail {
|
||||
color: GrayText;
|
||||
}
|
||||
|
||||
.addonFailure {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
list-style-image: url("chrome://mozapps/skin/extensions/notifyBadges.png");
|
||||
-moz-image-region: rect(0px 48px 16px 32px);
|
||||
}
|
||||
|
||||
.addonRating {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.addonLearnMore {
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.addonRating[rating] {
|
||||
display: -moz-box;
|
||||
width: 68px;
|
||||
height: 12px;
|
||||
list-style-image: url("chrome://mozapps/skin/extensions/ratings.png");
|
||||
}
|
||||
|
||||
.addonRating[rating="0"] {
|
||||
-moz-image-region: rect(0px 68px 12px 0px);
|
||||
}
|
||||
|
||||
.addonRating[rating="1"], .addonRating[rating="2"] {
|
||||
-moz-image-region: rect(12px 68px 24px 0px);
|
||||
}
|
||||
|
||||
.addonRating[rating="3"], .addonRating[rating="4"] {
|
||||
-moz-image-region: rect(24px 68px 36px 0px);
|
||||
}
|
||||
|
||||
.addonRating[rating="5"], .addonRating[rating="6"] {
|
||||
-moz-image-region: rect(36px 68px 48px 0px);
|
||||
}
|
||||
|
||||
.addonRating[rating="7"], .addonRating[rating="8"] {
|
||||
-moz-image-region: rect(48px 68px 60px 0px);
|
||||
}
|
||||
|
||||
.addonRating[rating="9"], .addonRating[rating="10"] {
|
||||
-moz-image-region: rect(60px 68px 72px 0px);
|
||||
}
|
||||
|
||||
.addonType image {
|
||||
-moz-margin-start: 6px;
|
||||
list-style-image: url("chrome://mozapps/skin/extensions/extensionIcons.png");
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.addonTypeExtension image {
|
||||
-moz-image-region: rect(0px 16px 16px 0px);
|
||||
}
|
||||
|
||||
.addonTypeTheme image {
|
||||
-moz-image-region: rect(0px 32px 16px 16px);
|
||||
}
|
||||
|
||||
vbox[typeName="status"][type="search-failure"],
|
||||
vbox[typeName="status"][type="recommended-failure"],
|
||||
vbox[typeName="status"][type="retrieve-search"],
|
||||
vbox[typeName="status"][type="retrieve-recommended"] {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
vbox[typeName="status"][type="footer-recommended"],
|
||||
vbox[typeName="status"][type="footer-search"] {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
vbox[typeName="status"][type="header-recommended"] {
|
||||
font-size: 150%;
|
||||
background: -moz-dialog;
|
||||
}
|
||||
|
||||
#searchbox {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/searchIcons.png);
|
||||
-moz-image-region: rect(0px 19px 19px 0px);
|
||||
}
|
||||
|
||||
.searchbox-search, .searchbox-cancel {
|
||||
-moz-appearance: none;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
min-width: 19px;
|
||||
}
|
||||
|
||||
.searchbox-search {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/searchIcons.png);
|
||||
-moz-image-region: rect(0px 38px 19px 19px);
|
||||
}
|
||||
|
||||
.searchbox-cancel {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/searchIcons.png);
|
||||
-moz-image-region: rect(0px 57px 19px 38px);
|
||||
}
|
||||
|
||||
#progressBox {
|
||||
padding: 5px 5px 5px 5px;
|
||||
}
|
||||
|
@ -339,6 +464,13 @@ radio#installs-view:hover, radio#installs-view[selected="true"] {
|
|||
-moz-image-region: rect(32px, 192px, 64px, 160px)
|
||||
}
|
||||
|
||||
radio#search-view {
|
||||
-moz-image-region: rect(0px, 224px, 32px, 192px)
|
||||
}
|
||||
radio#search-view:hover, radio#search-view[selected="true"] {
|
||||
-moz-image-region: rect(32px, 224px, 64px, 192px)
|
||||
}
|
||||
|
||||
/* Update view checkbox */
|
||||
.includeUpdate {
|
||||
-moz-user-focus: none;
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#heading {
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
#scrollbox {
|
||||
overflow-y: auto;
|
||||
background-color: window;
|
||||
border: 1px solid ActiveBorder;
|
||||
margin: 1em 0 1em 0;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#eula {
|
||||
font-family: monospace;
|
||||
white-space: -moz-pre-wrap;
|
||||
}
|
После Ширина: | Высота: | Размер: 1.3 KiB |
|
@ -220,6 +220,136 @@ richlistitem[opType="needs-uninstall"] .notifyBadge {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.addon-search-details {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
-moz-margin-start: 6px;
|
||||
-moz-margin-end: 0;
|
||||
}
|
||||
|
||||
.addonThumbnailContainer {
|
||||
background: window;
|
||||
padding: 5px;
|
||||
border: 2px solid ActiveBorder;
|
||||
width: 135px;
|
||||
min-height: 104px;
|
||||
-moz-margin-end: 5px;
|
||||
}
|
||||
|
||||
.addonMissingThumbnail {
|
||||
color: GrayText;
|
||||
}
|
||||
|
||||
.addonFailure {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
list-style-image: url("chrome://mozapps/skin/extensions/notifyBadges.png");
|
||||
-moz-image-region: rect(0px 48px 16px 32px);
|
||||
}
|
||||
|
||||
.addonRating {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.addonLearnMore {
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.addonRating[rating] {
|
||||
display: -moz-box;
|
||||
width: 68px;
|
||||
height: 12px;
|
||||
list-style-image: url("chrome://mozapps/skin/extensions/ratings.png");
|
||||
}
|
||||
|
||||
.addonRating[rating="0"] {
|
||||
-moz-image-region: rect(0px 68px 12px 0px);
|
||||
}
|
||||
|
||||
.addonRating[rating="1"], .addonRating[rating="2"] {
|
||||
-moz-image-region: rect(12px 68px 24px 0px);
|
||||
}
|
||||
|
||||
.addonRating[rating="3"], .addonRating[rating="4"] {
|
||||
-moz-image-region: rect(24px 68px 36px 0px);
|
||||
}
|
||||
|
||||
.addonRating[rating="5"], .addonRating[rating="6"] {
|
||||
-moz-image-region: rect(36px 68px 48px 0px);
|
||||
}
|
||||
|
||||
.addonRating[rating="7"], .addonRating[rating="8"] {
|
||||
-moz-image-region: rect(48px 68px 60px 0px);
|
||||
}
|
||||
|
||||
.addonRating[rating="9"], .addonRating[rating="10"] {
|
||||
-moz-image-region: rect(60px 68px 72px 0px);
|
||||
}
|
||||
|
||||
.addonType image {
|
||||
-moz-margin-start: 6px;
|
||||
list-style-image: url("chrome://mozapps/skin/extensions/extensionIcons.png");
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.addonTypeExtension image {
|
||||
-moz-image-region: rect(0px 16px 16px 0px);
|
||||
}
|
||||
|
||||
.addonTypeTheme image {
|
||||
-moz-image-region: rect(0px 32px 16px 16px);
|
||||
}
|
||||
|
||||
vbox[typeName="status"][type="search-failure"],
|
||||
vbox[typeName="status"][type="recommended-failure"],
|
||||
vbox[typeName="status"][type="retrieve-search"],
|
||||
vbox[typeName="status"][type="retrieve-recommended"] {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
vbox[typeName="status"][type="footer-recommended"],
|
||||
vbox[typeName="status"][type="footer-search"] {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
vbox[typeName="status"][type="header-recommended"] {
|
||||
font-size: 150%;
|
||||
background: -moz-dialog;
|
||||
}
|
||||
|
||||
#searchPanel {
|
||||
border-bottom: 1px solid #878787;
|
||||
}
|
||||
|
||||
#searchbox {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/searchIcons.png);
|
||||
-moz-image-region: rect(0px 19px 19px 0px);
|
||||
}
|
||||
|
||||
.searchbox-search, .searchbox-cancel {
|
||||
-moz-appearance: none;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
min-width: 19px;
|
||||
min-height: 19px;
|
||||
}
|
||||
|
||||
.searchbox-search {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/searchIcons.png);
|
||||
-moz-image-region: rect(0px 38px 19px 19px);
|
||||
}
|
||||
|
||||
.searchbox-cancel {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/searchIcons.png);
|
||||
-moz-image-region: rect(0px 57px 19px 38px);
|
||||
}
|
||||
|
||||
#progressBox {
|
||||
padding: 5px 5px 5px 5px;
|
||||
}
|
||||
|
|
После Ширина: | Высота: | Размер: 568 B |
После Ширина: | Высота: | Размер: 1.5 KiB |
|
@ -13,10 +13,14 @@ classic.jar:
|
|||
skin/classic/mozapps/extensions/question.png (extensions/question.png)
|
||||
skin/classic/mozapps/extensions/themeGeneric.png (extensions/themeGeneric.png)
|
||||
skin/classic/mozapps/extensions/viewButtons.png (extensions/viewButtons.png)
|
||||
skin/classic/mozapps/extensions/ratings.png (extensions/ratings.png)
|
||||
skin/classic/mozapps/extensions/extensionIcons.png (extensions/extensionIcons.png)
|
||||
skin/classic/mozapps/extensions/searchIcons.png (extensions/searchIcons.png)
|
||||
skin/classic/mozapps/extensions/about.css (extensions/about.css)
|
||||
skin/classic/mozapps/extensions/extensions.css (extensions/extensions.css)
|
||||
skin/classic/mozapps/extensions/extensions.xml (extensions/extensions.xml)
|
||||
skin/classic/mozapps/extensions/update.css (extensions/update.css)
|
||||
skin/classic/mozapps/extensions/eula.css (extensions/eula.css)
|
||||
skin/classic/mozapps/plugins/missingPlugin.css (plugins/missingPlugin.css)
|
||||
skin/classic/mozapps/plugins/pluginGeneric.png (plugins/pluginGeneric.png)
|
||||
skin/classic/mozapps/profile/profileicon.png (profile/profileicon.png)
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#heading {
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
#scrollbox {
|
||||
overflow-y: auto;
|
||||
background-color: window;
|
||||
border: 1px solid ActiveBorder;
|
||||
margin: 1em 0 1em 0;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#eula {
|
||||
font-family: monospace;
|
||||
white-space: -moz-pre-wrap;
|
||||
}
|
После Ширина: | Высота: | Размер: 1.3 KiB |
|
@ -263,6 +263,138 @@ richlistitem[opType="needs-uninstall"] .notifyBadge {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.addon-search-details {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
-moz-margin-start: 6px;
|
||||
-moz-margin-end: 0;
|
||||
}
|
||||
|
||||
.addonThumbnailContainer {
|
||||
background: window;
|
||||
padding: 5px;
|
||||
border: 2px solid ActiveBorder;
|
||||
width: 135px;
|
||||
min-height: 104px;
|
||||
-moz-margin-end: 5px;
|
||||
}
|
||||
|
||||
.addonMissingThumbnail {
|
||||
color: GrayText;
|
||||
}
|
||||
|
||||
.addonFailure {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
list-style-image: url("chrome://mozapps/skin/extensions/notifyBadges.png");
|
||||
-moz-image-region: rect(0px 48px 16px 32px);
|
||||
}
|
||||
|
||||
.addonRating {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.addonLearnMore {
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.addonRating[rating] {
|
||||
display: -moz-box;
|
||||
width: 68px;
|
||||
height: 12px;
|
||||
list-style-image: url("chrome://mozapps/skin/extensions/ratings.png");
|
||||
}
|
||||
|
||||
.addonRating[rating="0"] {
|
||||
-moz-image-region: rect(0px 68px 12px 0px);
|
||||
}
|
||||
|
||||
.addonRating[rating="1"], .addonRating[rating="2"] {
|
||||
-moz-image-region: rect(12px 68px 24px 0px);
|
||||
}
|
||||
|
||||
.addonRating[rating="3"], .addonRating[rating="4"] {
|
||||
-moz-image-region: rect(24px 68px 36px 0px);
|
||||
}
|
||||
|
||||
.addonRating[rating="5"], .addonRating[rating="6"] {
|
||||
-moz-image-region: rect(36px 68px 48px 0px);
|
||||
}
|
||||
|
||||
.addonRating[rating="7"], .addonRating[rating="8"] {
|
||||
-moz-image-region: rect(48px 68px 60px 0px);
|
||||
}
|
||||
|
||||
.addonRating[rating="9"], .addonRating[rating="10"] {
|
||||
-moz-image-region: rect(60px 68px 72px 0px);
|
||||
}
|
||||
|
||||
.addonType image {
|
||||
-moz-margin-start: 6px;
|
||||
list-style-image: url("chrome://mozapps/skin/extensions/extensionIcons.png");
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.addonTypeExtension image {
|
||||
-moz-image-region: rect(0px 16px 16px 0px);
|
||||
}
|
||||
|
||||
.addonTypeTheme image {
|
||||
-moz-image-region: rect(0px 32px 16px 16px);
|
||||
}
|
||||
|
||||
vbox[typeName="status"][type="search-failure"],
|
||||
vbox[typeName="status"][type="recommended-failure"],
|
||||
vbox[typeName="status"][type="retrieve-search"],
|
||||
vbox[typeName="status"][type="retrieve-recommended"] {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
vbox[typeName="status"][type="footer-recommended"],
|
||||
vbox[typeName="status"][type="footer-search"] {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
vbox[typeName="status"][type="header-recommended"] {
|
||||
font-size: 150%;
|
||||
background: -moz-dialog;
|
||||
}
|
||||
|
||||
#searchbox {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/searchIcons.png);
|
||||
-moz-image-region: rect(0px 19px 19px 0px);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.searchbox-search, .searchbox-cancel {
|
||||
-moz-appearance: none;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
min-width: 19px;
|
||||
}
|
||||
|
||||
.searchbox-search .button-box,
|
||||
.searchbox-cancel .button-box {
|
||||
border: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.searchbox-search {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/searchIcons.png);
|
||||
-moz-image-region: rect(0px 38px 19px 19px);
|
||||
}
|
||||
|
||||
.searchbox-cancel {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/searchIcons.png);
|
||||
-moz-image-region: rect(0px 57px 19px 38px);
|
||||
}
|
||||
|
||||
#progressBox {
|
||||
padding: 5px 5px 5px 5px;
|
||||
}
|
||||
|
@ -345,6 +477,13 @@ radio#installs-view:hover, radio#installs-view[selected="true"] {
|
|||
-moz-image-region: rect(32px, 192px, 64px, 160px)
|
||||
}
|
||||
|
||||
radio#search-view {
|
||||
-moz-image-region: rect(0px, 224px, 32px, 192px)
|
||||
}
|
||||
radio#search-view:hover, radio#search-view[selected="true"] {
|
||||
-moz-image-region: rect(32px, 224px, 64px, 192px)
|
||||
}
|
||||
|
||||
/* Update view checkbox */
|
||||
.includeUpdate {
|
||||
-moz-user-focus: none;
|
||||
|
|
После Ширина: | Высота: | Размер: 568 B |
После Ширина: | Высота: | Размер: 1.5 KiB |
Двоичные данные
toolkit/themes/winstripe/mozapps/extensions/viewButtons.png
До Ширина: | Высота: | Размер: 23 KiB После Ширина: | Высота: | Размер: 24 KiB |
|
@ -15,6 +15,10 @@ classic.jar:
|
|||
skin/classic/mozapps/extensions/update.css (extensions/update.css)
|
||||
skin/classic/mozapps/extensions/themeGeneric.png (extensions/themeGeneric.png)
|
||||
skin/classic/mozapps/extensions/viewButtons.png (extensions/viewButtons.png)
|
||||
skin/classic/mozapps/extensions/ratings.png (extensions/ratings.png)
|
||||
skin/classic/mozapps/extensions/extensionIcons.png (extensions/extensionIcons.png)
|
||||
skin/classic/mozapps/extensions/searchIcons.png (extensions/searchIcons.png)
|
||||
skin/classic/mozapps/extensions/eula.css (extensions/eula.css)
|
||||
skin/classic/mozapps/plugins/missingPlugin.css (plugins/missingPlugin.css)
|
||||
skin/classic/mozapps/plugins/pluginGeneric.png (plugins/pluginGeneric.png)
|
||||
skin/classic/mozapps/plugins/pluginInstallerWizard.css (plugins/pluginInstallerWizard.css)
|
||||
|
|