Bug 726444 - Implement the Downloads Panel. r=mak ui-r=limi

Includes: Bug 697679 - By Javi Rueda <leofigueres@yahoo.com>.
This commit is contained in:
Paolo Amadini 2012-04-17 13:35:09 +02:00
parent 7dbd0da436
commit 9180b309a7
56 changed files with 5308 additions and 9 deletions

View File

@ -349,6 +349,12 @@ pref("browser.download.manager.quitBehavior", 0);
pref("browser.download.manager.scanWhenDone", true);
pref("browser.download.manager.resumeOnWakeDelay", 10000);
// This allows disabling the Downloads Panel in favor of the old interface.
pref("browser.download.useToolkitUI", false);
// This controls retention behavior in the Downloads Panel only.
pref("browser.download.panel.removeFinishedDownloads", false);
// search engines URL
pref("browser.search.searchEnginesURL", "https://addons.mozilla.org/%LOCALE%/firefox/search-engines/");

View File

@ -1391,6 +1391,8 @@ function BrowserStartup() {
gPrivateBrowsingUI.init();
DownloadsButton.initializePlaceholder();
retrieveToolbarIconsizesFromTheme();
gDelayedStartupTimeoutId = setTimeout(delayedStartup, 0, isLoadingBlank, mustLoadSidebar);
@ -1640,6 +1642,11 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
#endif
}, 10000);
// The object handling the downloads indicator is also initialized here in the
// delayed startup function, but the actual indicator element is not loaded
// unless there are downloads to be displayed.
DownloadsButton.initializeIndicator();
#ifndef XP_MACOSX
updateEditUIVisibility();
let placesContext = document.getElementById("placesContext");
@ -3722,6 +3729,7 @@ function BrowserCustomizeToolbar()
PlacesToolbarHelper.customizeStart();
BookmarksMenuButton.customizeStart();
DownloadsButton.customizeStart();
TabsInTitlebar.allowedBy("customizing-toolbars", false);
@ -3788,6 +3796,7 @@ function BrowserToolboxCustomizeDone(aToolboxChanged) {
PlacesToolbarHelper.customizeDone();
BookmarksMenuButton.customizeDone();
DownloadsButton.customizeDone();
// The url bar splitter state is dependent on whether stop/reload
// and the location bar are combined, so we need this ordering

View File

@ -855,6 +855,9 @@
label="&printButton.label;" command="cmd_print"
tooltiptext="&printButton.tooltip;"/>
<!-- This is a placeholder for the Downloads Indicator. It is visible
only during the customization of the toolbar or in the palette, and
is replaced when customization is done. -->
<toolbarbutton id="downloads-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
observes="Tools:Downloads"
ondrop="DownloadsButtonDNDObserver.onDrop(event)"

View File

@ -41,5 +41,7 @@
<script type="application/javascript" src="chrome://global/content/viewZoomOverlay.js"/>
<script type="application/javascript" src="chrome://browser/content/places/browserPlacesViews.js"/>
<script type="application/javascript" src="chrome://browser/content/browser.js"/>
<script type="application/javascript" src="chrome://browser/content/downloads/downloads.js"/>
<script type="application/javascript" src="chrome://browser/content/downloads/indicator.js"/>
<script type="application/javascript" src="chrome://global/content/inlineSpellCheckUI.js"/>
<script type="application/javascript" src="chrome://global/content/viewSourceUtils.js"/>

View File

@ -62,6 +62,7 @@ PARALLEL_DIRS = \
about \
certerror \
dirprovider \
downloads \
feeds \
places \
preferences \

View File

@ -0,0 +1,18 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
DIRS = src
ifdef ENABLE_TESTS
DIRS += test
endif
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,60 @@
<?xml version="1.0"?>
# -*- Mode: HTML; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# vim: set ts=2 et sw=2 tw=80:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
<!DOCTYPE bindings SYSTEM "chrome://browser/locale/downloads/downloads.dtd">
<bindings id="downloadBindings"
xmlns="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xbl="http://www.mozilla.org/xbl">
<binding id="download"
extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
<resources>
<stylesheet src="chrome://browser/skin/downloads/downloads.css"/>
</resources>
<content orient="horizontal">
<xul:hbox class="downloadInfo"
align="center"
flex="1"
onclick="DownloadsView.onDownloadClick(event);">
<xul:vbox pack="center">
<xul:image class="downloadTypeIcon"
validate="always"
xbl:inherits="src=image"/>
<xul:image class="downloadTypeIcon blockedIcon"/>
</xul:vbox>
<xul:vbox pack="center"
flex="1">
<xul:description class="downloadTarget"
crop="center"
xbl:inherits="value=target,tooltiptext=target"/>
<xul:progressmeter anonid="progressmeter"
class="downloadProgress"
min="0"
max="100"
xbl:inherits="mode=progressmode,value=progress"/>
<xul:description class="downloadDetails"
crop="end"
xbl:inherits="value=status,tooltiptext=statusTip"/>
</xul:vbox>
</xul:hbox>
<xul:hbox class="downloadButtonContainer"
align="center">
<xul:button class="downloadButton downloadCancel"
tooltiptext="&cmd.cancel.label;"
oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_cancel');"/>
<xul:button class="downloadButton downloadRetry"
tooltiptext="&cmd.retry.label;"
oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_retry');"/>
<xul:button class="downloadButton downloadShow"
tooltiptext="&cmd.show.label;"
oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_show');"/>
</xul:hbox>
</content>
</binding>
</bindings>

View File

@ -0,0 +1,90 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/*** Download items ***/
richlistitem[type="download"] {
-moz-binding: url('chrome://browser/content/downloads/download.xml#download');
}
richlistitem[type="download"]:not([selected]) button {
/* Only focus buttons in the selected item. */
-moz-user-focus: none;
}
/*** Visibility of controls inside download items ***/
.download-state:-moz-any( [state="6"], /* Blocked (parental) */
[state="8"], /* Blocked (dirty) */
[state="9"]) /* Blocked (policy) */
.downloadTypeIcon:not(.blockedIcon),
.download-state:not(:-moz-any([state="6"], /* Blocked (parental) */
[state="8"], /* Blocked (dirty) */
[state="9"]) /* Blocked (policy) */)
.downloadTypeIcon.blockedIcon,
.download-state:not(:-moz-any([state="-1"],/* Starting (initial) */
[state="5"], /* Starting (queued) */
[state="0"], /* Downloading */
[state="4"], /* Paused */
[state="7"]) /* Scanning */)
.downloadProgress,
.download-state:not( [state="0"] /* Downloading */)
.downloadPauseMenuItem,
.download-state:not( [state="4"] /* Paused */)
.downloadResumeMenuItem,
.download-state:not(:-moz-any([state="-1"],/* Starting (initial) */
[state="5"], /* Starting (queued) */
[state="0"], /* Downloading */
[state="4"]) /* Paused */)
.downloadCancel,
.download-state:not(:-moz-any([state="2"], /* Failed */
[state="4"]) /* Paused */)
.downloadCancelMenuItem,
.download-state:not(:-moz-any([state="1"], /* Finished */
[state="3"], /* Canceled */
[state="6"], /* Blocked (parental) */
[state="8"], /* Blocked (dirty) */
[state="9"]) /* Blocked (policy) */)
.downloadRemoveFromListMenuItem,
.download-state:not(:-moz-any([state="2"], /* Failed */
[state="3"]) /* Canceled */)
.downloadRetry,
.download-state:not( [state="1"] /* Finished */)
.downloadShow,
.download-state:not(:-moz-any([state="-1"],/* Starting (initial) */
[state="5"], /* Starting (queued) */
[state="0"], /* Downloading */
[state="4"]) /* Paused */)
.downloadShowMenuItem,
.download-state[state="7"] .downloadCommandsSeparator
{
display: none;
}
/*** Visibility of controls inside the downloads indicator ***/
#downloads-indicator:-moz-any([progress],
[counter],
[paused]) #downloads-indicator-icon,
#downloads-indicator:not(:-moz-any([progress],
[counter],
[paused]))
#downloads-indicator-progress-area
{
visibility: hidden;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,114 @@
<?xml version="1.0"?>
# -*- Mode: HTML; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# vim: set ts=2 et sw=2 tw=80:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
<?xml-stylesheet href="chrome://browser/content/downloads/downloads.css"?>
<?xml-stylesheet href="chrome://browser/skin/downloads/downloads.css"?>
<!DOCTYPE overlay SYSTEM "chrome://browser/locale/downloads/downloads.dtd">
<overlay xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
id="downloadsOverlay">
<commandset>
<command id="downloadsCmd_doDefault"
oncommand="goDoCommand('downloadsCmd_doDefault')"/>
<command id="downloadsCmd_pauseResume"
oncommand="goDoCommand('downloadsCmd_pauseResume')"/>
<command id="downloadsCmd_cancel"
oncommand="goDoCommand('downloadsCmd_cancel')"/>
<command id="downloadsCmd_open"
oncommand="goDoCommand('downloadsCmd_open')"/>
<command id="downloadsCmd_show"
oncommand="goDoCommand('downloadsCmd_show')"/>
<command id="downloadsCmd_retry"
oncommand="goDoCommand('downloadsCmd_retry')"/>
<command id="downloadsCmd_openReferrer"
oncommand="goDoCommand('downloadsCmd_openReferrer')"/>
<command id="downloadsCmd_copyLocation"
oncommand="goDoCommand('downloadsCmd_copyLocation')"/>
<command id="downloadsCmd_clearList"
oncommand="goDoCommand('downloadsCmd_clearList')"/>
</commandset>
<popupset>
<!-- The panel has level="top" to ensure that it is never hidden by the
taskbar on Windows. See bug 672365. For accessibility to screen
readers, we use a label on the panel instead of the anchor because the
panel can also be displayed without an anchor. -->
<panel id="downloadsPanel"
aria-label="&downloads.title;"
role="group"
type="arrow"
orient="vertical"
level="top"
onpopupshown="DownloadsPanel.onPopupShown(event);"
onpopuphidden="DownloadsPanel.onPopupHidden(event);">
<!-- The following popup menu should be a child of the panel element,
otherwise flickering may occur when the cursor is moved over the area
of a disabled menu item that overlaps the panel. See bug 492960. -->
<menupopup id="downloadsContextMenu"
class="download-state">
<menuitem command="downloadsCmd_pauseResume"
class="downloadPauseMenuItem"
label="&cmd.pause.label;"
accesskey="&cmd.pause.accesskey;"/>
<menuitem command="downloadsCmd_pauseResume"
class="downloadResumeMenuItem"
label="&cmd.resume.label;"
accesskey="&cmd.resume.accesskey;"/>
<menuitem command="downloadsCmd_cancel"
class="downloadCancelMenuItem"
label="&cmd.cancel.label;"
accesskey="&cmd.cancel.accesskey;"/>
<menuitem command="cmd_delete"
class="downloadRemoveFromListMenuItem"
label="&cmd.removeFromList.label;"
accesskey="&cmd.removeFromList.accesskey;"/>
<menuitem command="downloadsCmd_show"
class="downloadShowMenuItem"
#ifdef XP_MACOSX
label="&cmd.showMac.label;"
accesskey="&cmd.showMac.accesskey;"
#else
label="&cmd.show.label;"
accesskey="&cmd.show.accesskey;"
#endif
/>
<menuseparator class="downloadCommandsSeparator"/>
<menuitem command="downloadsCmd_openReferrer"
label="&cmd.goToDownloadPage.label;"
accesskey="&cmd.goToDownloadPage.accesskey;"/>
<menuitem command="downloadsCmd_copyLocation"
label="&cmd.copyDownloadLink.label;"
accesskey="&cmd.copyDownloadLink.accesskey;"/>
<menuseparator/>
<menuitem command="downloadsCmd_clearList"
label="&cmd.clearList.label;"
accesskey="&cmd.clearList.accesskey;"/>
</menupopup>
<richlistbox id="downloadsListBox"
class="plain"
flex="1"
context="downloadsContextMenu"
onkeypress="DownloadsView.onDownloadKeyPress(event);"
oncontextmenu="DownloadsView.onDownloadContextMenu(event);"
ondragstart="DownloadsView.onDownloadDragStart(event);"/>
<button id="downloadsHistory"
class="plain"
label="&downloadshistory.label;"
accesskey="&downloadshistory.accesskey;"
oncommand="DownloadsPanel.showDownloadsHistory();"/>
</panel>
</popupset>
</overlay>

View File

@ -0,0 +1,591 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Handles the indicator that displays the progress of ongoing downloads, which
* is also used as the anchor for the downloads panel.
*
* This module includes the following constructors and global objects:
*
* DownloadsButton
* Main entry point for the downloads indicator. Depending on how the toolbars
* have been customized, this object determines if we should show a fully
* functional indicator, a placeholder used during customization and in the
* customization palette, or a neutral view as a temporary anchor for the
* downloads panel.
*
* DownloadsIndicatorView
* Builds and updates the actual downloads status widget, responding to changes
* in the global status data, or provides a neutral view if the indicator is
* removed from the toolbars and only used as a temporary anchor. In addition,
* handles the user interaction events raised by the widget.
*/
"use strict";
////////////////////////////////////////////////////////////////////////////////
//// DownloadsButton
/**
* Main entry point for the downloads indicator. Depending on how the toolbars
* have been customized, this object determines if we should show a fully
* functional indicator, a placeholder used during customization and in the
* customization palette, or a neutral view as a temporary anchor for the
* downloads panel.
*/
const DownloadsButton = {
/**
* Location of the indicator overlay.
*/
get kIndicatorOverlay()
"chrome://browser/content/downloads/indicatorOverlay.xul",
/**
* Returns a reference to the downloads button position placeholder, or null
* if not available because it has been removed from the toolbars.
*/
get _placeholder()
{
return document.getElementById("downloads-button");
},
/**
* This function is called synchronously at window initialization. It only
* sets the visibility of user interface elements to avoid flickering.
*
* NOTE: To keep startup time to a minimum, this function should not perform
* any expensive operations or input/output, and should not cause the
* Download Manager service to start.
*/
initializePlaceholder: function DB_initializePlaceholder()
{
// Exit now if the feature is disabled. To improve startup time, we don't
// load the DownloadsCommon module yet, but check the preference directly.
if (gPrefService.getBoolPref("browser.download.useToolkitUI")) {
return;
}
// We must hide the placeholder used for toolbar customization, unless it
// has been removed from the toolbars and is now located in the palette.
let placeholder = this._placeholder;
if (placeholder) {
placeholder.collapsed = true;
}
},
/**
* This function is called asynchronously just after window initialization.
*
* NOTE: This function should limit the input/output it performs to improve
* startup time, and in particular should not cause the Download Manager
* service to start.
*/
initializeIndicator: function DB_initializeIndicator()
{
this._update();
},
/**
* Indicates whether toolbar customization is in progress.
*/
_customizing: false,
/**
* This function is called when toolbar customization starts.
*
* During customization, we never show the actual download progress indication
* or the event notifications, but we show a neutral placeholder. The neutral
* placeholder is an ordinary button defined in the browser window that can be
* moved freely between the toolbars and the customization palette.
*/
customizeStart: function DB_customizeStart()
{
// Hide the indicator and prevent it to be displayed as a temporary anchor
// during customization, even if requested using the getAnchor method.
this._customizing = true;
this._anchorRequested = false;
let indicator = DownloadsIndicatorView.indicator;
if (indicator) {
indicator.collapsed = true;
}
let placeholder = this._placeholder;
if (placeholder) {
placeholder.collapsed = false;
}
},
/**
* This function is called when toolbar customization ends.
*/
customizeDone: function DB_customizeDone()
{
this._customizing = false;
this._update();
},
/**
* This function is called during initialization or when toolbar customization
* ends. It determines if we should enable or disable the object that keeps
* the indicator updated, and ensures that the placeholder is hidden unless it
* has been moved to the customization palette.
*
* NOTE: This function is also called on startup, thus it should limit the
* input/output it performs, and in particular should not cause the
* Download Manager service to start.
*/
_update: function DB_update() {
this._updatePositionInternal();
let placeholder = this._placeholder;
if (!DownloadsCommon.useToolkitUI) {
DownloadsIndicatorView.ensureInitialized();
if (placeholder) {
placeholder.collapsed = true;
}
} else {
DownloadsIndicatorView.ensureTerminated();
}
},
/**
* Determines the position where the indicator should appear, and moves its
* associated element to the new position. This does not happen if the
* indicator is currently being used as the anchor for the panel, to ensure
* that the panel doesn't flicker because we move the DOM element to which
* it's anchored.
*/
updatePosition: function DB_updatePosition()
{
if (!this._anchorRequested) {
this._updatePositionInternal();
}
},
/**
* Determines the position where the indicator should appear, and moves its
* associated element to the new position.
*
* @return Anchor element, or null if the indicator is not visible.
*/
_updatePositionInternal: function DB_updatePositionInternal()
{
let indicator = DownloadsIndicatorView.indicator;
if (!indicator) {
// Exit now if the indicator overlay isn't loaded yet.
return null;
}
let placeholder = this._placeholder;
// Firstly, determine if we should always hide the indicator.
if (!placeholder && !this._anchorRequested &&
!DownloadsIndicatorView.hasDownloads) {
indicator.collapsed = true;
return null;
}
indicator.collapsed = false;
indicator.open = this._anchorRequested;
// Determine if we should display the indicator in a known position.
if (placeholder) {
placeholder.parentNode.insertBefore(indicator, placeholder);
// Determine if the placeholder is located on a visible toolbar.
if (isElementVisible(placeholder.parentNode)) {
return DownloadsIndicatorView.indicatorAnchor;
}
}
// If not customized, the indicator is normally in the navigation bar.
// Always place it in the default position, unless we need an anchor.
if (!this._anchorRequested) {
this._navBar.appendChild(indicator);
return null;
}
// Show the indicator temporarily in the navigation bar, if visible.
if (isElementVisible(this._navBar)) {
this._navBar.appendChild(indicator);
return DownloadsIndicatorView.indicatorAnchor;
}
// Show the indicator temporarily in the tab bar, if visible.
if (!this._tabsToolbar.collapsed) {
this._tabsToolbar.appendChild(indicator);
return DownloadsIndicatorView.indicatorAnchor;
}
// The temporary anchor cannot be shown.
return null;
},
/**
* Indicates whether we should try and show the indicator temporarily as an
* anchor for the panel, even if the indicator would be hidden by default.
*/
_anchorRequested: false,
/**
* Ensures that there is an anchor available for the panel.
*
* @param aCallback
* Called when the anchor is available, passing the element where the
* panel should be anchored, or null if an anchor is not available (for
* example because both the tab bar and the navigation bar are hidden).
*/
getAnchor: function DB_getAnchor(aCallback)
{
// Do not allow anchoring the panel to the element while customizing.
if (this._customizing) {
aCallback(null);
return;
}
function DB_GA_callback() {
this._anchorRequested = true;
aCallback(this._updatePositionInternal());
}
DownloadsOverlayLoader.ensureOverlayLoaded(this.kIndicatorOverlay,
DB_GA_callback.bind(this));
},
/**
* Allows the temporary anchor to be hidden.
*/
releaseAnchor: function DB_releaseAnchor()
{
this._anchorRequested = false;
this._updatePositionInternal();
},
get _tabsToolbar()
{
delete this._tabsToolbar;
return this._tabsToolbar = document.getElementById("TabsToolbar");
},
get _navBar()
{
delete this._navBar;
return this._navBar = document.getElementById("nav-bar");
}
};
////////////////////////////////////////////////////////////////////////////////
//// DownloadsIndicatorView
/**
* Builds and updates the actual downloads status widget, responding to changes
* in the global status data, or provides a neutral view if the indicator is
* removed from the toolbars and only used as a temporary anchor. In addition,
* handles the user interaction events raised by the widget.
*/
const DownloadsIndicatorView = {
/**
* True when the view is connected with the underlying downloads data.
*/
_initialized: false,
/**
* True when the user interface elements required to display the indicator
* have finished loading in the browser window, and can be referenced.
*/
_operational: false,
/**
* Prepares the downloads indicator to be displayed.
*/
ensureInitialized: function DIV_ensureInitialized()
{
if (this._initialized) {
return;
}
this._initialized = true;
window.addEventListener("unload", this.onWindowUnload, false);
DownloadsCommon.indicatorData.addView(this);
},
/**
* Frees the internal resources related to the indicator.
*/
ensureTerminated: function DIV_ensureTerminated()
{
if (!this._initialized) {
return;
}
this._initialized = false;
window.removeEventListener("unload", this.onWindowUnload, false);
DownloadsCommon.indicatorData.removeView(this);
// Reset the view properties, so that a neutral indicator is displayed if we
// are visible only temporarily as an anchor.
this.counter = "";
this.percentComplete = 0;
this.paused = false;
this.attention = false;
},
/**
* Ensures that the user interface elements required to display the indicator
* are loaded, then invokes the given callback.
*/
_ensureOperational: function DIV_ensureOperational(aCallback)
{
if (this._operational) {
aCallback();
return;
}
function DIV_EO_callback() {
this._operational = true;
// If the view is initialized, we need to update the elements now that
// they are finally available in the document.
if (this._initialized) {
DownloadsCommon.indicatorData.refreshView(this);
}
aCallback();
}
DownloadsOverlayLoader.ensureOverlayLoaded(
DownloadsButton.kIndicatorOverlay,
DIV_EO_callback.bind(this));
},
//////////////////////////////////////////////////////////////////////////////
//// Direct control functions
/**
* Set while we are waiting for a notification to fade out.
*/
_notificationTimeout: null,
/**
* If the status indicator is visible in its assigned position, shows for a
* brief time a visual notification of a relevant event, like a new download.
*/
showEventNotification: function DIV_showEventNotification()
{
if (!this._initialized) {
return;
}
function DIV_SEN_callback() {
if (this._notificationTimeout) {
clearTimeout(this._notificationTimeout);
}
let indicator = this.indicator;
indicator.setAttribute("notification", "true");
this._notificationTimeout = setTimeout(
function () indicator.removeAttribute("notification"), 1000);
}
this._ensureOperational(DIV_SEN_callback.bind(this));
},
//////////////////////////////////////////////////////////////////////////////
//// Callback functions from DownloadsIndicatorData
/**
* Indicates whether the indicator should be shown because there are some
* downloads to be displayed.
*/
set hasDownloads(aValue)
{
if (this._hasDownloads != aValue) {
this._hasDownloads = aValue;
// If there is at least one download, ensure that the view elements are
// loaded before determining the position of the downloads button.
if (aValue) {
this._ensureOperational(function() DownloadsButton.updatePosition());
} else {
DownloadsButton.updatePosition();
}
}
return aValue;
},
get hasDownloads()
{
return this._hasDownloads;
},
_hasDownloads: false,
/**
* Status text displayed in the indicator. If this is set to an empty value,
* then the small downloads icon is displayed instead of the text.
*/
set counter(aValue)
{
if (!this._operational) {
return this._counter;
}
if (this._counter !== aValue) {
this._counter = aValue;
if (this._counter)
this.indicator.setAttribute("counter", "true");
else
this.indicator.removeAttribute("counter");
// We have to set the attribute instead of using the property because the
// XBL binding isn't applied if the element is invisible for any reason.
this._indicatorCounter.setAttribute("value", aValue);
}
return aValue;
},
_counter: null,
/**
* Progress indication to display, from 0 to 100, or -1 if unknown. The
* progress bar is hidden if the current progress is unknown and no status
* text is set in the "counter" property.
*/
set percentComplete(aValue)
{
if (!this._operational) {
return this._percentComplete;
}
if (this._percentComplete !== aValue) {
this._percentComplete = aValue;
if (this._percentComplete >= 0)
this.indicator.setAttribute("progress", "true");
else
this.indicator.removeAttribute("progress");
// We have to set the attribute instead of using the property because the
// XBL binding isn't applied if the element is invisible for any reason.
this._indicatorProgress.setAttribute("value", Math.max(aValue, 0));
}
return aValue;
},
_percentComplete: null,
/**
* Indicates whether the progress won't advance because of a paused state.
* Setting this property forces a paused progress bar to be displayed, even if
* the current progress information is unavailable.
*/
set paused(aValue)
{
if (!this._operational) {
return this._paused;
}
if (this._paused != aValue) {
this._paused = aValue;
if (this._paused) {
this.indicator.setAttribute("paused", "true")
} else {
this.indicator.removeAttribute("paused");
}
}
return aValue;
},
_paused: false,
/**
* Set when the indicator should draw user attention to itself.
*/
set attention(aValue)
{
if (!this._operational) {
return this._attention;
}
if (this._attention != aValue) {
this._attention = aValue;
if (aValue) {
this.indicator.setAttribute("attention", "true")
} else {
this.indicator.removeAttribute("attention");
}
}
return aValue;
},
_attention: false,
//////////////////////////////////////////////////////////////////////////////
//// User interface event functions
onWindowUnload: function DIV_onWindowUnload()
{
// This function is registered as an event listener, we can't use "this".
DownloadsIndicatorView.ensureTerminated();
},
onCommand: function DIV_onCommand(aEvent)
{
if (DownloadsCommon.useToolkitUI) {
// The panel won't suppress attention for us, we need to clear now.
DownloadsCommon.indicatorData.attention = false;
}
BrowserDownloadsUI();
aEvent.stopPropagation();
},
onDragOver: function DIV_onDragOver(aEvent)
{
browserDragAndDrop.dragOver(aEvent);
},
onDragExit: function () { },
onDrop: function DIV_onDrop(aEvent)
{
let name = {};
let url = browserDragAndDrop.drop(aEvent, name);
if (url) {
saveURL(url, name.value, null, true, true);
aEvent.preventDefault();
}
},
/**
* Returns a reference to the main indicator element, or null if the element
* is not present in the browser window yet.
*/
get indicator()
{
let indicator = document.getElementById("downloads-indicator");
if (!indicator) {
return null;
}
// Once the element is loaded, it will never be unloaded.
delete this.indicator;
return this.indicator = indicator;
},
get indicatorAnchor()
{
delete this.indicatorAnchor;
return this.indicatorAnchor =
document.getElementById("downloads-indicator-anchor");
},
get _indicatorCounter()
{
delete this._indicatorCounter;
return this._indicatorCounter =
document.getElementById("downloads-indicator-counter");
},
get _indicatorProgress()
{
delete this._indicatorProgress;
return this._indicatorProgress =
document.getElementById("downloads-indicator-progress");
}
};

View File

@ -0,0 +1,51 @@
<?xml version="1.0"?>
# -*- Mode: HTML; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# vim: set ts=2 et sw=2 tw=80:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
<?xml-stylesheet href="chrome://browser/content/downloads/downloads.css"?>
<?xml-stylesheet href="chrome://browser/skin/downloads/downloads.css"?>
<!DOCTYPE overlay SYSTEM "chrome://browser/locale/downloads/downloads.dtd">
<overlay xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
id="indicatorOverlay">
<popupset>
<!-- The downloads indicator is placed in its final toolbar location
programmatically, and can be shown temporarily even when its
placeholder is removed from the toolbars. Its initial location within
the document must not be a toolbar or the toolbar palette, otherwise the
toolbar handling code could remove it from the document. -->
<toolbarbutton id="downloads-indicator"
class="toolbarbutton-1 chromeclass-toolbar-additional"
tooltiptext="&indicator.tooltiptext;"
collapsed="true"
oncommand="DownloadsIndicatorView.onCommand(event);"
ondrop="DownloadsIndicatorView.onDrop(event);"
ondragover="DownloadsIndicatorView.onDragOver(event);"
ondragenter="DownloadsIndicatorView.onDragOver(event);"
ondragleave="DownloadsIndicatorView.onDragLeave(event);">
<!-- The panel's anchor area is smaller than the outer button, but must
always be visible and must not move or resize when the indicator
state changes, otherwise the panel could change its position or lose
its arrow unexpectedly. -->
<stack id="downloads-indicator-anchor"
class="toolbarbutton-icon">
<vbox id="downloads-indicator-progress-area"
pack="center">
<description id="downloads-indicator-counter"/>
<progressmeter id="downloads-indicator-progress"
class="plain"
min="0"
max="100"/>
</vbox>
<vbox id="downloads-indicator-icon"/>
<vbox id="downloads-indicator-notification"/>
</stack>
</toolbarbutton>
</popupset>
</overlay>

View File

@ -0,0 +1,7 @@
browser.jar:
* content/browser/downloads/download.xml (content/download.xml)
content/browser/downloads/downloads.css (content/downloads.css)
content/browser/downloads/downloads.js (content/downloads.js)
* content/browser/downloads/downloadsOverlay.xul (content/downloadsOverlay.xul)
content/browser/downloads/indicator.js (content/indicator.js)
* content/browser/downloads/indicatorOverlay.xul (content/indicatorOverlay.xul)

View File

@ -0,0 +1,4 @@
component {49507fe5-2cee-4824-b6a3-e999150ce9b8} DownloadsStartup.js
contract @mozilla.org/browser/downloadsstartup;1 {49507fe5-2cee-4824-b6a3-e999150ce9b8}
category app-startup DownloadsStartup service,@mozilla.org/browser/downloadsstartup;1
component {4d99321e-d156-455b-81f7-e7aa2308134f} DownloadsUI.js

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,242 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* This component listens to notifications for startup, shutdown and session
* restore, controlling which downloads should be loaded from the database.
*
* To avoid affecting startup performance, this component monitors the current
* session restore state, but defers the actual downloads data manipulation
* until the Download Manager service is loaded.
*/
"use strict";
////////////////////////////////////////////////////////////////////////////////
//// Globals
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
"resource:///modules/DownloadsCommon.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gSessionStartup",
"@mozilla.org/browser/sessionstartup;1",
"nsISessionStartup");
XPCOMUtils.defineLazyServiceGetter(this, "gPrivateBrowsingService",
"@mozilla.org/privatebrowsing;1",
"nsIPrivateBrowsingService");
const kObservedTopics = [
"sessionstore-windows-restored",
"sessionstore-browser-state-restored",
"download-manager-initialized",
"download-manager-change-retention",
"private-browsing-transition-complete",
"browser-lastwindow-close-granted",
"quit-application",
"profile-change-teardown",
];
/**
* CID of our implementation of nsIDownloadManagerUI.
*/
const kDownloadsUICid = Components.ID("{4d99321e-d156-455b-81f7-e7aa2308134f}");
/**
* Contract ID of the service implementing nsIDownloadManagerUI.
*/
const kDownloadsUIContractId = "@mozilla.org/download-manager-ui;1";
////////////////////////////////////////////////////////////////////////////////
//// DownloadsStartup
function DownloadsStartup() { }
DownloadsStartup.prototype = {
classID: Components.ID("{49507fe5-2cee-4824-b6a3-e999150ce9b8}"),
_xpcom_factory: XPCOMUtils.generateSingletonFactory(DownloadsStartup),
//////////////////////////////////////////////////////////////////////////////
//// nsISupports
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
//////////////////////////////////////////////////////////////////////////////
//// nsIObserver
observe: function DS_observe(aSubject, aTopic, aData)
{
switch (aTopic) {
case "app-startup":
kObservedTopics.forEach(
function (topic) Services.obs.addObserver(this, topic, true),
this);
// Override Toolkit's nsIDownloadManagerUI implementation with our own.
// This must be done at application startup and not in the manifest to
// ensure that our implementation overrides the original one.
Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
.registerFactory(kDownloadsUICid, "",
kDownloadsUIContractId, null);
break;
case "sessionstore-windows-restored":
case "sessionstore-browser-state-restored":
// Unless there is no saved session, there is a chance that we are
// starting up after a restart or a crash. We should check the disk
// database to see if there are completed downloads to recover and show
// in the panel, in addition to in-progress downloads.
if (gSessionStartup.sessionType != Ci.nsISessionStartup.NO_SESSION) {
this._recoverAllDownloads = true;
}
this._ensureDataLoaded();
break;
case "download-manager-initialized":
// Don't initialize the JavaScript data and user interface layer if we
// are initializing the Download Manager service during shutdown.
if (this._shuttingDown) {
break;
}
// Start receiving events for active and new downloads before we return
// from this observer function. We can't defer the execution of this
// step, to ensure that we don't lose events raised in the meantime.
DownloadsCommon.data.initializeDataLink(
aSubject.QueryInterface(Ci.nsIDownloadManager));
this._downloadsServiceInitialized = true;
// Since this notification is generated during the getService call and
// we need to get the Download Manager service ourselves, we must post
// the handler on the event queue to be executed later.
Services.tm.mainThread.dispatch(this._ensureDataLoaded.bind(this),
Ci.nsIThread.DISPATCH_NORMAL);
break;
case "download-manager-change-retention":
// When the panel interface is enabled, we use a different preference to
// determine whether downloads should be removed from view as soon as
// they are finished. We do this to allow proper migration to the new
// feature when using the same profile on multiple versions of the
// product (bug 697678).
if (!DownloadsCommon.useToolkitUI) {
let removeFinishedDownloads = Services.prefs.getBoolPref(
"browser.download.panel.removeFinishedDownloads");
aSubject.QueryInterface(Ci.nsISupportsPRInt32)
.data = removeFinishedDownloads ? 0 : 2;
}
break;
case "private-browsing-transition-complete":
// Ensure that persistent data is reloaded only when the database
// connection is available again.
this._ensureDataLoaded();
break;
case "browser-lastwindow-close-granted":
// When using the panel interface, downloads that are already completed
// should be removed when the last full browser window is closed. This
// event is invoked only if the application is not shutting down yet.
// If the Download Manager service is not initialized, we don't want to
// initialize it just to clean up completed downloads, because they can
// be present only in case there was a browser crash or restart.
if (this._downloadsServiceInitialized &&
!DownloadsCommon.useToolkitUI) {
Services.downloads.cleanUp();
}
break;
case "quit-application":
// When the application is shutting down, we must free all resources in
// addition to cleaning up completed downloads. If the Download Manager
// service is not initialized, we don't want to initialize it just to
// clean up completed downloads, because they can be present only in
// case there was a browser crash or restart.
this._shuttingDown = true;
if (!this._downloadsServiceInitialized) {
break;
}
DownloadsCommon.data.terminateDataLink();
// When using the panel interface, downloads that are already completed
// should be removed when quitting the application.
if (!DownloadsCommon.useToolkitUI && aData != "restart") {
this._cleanupOnShutdown = true;
}
break;
case "profile-change-teardown":
// If we need to clean up, we must do it synchronously after all the
// "quit-application" listeners are invoked, so that the Download
// Manager service has a chance to pause or cancel in-progress downloads
// before we remove completed downloads from the list. Note that, since
// "quit-application" was invoked, we've already exited Private Browsing
// Mode, thus we are always working on the disk database.
if (this._cleanupOnShutdown) {
Services.downloads.cleanUp();
}
break;
}
},
//////////////////////////////////////////////////////////////////////////////
//// Private
/**
* Indicates whether we should load all downloads from the previous session,
* including completed items as well as active downloads.
*/
_recoverAllDownloads: false,
/**
* Indicates whether the Download Manager service has been initialized. This
* flag is required because we want to avoid accessing the service immediately
* at browser startup. The service will start when the user first requests a
* download, or some time after browser startup.
*/
_downloadsServiceInitialized: false,
/**
* True while we are processing the "quit-application" event, and later.
*/
_shuttingDown: false,
/**
* True during shutdown if we need to remove completed downloads.
*/
_cleanupOnShutdown: false,
/**
* Ensures that persistent download data is reloaded at the appropriate time.
*/
_ensureDataLoaded: function DS_ensureDataLoaded()
{
if (!this._downloadsServiceInitialized ||
gPrivateBrowsingService.privateBrowsingEnabled) {
return;
}
// If the previous session has been already restored, then we ensure that
// all the downloads are loaded. Otherwise, we only ensure that the active
// downloads from the previous session are loaded.
DownloadsCommon.data.ensurePersistentDataLoaded(!this._recoverAllDownloads);
}
};
////////////////////////////////////////////////////////////////////////////////
//// Module
const NSGetFactory = XPCOMUtils.generateNSGetFactory([DownloadsStartup]);

View File

@ -0,0 +1,125 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* This component implements the nsIDownloadManagerUI interface and opens the
* downloads panel in the most recent browser window when requested.
*
* If a specific preference is set, this component transparently forwards all
* calls to the original implementation in Toolkit, that shows the window UI.
*/
"use strict";
////////////////////////////////////////////////////////////////////////////////
//// Globals
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
"resource:///modules/DownloadsCommon.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gBrowserGlue",
"@mozilla.org/browser/browserglue;1",
"nsIBrowserGlue");
////////////////////////////////////////////////////////////////////////////////
//// DownloadsUI
function DownloadsUI()
{
XPCOMUtils.defineLazyGetter(this, "_toolkitUI", function () {
// Create Toolkit's nsIDownloadManagerUI implementation.
return Components.classesByID["{7dfdf0d1-aff6-4a34-bad1-d0fe74601642}"]
.getService(Ci.nsIDownloadManagerUI);
});
}
DownloadsUI.prototype = {
classID: Components.ID("{4d99321e-d156-455b-81f7-e7aa2308134f}"),
_xpcom_factory: XPCOMUtils.generateSingletonFactory(DownloadsUI),
//////////////////////////////////////////////////////////////////////////////
//// nsISupports
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDownloadManagerUI]),
//////////////////////////////////////////////////////////////////////////////
//// nsIDownloadManagerUI
show: function DUI_show(aWindowContext, aID, aReason)
{
if (DownloadsCommon.useToolkitUI) {
this._toolkitUI.show(aWindowContext, aID, aReason);
return;
}
if (!aReason) {
aReason = Ci.nsIDownloadManagerUI.REASON_USER_INTERACTED;
}
if (aReason == Ci.nsIDownloadManagerUI.REASON_NEW_DOWNLOAD) {
// New download notifications are already handled by the panel service.
// We don't handle them here because we don't want them to depend on the
// "browser.download.manager.showWhenStarting" and
// "browser.download.manager.focusWhenStarting" preferences.
return;
}
// Show the panel in the most recent browser window, if present.
let browserWin = gBrowserGlue.getMostRecentBrowserWindow();
if (browserWin) {
browserWin.focus();
browserWin.DownloadsPanel.showPanel();
return;
}
// If no browser window is visible and the user requested to show the
// current downloads, try and open a new window. We'll open the panel when
// delayed loading is finished.
Services.obs.addObserver(function DUIO_observe(aSubject, aTopic, aData) {
Services.obs.removeObserver(DUIO_observe, aTopic);
aSubject.DownloadsPanel.showPanel();
}, "browser-delayed-startup-finished", false);
// We must really build an empty arguments list for the new window.
let windowFirstArg = Cc["@mozilla.org/supports-string;1"]
.createInstance(Ci.nsISupportsString);
let windowArgs = Cc["@mozilla.org/supports-array;1"]
.createInstance(Ci.nsISupportsArray);
windowArgs.AppendElement(windowFirstArg);
Services.ww.openWindow(null, "chrome://browser/content/browser.xul",
null, "chrome,dialog=no,all", windowArgs);
},
get visible()
{
if (DownloadsCommon.useToolkitUI) {
return this._toolkitUI.visible;
}
let browserWin = gBrowserGlue.getMostRecentBrowserWindow();
return browserWin ? browserWin.DownloadsPanel.isPanelShowing : false;
},
getAttention: function DUI_getAttention()
{
if (DownloadsCommon.useToolkitUI) {
this._toolkitUI.getAttention();
}
}
};
////////////////////////////////////////////////////////////////////////////////
//// Module
const NSGetFactory = XPCOMUtils.generateNSGetFactory([DownloadsUI]);

View File

@ -0,0 +1,22 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
EXTRA_COMPONENTS = \
BrowserDownloads.manifest \
DownloadsStartup.js \
DownloadsUI.js \
$(NULL)
EXTRA_JS_MODULES = \
DownloadsCommon.jsm \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,17 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = browser/components/downloads/test
include $(DEPTH)/config/autoconf.mk
XPCSHELL_TESTS = unit
DIRS = browser
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,20 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
DEPTH = ../../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = browser/components/downloads/test/browser
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_BROWSER_FILES = \
browser_basic_functionality.js \
head.js \
$(NULL)
libs:: $(_BROWSER_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)

View File

@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure the downloads panel can display items in the right order and
* contains the expected data.
*/
function gen_test()
{
// Display one of each download state.
const DownloadData = [
{ endTime: 1180493839859239, state: nsIDM.DOWNLOAD_NOTSTARTED },
{ endTime: 1180493839859238, state: nsIDM.DOWNLOAD_DOWNLOADING },
{ endTime: 1180493839859237, state: nsIDM.DOWNLOAD_PAUSED },
{ endTime: 1180493839859236, state: nsIDM.DOWNLOAD_SCANNING },
{ endTime: 1180493839859235, state: nsIDM.DOWNLOAD_QUEUED },
{ endTime: 1180493839859234, state: nsIDM.DOWNLOAD_FINISHED },
{ endTime: 1180493839859233, state: nsIDM.DOWNLOAD_FAILED },
{ endTime: 1180493839859232, state: nsIDM.DOWNLOAD_CANCELED },
{ endTime: 1180493839859231, state: nsIDM.DOWNLOAD_BLOCKED_PARENTAL },
{ endTime: 1180493839859230, state: nsIDM.DOWNLOAD_DIRTY },
{ endTime: 1180493839859229, state: nsIDM.DOWNLOAD_BLOCKED_POLICY },
];
try {
// Ensure that state is reset in case previous tests didn't finish.
for (let yy in gen_resetState()) yield;
// Populate the downloads database with the data required by this test.
for (let yy in gen_addDownloadRows(DownloadData)) yield;
// Open the user interface and wait for data to be fully loaded.
for (let yy in gen_openPanel()) yield;
// Test item data and count. This also tests the ordering of the display.
let richlistbox = document.getElementById("downloadsListBox");
is(richlistbox.children.length, DownloadData.length,
"There is the correct number of richlistitems");
for (let i = 0; i < richlistbox.children.length; i++) {
let element = richlistbox.children[i];
let dataItem = new DownloadsViewItemController(element).dataItem;
is(dataItem.target, DownloadData[i].name, "Download names match up");
is(dataItem.state, DownloadData[i].state, "Download states match up");
is(dataItem.file, DownloadData[i].target, "Download targets match up");
is(dataItem.uri, DownloadData[i].source, "Download sources match up");
}
} finally {
// Clean up when the test finishes.
for (let yy in gen_resetState()) yield;
}
}

View File

@ -0,0 +1,229 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Provides infrastructure for automated download components tests.
*/
////////////////////////////////////////////////////////////////////////////////
//// Globals
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
const nsIDM = Ci.nsIDownloadManager;
let gTestTargetFile = FileUtils.getFile("TmpD", ["dm-ui-test.file"]);
gTestTargetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
registerCleanupFunction(function () {
gTestTargetFile.remove(false);
});
/**
* This objects contains a property for each column in the downloads table.
*/
let gDownloadRowTemplate = {
name: "test-download.txt",
source: "http://www.example.com/test-download.txt",
target: NetUtil.newURI(gTestTargetFile).spec,
startTime: 1180493839859230,
endTime: 1180493839859234,
state: nsIDM.DOWNLOAD_FINISHED,
currBytes: 0,
maxBytes: -1,
preferredAction: 0,
autoResume: 0
};
////////////////////////////////////////////////////////////////////////////////
//// Infrastructure
// All test are run through the test runner.
function test()
{
testRunner.runTest(this.gen_test);
}
/**
* Runs a browser-chrome test defined through a generator function.
*
* This object is a singleton, initialized automatically when this script is
* included. Every browser-chrome test file includes a new copy of this object.
*/
var testRunner = {
_testIterator: null,
_lastEventResult: undefined,
_testRunning: false,
_eventRaised: false,
// --- Main test runner ---
/**
* Runs the test described by the provided generator function asynchronously.
*
* Calling yield in the generator will cause it to wait until continueTest is
* called. The parameter provided to continueTest will be the return value of
* the yield operator.
*
* @param aGenerator
* Test generator function. The function will be called with no
* arguments to retrieve its iterator.
*/
runTest: function TR_runTest(aGenerator) {
waitForExplicitFinish();
testRunner._testIterator = aGenerator();
testRunner.continueTest();
},
/**
* Continues the currently running test.
*
* @param aEventResult
* This will be the return value of the yield operator in the test.
*/
continueTest: function TR_continueTest(aEventResult) {
// Store the last event result, or set it to undefined.
testRunner._lastEventResult = aEventResult;
// Never reenter the main loop, but notify that the event has been raised.
if (testRunner._testRunning) {
testRunner._eventRaised = true;
return;
}
// Enter the main iteration loop.
testRunner._testRunning = true;
try {
do {
// Call the iterator, but don't leave the loop if the expected event is
// raised during the execution of the generator.
testRunner._eventRaised = false;
testRunner._testIterator.send(testRunner._lastEventResult);
} while (testRunner._eventRaised);
}
catch (e) {
// This block catches exceptions raised by the generator, including the
// normal StopIteration exception. Unexpected exceptions are reported as
// test failures.
if (!(e instanceof StopIteration))
ok(false, e);
// In any case, stop the tests in this file.
finish();
}
// Wait for the next event or finish.
testRunner._testRunning = false;
}
};
////////////////////////////////////////////////////////////////////////////////
//// Asynchronous generator-based support subroutines
//
// The following functions are all generators that can be used inside the main
// test generator to perform specific tasks asynchronously. To invoke these
// subroutines correctly, an iteration syntax should be used:
//
// for (let yy in gen_example("Parameter")) yield;
//
function gen_resetState()
{
let statement = Services.downloads.DBConnection.createAsyncStatement(
"DELETE FROM moz_downloads");
try {
statement.executeAsync({
handleResult: function(aResultSet) { },
handleError: function(aError)
{
Cu.reportError(aError);
},
handleCompletion: function(aReason)
{
testRunner.continueTest();
}
});
yield;
} finally {
statement.finalize();
}
// Ensure that the panel is closed and data is unloaded.
DownloadsCommon.data.clear();
DownloadsCommon.data._loadState = DownloadsCommon.data.kLoadNone;
// Wait for focus on the main window.
waitForFocus(testRunner.continueTest);
yield;
}
function gen_addDownloadRows(aDataRows)
{
let columnNames = Object.keys(gDownloadRowTemplate).join(", ");
let parameterNames = Object.keys(gDownloadRowTemplate)
.map(function(n) ":" + n)
.join(", ");
let statement = Services.downloads.DBConnection.createAsyncStatement(
"INSERT INTO moz_downloads (" + columnNames +
") VALUES(" + parameterNames + ")");
try {
// Execute the statement for each of the provided downloads in reverse.
for (let i = aDataRows.length - 1; i >= 0; i--) {
let dataRow = aDataRows[i];
// Populate insert parameters from the provided data.
for (let columnName in gDownloadRowTemplate) {
if (!(columnName in dataRow)) {
// Update the provided row object with data from the global template,
// for columns whose value is not provided explicitly.
dataRow[columnName] = gDownloadRowTemplate[columnName];
}
statement.params[columnName] = dataRow[columnName];
}
// Run the statement asynchronously and wait.
statement.executeAsync({
handleResult: function(aResultSet) { },
handleError: function(aError)
{
Cu.reportError(aError);
},
handleCompletion: function(aReason)
{
testRunner.continueTest();
}
});
yield;
// At each iteration, ensure that the end time in the global template is
// distinct, as this column is used to sort each download in its category.
gDownloadRowTemplate.endTime++;
}
} finally {
statement.finalize();
}
}
function gen_openPanel(aData)
{
// Hook to wait until the test data has been loaded.
let originalOnViewLoadCompleted = DownloadsPanel.onViewLoadCompleted;
DownloadsPanel.onViewLoadCompleted = function () {
DownloadsPanel.onViewLoadCompleted = originalOnViewLoadCompleted;
originalOnViewLoadCompleted.apply(this);
testRunner.continueTest();
};
// Start loading all the downloads from the database asynchronously.
DownloadsCommon.data.ensurePersistentDataLoaded(false);
// Wait for focus on the main window.
waitForFocus(testRunner.continueTest);
yield;
// Open the downloads panel, waiting until loading is completed.
DownloadsPanel.showPanel();
yield;
}

View File

@ -0,0 +1,18 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Provides infrastructure for automated download components tests.
*/
////////////////////////////////////////////////////////////////////////////////
//// Globals
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource:///modules/DownloadsCommon.jsm");

View File

@ -0,0 +1,37 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests for the functions located directly in the "DownloadsCommon" object.
*/
function testFormatTimeLeft(aSeconds, aExpectedValue, aExpectedUnitString)
{
let expected = "";
if (aExpectedValue) {
// Format the expected result based on the current language.
expected = DownloadsCommon.strings[aExpectedUnitString](aExpectedValue);
}
do_check_eq(DownloadsCommon.formatTimeLeft(aSeconds), expected);
}
function run_test()
{
testFormatTimeLeft( 0, "", "");
testFormatTimeLeft( 1, "1", "shortTimeLeftSeconds");
testFormatTimeLeft( 29, "29", "shortTimeLeftSeconds");
testFormatTimeLeft( 30, "30", "shortTimeLeftSeconds");
testFormatTimeLeft( 31, "1", "shortTimeLeftMinutes");
testFormatTimeLeft( 60, "1", "shortTimeLeftMinutes");
testFormatTimeLeft( 89, "1", "shortTimeLeftMinutes");
testFormatTimeLeft( 90, "2", "shortTimeLeftMinutes");
testFormatTimeLeft( 91, "2", "shortTimeLeftMinutes");
testFormatTimeLeft( 3600, "1", "shortTimeLeftHours");
testFormatTimeLeft( 86400, "24", "shortTimeLeftHours");
testFormatTimeLeft( 169200, "47", "shortTimeLeftHours");
testFormatTimeLeft( 172800, "2", "shortTimeLeftDays");
testFormatTimeLeft(8553600, "99", "shortTimeLeftDays");
testFormatTimeLeft(8640000, "99", "shortTimeLeftDays");
}

View File

@ -0,0 +1,5 @@
[DEFAULT]
head = head.js
tail =
[test_DownloadsCommon.js]

View File

@ -38,6 +38,10 @@
#
# ***** END LICENSE BLOCK *****
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
"resource:///modules/DownloadsCommon.jsm");
var gMainPane = {
_pane: null,
@ -55,12 +59,25 @@ var gMainPane = {
this.updateBrowserStartupLastSession();
this.startupPagePrefChanged();
this.setupDownloadsWindowOptions();
// Notify observers that the UI is now ready
Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService)
.notifyObservers(window, "main-pane-loaded", null);
},
setupDownloadsWindowOptions: function ()
{
var showWhenDownloading = document.getElementById("showWhenDownloading");
var closeWhenDone = document.getElementById("closeWhenDone");
// These radio-buttons should not be visible if we have enabled the Downloads Panel.
let shouldHide = !DownloadsCommon.useToolkitUI;
showWhenDownloading.hidden = shouldHide;
closeWhenDone.hidden = shouldHide;
},
// HOME PAGE
/*

View File

@ -308,6 +308,9 @@
@BINPATH@/components/nsBrowserGlue.js
@BINPATH@/components/nsSetDefaultBrowser.manifest
@BINPATH@/components/nsSetDefaultBrowser.js
@BINPATH@/components/BrowserDownloads.manifest
@BINPATH@/components/DownloadsStartup.js
@BINPATH@/components/DownloadsUI.js
@BINPATH@/components/BrowserPlaces.manifest
@BINPATH@/components/BrowserPageThumbs.manifest
@BINPATH@/components/nsPrivateBrowsingService.manifest

View File

@ -0,0 +1,41 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this file,
- You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!-- LOCALIZATION NOTE (indicator.tooltiptext):
Tooltip for the indicator that displays the progress of ongoing downloads.
-->
<!ENTITY indicator.tooltiptext "Downloads">
<!-- LOCALIZATION NOTE (downloads.title):
Used by screen readers to describe the Downloads Panel.
-->
<!ENTITY downloads.title "Downloads">
<!ENTITY cmd.pause.label "Pause">
<!ENTITY cmd.pause.accesskey "P">
<!ENTITY cmd.resume.label "Resume">
<!ENTITY cmd.resume.accesskey "R">
<!ENTITY cmd.cancel.label "Cancel">
<!ENTITY cmd.cancel.accesskey "C">
<!-- LOCALIZATION NOTE (cmd.show.label, cmd.show.accesskey, cmd.showMac.label,
cmd.showMac.accesskey):
The show and showMac commands are never shown together, thus they can share
the same access key (though the two access keys can also be different).
-->
<!ENTITY cmd.show.label "Open Containing Folder">
<!ENTITY cmd.show.accesskey "F">
<!ENTITY cmd.showMac.label "Show In Finder">
<!ENTITY cmd.showMac.accesskey "F">
<!ENTITY cmd.retry.label "Retry">
<!ENTITY cmd.goToDownloadPage.label "Go To Download Page">
<!ENTITY cmd.goToDownloadPage.accesskey "G">
<!ENTITY cmd.copyDownloadLink.label "Copy Download Link">
<!ENTITY cmd.copyDownloadLink.accesskey "L">
<!ENTITY cmd.removeFromList.label "Remove From List">
<!ENTITY cmd.removeFromList.accesskey "e">
<!ENTITY cmd.clearList.label "Clear List">
<!ENTITY cmd.clearList.accesskey "a">
<!ENTITY downloadshistory.label "Show All Downloads">
<!ENTITY downloadshistory.accesskey "S">

View File

@ -0,0 +1,72 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
# LOCALIZATION NOTE (stateStarting):
# Indicates that the download is starting.
stateStarting=Starting…
# LOCALIZATION NOTE (stateScanning):
# Indicates that an external program is scanning the download for viruses.
stateScanning=Scanning for viruses…
# LOCALIZATION NOTE (stateFailed):
# Indicates that the download failed because of an error.
stateFailed=Failed
# LOCALIZATION NOTE (statePaused):
# Indicates that the download was paused by the user.
statePaused=Paused
# LOCALIZATION NOTE (stateCanceled):
# Indicates that the download was canceled by the user.
stateCanceled=Canceled
# LOCALIZATION NOTE (stateBlockedParentalControls):
# Indicates that the download was blocked by the Parental Controls feature of
# Windows. "Parental Controls" should be consistently named and capitalized
# with the display of this feature in Windows. The following article can
# provide a reference for the translation of "Parental Controls" in various
# languages:
# http://windows.microsoft.com/en-US/windows-vista/Set-up-Parental-Controls
stateBlockedParentalControls=Blocked by Parental Controls
# LOCALIZATION NOTE (stateBlockedPolicy):
# Indicates that the download was blocked on Windows because of the "Launching
# applications and unsafe files" setting of the "security zone" associated with
# the target site. "Security zone" should be consistently named and capitalized
# with the display of this feature in Windows. The following article can
# provide a reference for the translation of "security zone" in various
# languages:
# http://support.microsoft.com/kb/174360
stateBlockedPolicy=Blocked by your security zone policy
# LOCALIZATION NOTE (stateDirty):
# Indicates that the download was blocked after scanning.
stateDirty=Blocked: May contain a virus or spyware
# LOCALIZATION NOTE (sizeWithUnits):
# %1$S is replaced with the size number, and %2$S with the measurement unit.
sizeWithUnits=%1$S %2$S
sizeUnknown=Unknown size
# LOCALIZATION NOTE (shortTimeLeftSeconds, shortTimeLeftMinutes,
# shortTimeLeftHours, shortTimeLeftDays):
# These values are displayed in the downloads indicator in the main browser
# window, where space is available for three characters maximum. %1$S is
# replaced with the time left for the given measurement unit. Even for days,
# the value is never longer than two digits.
shortTimeLeftSeconds=%1$Ss
shortTimeLeftMinutes=%1$Sm
shortTimeLeftHours=%1$Sh
shortTimeLeftDays=%1$Sd
# LOCALIZATION NOTE (statusSeparator, statusSeparatorBeforeNumber):
# These strings define templates for the separation of different elements in the
# status line of a download item. As a separator, by default we use the Unicode
# character U+2014 'EM DASH' (long dash). Examples of status lines include
# "Canceled - 222.net", "1.1 MB - website2.com", or "Paused - 1.1 MB". Note
# that we use a wider space after the separator when it is followed by a number,
# just to avoid visually confusing it with with a minus sign with some fonts.
# If you use a different separator, this might not be necessary. However, there
# is usually no need to change the separator or the order of the substitutions,
# even for right-to-left languages, unless the defaults are not suitable.
statusSeparator=%1$S \u2014 %2$S
statusSeparatorBeforeNumber=%1$S \u2014 %2$S
fileExecutableSecurityWarning="%S" is an executable file. Executable files may contain viruses or other malicious code that could harm your computer. Use caution when opening this file. Are you sure you want to launch "%S"?
fileExecutableSecurityWarningTitle=Open Executable File?
fileExecutableSecurityWarningDontAsk=Don't ask me this again

View File

@ -50,6 +50,8 @@
locale/browser/tabbrowser.properties (%chrome/browser/tabbrowser.properties)
locale/browser/tabview.properties (%chrome/browser/tabview.properties)
locale/browser/taskbar.properties (%chrome/browser/taskbar.properties)
locale/browser/downloads/downloads.dtd (%chrome/browser/downloads/downloads.dtd)
locale/browser/downloads/downloads.properties (%chrome/browser/downloads/downloads.properties)
locale/browser/places/places.dtd (%chrome/browser/places/places.dtd)
locale/browser/places/places.properties (%chrome/browser/places/places.properties)
locale/browser/places/editBookmarkOverlay.dtd (%chrome/browser/places/editBookmarkOverlay.dtd)

View File

@ -48,6 +48,8 @@ browser/components/about/Makefile
browser/components/build/Makefile
browser/components/certerror/Makefile
browser/components/dirprovider/Makefile
browser/components/downloads/Makefile
browser/components/downloads/src/Makefile
browser/components/feeds/Makefile
browser/components/feeds/public/Makefile
browser/components/feeds/src/Makefile
@ -131,6 +133,8 @@ if [ "$ENABLE_TESTS" ]; then
browser/base/content/test/newtab/Makefile
browser/components/certerror/test/Makefile
browser/components/dirprovider/tests/Makefile
browser/components/downloads/test/Makefile
browser/components/downloads/test/browser/Makefile
browser/components/preferences/tests/Makefile
browser/components/search/test/Makefile
browser/components/sessionstore/test/Makefile

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1,279 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/*** Panel and outer controls ***/
#downloadsPanel > .panel-arrowcontainer > .panel-arrowcontent {
padding: 0;
}
#downloadsListBox {
width: 60ch;
background: transparent;
padding: 4px;
color: inherit;
}
#downloadsPanel:not([hasdownloads]) > #downloadsListBox {
display: none;
}
#downloadsHistory {
background: inherit;
color: -moz-nativehyperlinktext;
cursor: pointer;
}
#downloadsPanel[hasdownloads] > #downloadsHistory {
border-top: 1px solid ThreeDShadow;
background-image: -moz-linear-gradient(hsla(0,0%,0%,.15), hsla(0,0%,0%,.08) 6px);
}
#downloadsHistory > .button-box {
margin: 1em;
}
/*** List items ***/
richlistitem[type="download"] {
height: 6em;
margin: 0;
border-top: 1px solid hsla(0,0%,100%,.2);
border-bottom: 1px solid hsla(0,0%,0%,.15);
background: transparent;
padding: 0;
color: inherit;
}
richlistitem[type="download"]:first-child {
border-top: 1px solid transparent;
}
richlistitem[type="download"]:last-child {
border-bottom: 1px solid transparent;
}
#downloadsListBox:-moz-focusring > richlistitem[type="download"][selected] {
outline: 1px #999 dotted;
outline-offset: -1px;
-moz-outline-radius: 3px;
}
.downloadInfo {
padding: 8px;
-moz-padding-end: 0;
}
.downloadTypeIcon {
-moz-margin-end: 8px;
/* Prevent flickering when changing states. */
min-height: 32px;
min-width: 32px;
}
.blockedIcon {
list-style-image: url("chrome://global/skin/icons/Error.png");
}
.downloadTarget {
margin-bottom: 7px;
cursor: inherit;
}
.downloadDetails {
margin-top: 1px;
opacity: 0.6;
font-size: 90%;
cursor: inherit;
}
.downloadButton {
-moz-appearance: none;
min-width: 0;
min-height: 0;
margin: 6px;
border: none;
background: transparent;
padding: 5px;
list-style-image: url("chrome://browser/skin/downloads/buttons.png");
}
.downloadButton > .button-box {
padding: 0;
}
/*** Highlighted list items ***/
richlistitem[type="download"][state="1"] > .downloadInfo {
border-top: 1px solid transparent;
border-bottom: 1px solid transparent;
-moz-padding-end: 8px;
}
richlistitem[type="download"][state="1"] > .downloadInfo:hover {
border-radius: 3px;
border-top: 1px solid hsla(0,0%,100%,.3);
border-bottom: 1px solid hsla(0,0%,0%,.2);
background-color: Highlight;
background-image: -moz-linear-gradient(hsla(0,0%,100%,.1), hsla(0,0%,100%,0));
color: HighlightText;
cursor: pointer;
}
/*** Button icons ***/
.downloadButton.downloadCancel {
-moz-image-region: rect(0px, 14px, 14px, 0px);
}
.downloadButton.downloadCancel:hover {
-moz-image-region: rect(0px, 28px, 14px, 14px);
}
.downloadButton.downloadCancel:active {
-moz-image-region: rect(0px, 42px, 14px, 28px);
}
.downloadButton.downloadShow {
-moz-image-region: rect(14px, 14px, 28px, 0px);
}
.downloadButton.downloadShow:hover {
-moz-image-region: rect(14px, 28px, 28px, 14px);
}
.downloadButton.downloadShow:active {
-moz-image-region: rect(14px, 42px, 28px, 28px);
}
.downloadButton.downloadRetry {
-moz-image-region: rect(28px, 14px, 42px, 0px);
}
.downloadButton.downloadRetry:hover {
-moz-image-region: rect(28px, 28px, 42px, 14px);
}
.downloadButton.downloadRetry:active {
-moz-image-region: rect(28px, 42px, 42px, 28px);
}
/*** Status and progress indicator ***/
#downloads-indicator {
width: 35px;
}
#downloads-indicator-anchor {
min-width: 18px;
min-height: 18px;
/* Makes the outermost stack element positioned, so that its contents are
rendered over the main browser window in the Z order. This is required by
the animated event notification. */
position: relative;
}
/*** Main indicator icon ***/
#downloads-indicator-icon {
background: -moz-image-rect(url("chrome://browser/skin/Toolbar-small.png"),
0, 16, 16, 0) center no-repeat;
}
#downloads-indicator-icon:-moz-lwtheme-brighttext {
background: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"),
0, 16, 16, 0) center no-repeat;
}
#downloads-indicator[attention] > #downloads-indicator-anchor > #downloads-indicator-icon {
background: -moz-image-rect(url("chrome://browser/skin/downloads/download-glow.png"),
16, 32, 32, 16) center no-repeat;
}
#downloads-indicator:not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
background: -moz-image-rect(url("chrome://browser/skin/Toolbar-small.png"),
0, 16, 16, 0) center no-repeat;
background-size: 12px;
}
#downloads-indicator:not([counter])[attention] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
background-image: -moz-image-rect(url("chrome://browser/skin/downloads/download-glow.png"),
16, 32, 32, 16);
}
/*** Event notification ***/
#downloads-indicator-notification {
opacity: 0;
background: url("chrome://browser/skin/downloads/download-notification.png")
center no-repeat;
background-size: 16px;
}
@-moz-keyframes downloadsIndicatorNotificationRight {
from { opacity: 0; -moz-transform: translate(-128px, 128px) scale(8); }
20% { opacity: .85; -moz-animation-timing-function: ease-out; }
to { opacity: 0; -moz-transform: translate(0) scale(1); }
}
@-moz-keyframes downloadsIndicatorNotificationLeft {
from { opacity: 0; -moz-transform: translate(128px, 128px) scale(8); }
20% { opacity: .85; -moz-animation-timing-function: ease-out; }
to { opacity: 0; -moz-transform: translate(0) scale(1); }
}
#downloads-indicator[notification] > #downloads-indicator-anchor > #downloads-indicator-notification {
-moz-animation-name: downloadsIndicatorNotificationRight;
-moz-animation-duration: 1s;
}
#downloads-indicator[notification]:-moz-locale-dir(rtl) > #downloads-indicator-anchor > #downloads-indicator-notification {
-moz-animation-name: downloadsIndicatorNotificationLeft;
}
/*** Progress bar and text ***/
#downloads-indicator-counter {
height: 12px;
margin: 0;
color: hsl(0,0%,30%);
text-shadow: 0 1px 0 hsla(0,0%,100%,.5);
font-size: 10px;
line-height: 10px;
text-align: center;
}
#downloads-indicator-progress {
width: 24px;
height: 4px;
min-width: 0;
min-height: 0;
margin-top: 1px;
margin-bottom: 2px;
border-radius: 2px;
box-shadow: 0 1px 0 hsla(0,0%,100%,.4);
}
#downloads-indicator-progress > .progress-bar {
-moz-appearance: none;
min-width: 0;
min-height: 0;
background-image: -moz-linear-gradient(#41a0ff, #2090ff);
border: 1px solid;
border-color: hsla(0,0%,0%,.6) hsla(0,0%,0%,.2) hsla(0,0%,0%,.2);
border-radius: 2px 0 0 2px;
}
#downloads-indicator-progress > .progress-remainder {
-moz-appearance: none;
min-width: 0;
min-height: 0;
background-image: -moz-linear-gradient(#9a9a9a, #a1a1a1);
border: 1px solid;
border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.3) hsla(0,0%,0%,.2);
-moz-border-start: none;
border-radius: 0 2px 2px 0;
}
#downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-bar {
background-image: -moz-linear-gradient(#a0a000, #909000);
}
#downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder {
background-image: -moz-linear-gradient(#9a9a00, #a1a100);
}

View File

@ -35,6 +35,10 @@ browser.jar:
skin/classic/browser/Toolbar.png
skin/classic/browser/Toolbar-small.png
skin/classic/browser/urlbar-arrow.png
skin/classic/browser/downloads/buttons.png (downloads/buttons.png)
skin/classic/browser/downloads/download-glow.png (downloads/download-glow.png)
skin/classic/browser/downloads/download-notification.png (downloads/download-notification.png)
skin/classic/browser/downloads/downloads.css (downloads/downloads.css)
skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png)
skin/classic/browser/feeds/feedIcon16.png (feeds/feedIcon16.png)
skin/classic/browser/feeds/videoFeedIcon.png (feeds/feedIcon.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1,300 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/*** Panel and outer controls ***/
#downloadsPanel > .panel-arrowcontainer > .panel-arrowcontent {
padding: 0;
}
#downloadsListBox {
width: 60ch;
background: transparent;
padding: 4px;
color: inherit;
}
#downloadsPanel:not([hasdownloads]) > #downloadsListBox {
display: none;
}
#downloadsHistory {
background: inherit;
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
color: hsl(210,100%,75%);
cursor: pointer;
}
#downloadsPanel:not([hasdownloads]) > #downloadsHistory {
border-top-left-radius: 6px;
border-top-right-radius: 6px;
}
#downloadsPanel[hasdownloads] > #downloadsHistory {
border-top: 1px solid hsla(0,0%,100%,.1);
background-color: hsla(0,0%,7%,.3);
box-shadow: 0 1px 1px hsla(0,0%,0%,.25) inset;
}
#downloadsHistory > .button-box {
margin: 1em;
}
#downloadsHistory:-moz-focusring > .button-box {
border-top-left-radius: 6px;
border-top-right-radius: 6px;
}
#downloadsPanel:not([hasdownloads]) > #downloadsHistory:-moz-focusring > .button-box {
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
}
/*** List items ***/
richlistitem[type="download"] {
height: 7em;
margin: 0;
border-top: 1px solid hsla(0,0%,100%,.07);
border-bottom: 1px solid hsla(0,0%,0%,.2);
background: transparent;
padding: 0;
color: inherit;
}
richlistitem[type="download"]:first-child {
border-top: 1px solid transparent;
}
richlistitem[type="download"]:last-child {
border-bottom: 1px solid transparent;
}
#downloadsListBox:-moz-focusring > richlistitem[type="download"][selected] {
outline: 1px #999 dotted;
outline-offset: -1px;
-moz-outline-radius: 3px;
}
.downloadInfo {
color: white;
padding: 8px;
-moz-padding-end: 0;
}
.downloadTypeIcon {
-moz-margin-end: 8px;
/* Prevent flickering when changing states. */
min-height: 32px;
min-width: 32px;
}
.blockedIcon {
list-style-image: url("chrome://global/skin/icons/Error.png");
}
.downloadTarget {
margin-bottom: 6px;
cursor: inherit;
}
.downloadDetails {
opacity: 0.7;
font-size: 95%;
cursor: inherit;
}
.downloadButton {
-moz-appearance: none;
min-width: 0;
min-height: 0;
margin: 6px;
border: none;
background: transparent;
padding: 5px;
list-style-image: url("chrome://browser/skin/downloads/buttons.png");
}
.downloadButton > .button-box {
padding: 0;
}
/*** Highlighted list items ***/
richlistitem[type="download"][state="1"] .downloadInfo {
border-top: 1px solid transparent;
border-bottom: 1px solid transparent;
-moz-padding-end: 8px;
}
richlistitem[type="download"][state="1"] .downloadInfo:hover {
border-radius: 3px;
border-top: 1px solid hsla(0,0%,100%,.2);
border-bottom: 1px solid hsla(0,0%,0%,.4);
background-color: Highlight;
background-image: -moz-linear-gradient(hsl(210,100%,50%), hsl(210,96%,41%));
color: HighlightText;
cursor: pointer;
}
/*** Button icons ***/
.downloadButton.downloadCancel {
-moz-image-region: rect(0px, 14px, 14px, 0px);
}
.downloadButton.downloadCancel:hover {
-moz-image-region: rect(0px, 28px, 14px, 14px);
}
.downloadButton.downloadCancel:active {
-moz-image-region: rect(0px, 42px, 14px, 28px);
}
.downloadButton.downloadShow {
-moz-image-region: rect(14px, 14px, 28px, 0px);
}
.downloadButton.downloadShow:hover {
-moz-image-region: rect(14px, 28px, 28px, 14px);
}
.downloadButton.downloadShow:active {
-moz-image-region: rect(14px, 42px, 28px, 28px);
}
.downloadButton.downloadRetry {
-moz-image-region: rect(28px, 14px, 42px, 0px);
}
.downloadButton.downloadRetry:hover {
-moz-image-region: rect(28px, 28px, 42px, 14px);
}
.downloadButton.downloadRetry:active {
-moz-image-region: rect(28px, 42px, 42px, 28px);
}
/*** Status and progress indicator ***/
#downloads-indicator {
width: 35px;
}
#downloads-indicator-anchor {
min-width: 20px;
min-height: 20px;
/* Makes the outermost stack element positioned, so that its contents are
rendered over the main browser window in the Z order. This is required by
the animated event notification. */
position: relative;
}
/*** Main indicator icon ***/
#downloads-indicator-icon {
background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"),
0, 140, 20, 120) center no-repeat;
}
#downloads-indicator-icon:-moz-lwtheme-brighttext {
background: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"),
0, 140, 20, 120) center no-repeat;
}
#downloads-indicator[attention]
#downloads-indicator-icon {
background: -moz-image-rect(url("chrome://browser/skin/downloads/download-glow.png"),
14, 34, 34, 14) center no-repeat;
}
#downloads-indicator:not([counter])
#downloads-indicator-counter {
background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"),
0, 140, 20, 120) center no-repeat;
background-size: 12px;
}
#downloads-indicator:not([counter])[attention]
#downloads-indicator-counter {
background-image: -moz-image-rect(url("chrome://browser/skin/downloads/download-glow.png"),
14, 34, 34, 14);
}
/*** Event notification ***/
#downloads-indicator-notification {
opacity: 0;
background: url("chrome://browser/skin/downloads/download-notification.png")
center no-repeat;
background-size: 16px;
}
@-moz-keyframes downloadsIndicatorNotificationRight {
from { opacity: 0; -moz-transform: translate(-128px, 128px) scale(8); }
20% { opacity: .85; -moz-animation-timing-function: ease-out; }
to { opacity: 0; -moz-transform: translate(0) scale(1); }
}
@-moz-keyframes downloadsIndicatorNotificationLeft {
from { opacity: 0; -moz-transform: translate(128px, 128px) scale(8); }
20% { opacity: .85; -moz-animation-timing-function: ease-out; }
to { opacity: 0; -moz-transform: translate(0) scale(1); }
}
#downloads-indicator[notification] > #downloads-indicator-anchor > #downloads-indicator-notification {
-moz-animation-name: downloadsIndicatorNotificationRight;
-moz-animation-duration: 1s;
}
#downloads-indicator[notification]:-moz-locale-dir(rtl) > #downloads-indicator-anchor > #downloads-indicator-notification {
-moz-animation-name: downloadsIndicatorNotificationLeft;
}
/*** Progress bar and text ***/
#downloads-indicator-counter {
height: 12px;
margin: 0;
color: hsl(0,0%,30%);
text-shadow: 0 1px 0 hsla(0,0%,100%,.5);
font-size: 10px;
line-height: 10px;
text-align: center;
}
#downloads-indicator-progress {
width: 24px;
height: 4px;
min-width: 0;
min-height: 0;
margin-top: 1px;
margin-bottom: 2px;
border-radius: 2px;
box-shadow: 0 1px 0 hsla(0,0%,100%,.4);
}
#downloads-indicator-progress > .progress-bar {
-moz-appearance: none;
min-width: 0;
min-height: 0;
background-image: -moz-linear-gradient(#41a0ff, #2090ff);
border: 1px solid;
border-color: hsla(0,0%,0%,.6) hsla(0,0%,0%,.2) hsla(0,0%,0%,.2);
border-radius: 2px 0 0 2px;
}
#downloads-indicator-progress > .progress-remainder {
-moz-appearance: none;
min-width: 0;
min-height: 0;
background-image: -moz-linear-gradient(#9a9a9a, #a1a1a1);
border: 1px solid;
border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.3) hsla(0,0%,0%,.2);
-moz-border-start: none;
border-radius: 0 2px 2px 0;
}
#downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-bar {
background-image: -moz-linear-gradient(#a0a000, #909000);
}
#downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder {
background-image: -moz-linear-gradient(#9a9a00, #a1a100);
}

View File

@ -45,6 +45,10 @@ browser.jar:
skin/classic/browser/urlbar-history-dropmarker.png
skin/classic/browser/urlbar-arrow.png
skin/classic/browser/urlbar-popup-blocked.png
skin/classic/browser/downloads/buttons.png (downloads/buttons.png)
skin/classic/browser/downloads/download-glow.png (downloads/download-glow.png)
skin/classic/browser/downloads/download-notification.png (downloads/download-notification.png)
skin/classic/browser/downloads/downloads.css (downloads/downloads.css)
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
skin/classic/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css)
skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1,49 @@
%define WINSTRIPE_AERO
%include downloads.css
%undef WINSTRIPE_AERO
#downloadsPanel > .panel-arrowcontainer > .panel-arrowcontent > .panel-inner-arrowcontent {
padding: 0;
}
@media (-moz-windows-default-theme) {
#downloadsPanel[hasdownloads] > #downloadsHistory {
background-color: #f1f5fb;
}
richlistitem[type="download"] {
border: 1px solid transparent;
border-bottom: 1px solid hsl(213,40%,90%);
}
richlistitem[type="download"][state="1"] > .downloadInfo {
border: 1px solid transparent;
-moz-padding-end: 8px;
}
richlistitem[type="download"][state="1"] > .downloadInfo:hover {
border: 1px solid hsl(213,45%,65%);
box-shadow: 0 0 0 1px hsla(0,0%,100%,.5) inset,
0 1px 0 hsla(0,0%,100%,.3) inset;
background-image: -moz-linear-gradient(hsl(212,86%,92%), hsl(212,91%,86%));
color: black;
}
}
@media (-moz-windows-compositor) {
#toolbar-menubar #downloads-indicator-icon:not(:-moz-lwtheme),
#TabsToolbar[tabsontop=true] #downloads-indicator-icon:not(:-moz-lwtheme),
#navigator-toolbox[tabsontop=false] > #nav-bar #downloads-indicator-icon:not(:-moz-lwtheme),
#nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child #downloads-indicator-icon:not(:-moz-lwtheme) {
list-style-image: url("chrome://browser/skin/Toolbar-inverted.png");
}
#toolbar-menubar #downloads-indicator-counter:not(:-moz-lwtheme),
#TabsToolbar[tabsontop=true] #downloads-indicator-counter:not(:-moz-lwtheme),
#navigator-toolbox[tabsontop=false] > #nav-bar #downloads-indicator-counter:not(:-moz-lwtheme),
#nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child #downloads-indicator-counter:not(:-moz-lwtheme) {
color: white;
text-shadow: 0 0 1px rgba(0,0,0,.7),
0 1px 1.5px rgba(0,0,0,.5);
}
}

View File

@ -0,0 +1,310 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/*** Panel and outer controls ***/
%ifndef WINSTRIPE_AERO
#downloadsHistory,
#downloadsHistory:-moz-focusring > .button-box {
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
}
#downloadsPanel:not([hasdownloads]) > #downloadsHistory,
#downloadsPanel:not([hasdownloads]) > #downloadsHistory:-moz-focusring > .button-box {
border-top-left-radius: 6px;
border-top-right-radius: 6px;
}
#downloadsPanel > .panel-arrowcontainer > .panel-arrowcontent {
/* Avoid that the arrow overlaps the selection on first item */
padding-top: 5px;
}
%endif
#downloadsPanel > .panel-arrowcontainer > .panel-arrowcontent {
padding: 0;
}
#downloadsListBox {
width: 60ch;
background-color: transparent;
padding: 4px;
color: inherit;
}
#downloadsHistory {
background: inherit;
color: -moz-nativehyperlinktext;
cursor: pointer;
}
#downloadsHistory > .button-box {
margin: 1em;
}
@media (-moz-windows-default-theme) {
#downloadsPanel[hasdownloads] > #downloadsHistory {
background-color: hsla(216,45%,88%,.98);
box-shadow: 0px 1px 2px rgb(204,214,234) inset;
}
}
/*** List items ***/
richlistitem[type="download"] {
height: 7em;
margin: 0;
border-top: 1px solid hsla(0,0%,100%,.3);
border-bottom: 1px solid hsla(220,18%,51%,.25);
background: transparent;
padding: 0;
color: inherit;
}
richlistitem[type="download"]:first-child {
border-top: 1px solid transparent;
}
@media (-moz-windows-default-theme) {
richlistitem[type="download"]:last-child {
border-bottom: 1px solid transparent;
}
}
#downloadsListBox:-moz-focusring > richlistitem[type="download"][selected] {
outline: 1px #999 dotted;
outline-offset: -1px;
-moz-outline-radius: 3px;
}
.downloadInfo {
padding: 8px;
-moz-padding-end: 0;
}
.downloadTypeIcon {
-moz-margin-end: 8px;
/* Prevent flickering when changing states. */
min-height: 32px;
min-width: 32px;
}
.blockedIcon {
list-style-image: url("chrome://global/skin/icons/Error.png");
}
.downloadTarget {
margin-bottom: 6px;
cursor: inherit;
}
.downloadDetails {
opacity: 0.6;
font-size: 90%;
cursor: inherit;
}
.downloadButton {
-moz-appearance: none;
min-width: 0;
min-height: 0;
margin: 6px;
border: none;
background: transparent;
padding: 5px;
list-style-image: url("chrome://browser/skin/downloads/buttons.png");
}
.downloadButton > .button-box {
padding: 0;
}
/*** Highlighted list items ***/
%ifdef WINSTRIPE_AERO
@media not all and (-moz-windows-default-theme) {
%endif
richlistitem[type="download"][state="1"] > .downloadInfo {
border-top: 1px solid transparent;
border-bottom: 1px solid transparent;
-moz-padding-end: 8px;
}
%ifdef WINSTRIPE_AERO
}
%endif
richlistitem[type="download"][state="1"] > .downloadInfo:hover {
border-radius: 3px;
border-top: 1px solid hsla(0,0%,100%,.2);
border-bottom: 1px solid hsla(0,0%,0%,.2);
background-color: Highlight;
color: HighlightText;
cursor: pointer;
}
/*** Button icons ***/
.downloadButton.downloadCancel {
-moz-image-region: rect(0px, 14px, 14px, 0px);
}
.downloadButton.downloadCancel:hover {
-moz-image-region: rect(0px, 28px, 14px, 14px);
}
.downloadButton.downloadCancel:active {
-moz-image-region: rect(0px, 42px, 14px, 28px);
}
.downloadButton.downloadShow {
-moz-image-region: rect(14px, 14px, 28px, 0px);
}
.downloadButton.downloadShow:hover {
-moz-image-region: rect(14px, 28px, 28px, 14px);
}
.downloadButton.downloadShow:active {
-moz-image-region: rect(14px, 42px, 28px, 28px);
}
.downloadButton.downloadRetry {
-moz-image-region: rect(28px, 14px, 42px, 0px);
}
.downloadButton.downloadRetry:hover {
-moz-image-region: rect(28px, 28px, 42px, 14px);
}
.downloadButton.downloadRetry:active {
-moz-image-region: rect(28px, 42px, 42px, 28px);
}
/*** Status and progress indicator ***/
#downloads-indicator {
width: 35px;
}
#downloads-indicator-anchor {
min-width: 18px;
min-height: 18px;
/* Makes the outermost stack element positioned, so that its contents are
rendered over the main browser window in the Z order. This is required by
the animated event notification. */
position: relative;
}
/*** Main indicator icon ***/
#downloads-indicator-icon {
background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"),
0, 108, 18, 90) center no-repeat;
}
#downloads-indicator-icon:-moz-lwtheme-brighttext {
background: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"),
0, 108, 18, 90) center no-repeat;
}
#downloads-indicator[attention] > #downloads-indicator-anchor > #downloads-indicator-icon {
background: -moz-image-rect(url("chrome://browser/skin/downloads/download-glow.png"),
15, 33, 33, 15) center no-repeat;
}
#downloads-indicator:not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"),
0, 108, 18, 90) center no-repeat;
background-size: 12px;
}
#downloads-indicator:not([counter])[attention] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
background-image: -moz-image-rect(url("chrome://browser/skin/downloads/download-glow.png"),
16, 32, 32, 16);
}
/*** Event notification ***/
#downloads-indicator-notification {
opacity: 0;
background: url("chrome://browser/skin/downloads/download-notification.png")
center no-repeat;
background-size: 16px;
}
@-moz-keyframes downloadsIndicatorNotificationRight {
from { opacity: 0; -moz-transform: translate(-128px, 128px) scale(8); }
20% { opacity: .85; -moz-animation-timing-function: ease-out; }
to { opacity: 0; -moz-transform: translate(0) scale(1); }
}
@-moz-keyframes downloadsIndicatorNotificationLeft {
from { opacity: 0; -moz-transform: translate(128px, 128px) scale(8); }
20% { opacity: .85; -moz-animation-timing-function: ease-out; }
to { opacity: 0; -moz-transform: translate(0) scale(1); }
}
#downloads-indicator[notification] > #downloads-indicator-anchor > #downloads-indicator-notification {
-moz-animation-name: downloadsIndicatorNotificationRight;
-moz-animation-duration: 1s;
}
#downloads-indicator[notification]:-moz-locale-dir(rtl) > #downloads-indicator-anchor > #downloads-indicator-notification {
-moz-animation-name: downloadsIndicatorNotificationLeft;
}
/*** Progress bar and text ***/
#downloads-indicator-counter {
height: 12px;
margin: 0;
color: hsl(0,0%,30%);
text-shadow: hsla(0,0%,100%,.5) 0 1px;
font-size: 10px;
line-height: 10px;
text-align: center;
}
#downloads-indicator-counter:-moz-lwtheme-brighttext {
color: white;
text-shadow: 0 0 1px rgba(0,0,0,.7),
0 1px 1.5px rgba(0,0,0,.5);
}
#downloads-indicator-progress {
width: 24px;
height: 4px;
min-width: 0;
min-height: 0;
margin-top: 1px;
margin-bottom: 2px;
border-radius: 2px;
box-shadow: 0 1px 0 hsla(0,0%,100%,.4);
}
#downloads-indicator-progress > .progress-bar {
-moz-appearance: none;
min-width: 0;
min-height: 0;
background-image: -moz-linear-gradient(#92DDA0, #6FC483 49%, #5EB272 51%, #80CE91);
border: 1px solid;
border-color: hsla(0,0%,0%,.6) hsla(0,0%,0%,.2) hsla(0,0%,0%,.2);
border-radius: 2px 0 0 2px;
}
#downloads-indicator-progress > .progress-remainder {
-moz-appearance: none;
min-width: 0;
min-height: 0;
background-image: -moz-linear-gradient(#9a9a9a, #a1a1a1);
border: 1px solid;
border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.3) hsla(0,0%,0%,.2);
-moz-border-start: none;
border-radius: 0 2px 2px 0;
}
#downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-bar {
background-image: -moz-linear-gradient(#DDDD00, #C4C400 49%, #B2B200 51%, #CECE00);
}
#downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder {
background-image: -moz-linear-gradient(#9a9a00, #a1a100);
}

View File

@ -50,6 +50,10 @@ browser.jar:
skin/classic/browser/urlbar-arrow.png
skin/classic/browser/urlbar-popup-blocked.png
skin/classic/browser/urlbar-history-dropmarker.png
skin/classic/browser/downloads/buttons.png (downloads/buttons.png)
skin/classic/browser/downloads/download-glow.png (downloads/download-glow.png)
skin/classic/browser/downloads/download-notification.png (downloads/download-notification.png)
* skin/classic/browser/downloads/downloads.css (downloads/downloads.css)
skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png)
skin/classic/browser/feeds/feedIcon16.png (feeds/feedIcon16.png)
skin/classic/browser/feeds/audioFeedIcon.png (feeds/feedIcon.png)
@ -224,6 +228,10 @@ browser.jar:
skin/classic/aero/browser/urlbar-arrow.png
skin/classic/aero/browser/urlbar-popup-blocked.png
skin/classic/aero/browser/urlbar-history-dropmarker.png
skin/classic/aero/browser/downloads/buttons.png (downloads/buttons-aero.png)
skin/classic/aero/browser/downloads/download-glow.png (downloads/download-glow-aero.png)
skin/classic/aero/browser/downloads/download-notification.png (downloads/download-notification.png)
* skin/classic/aero/browser/downloads/downloads.css (downloads/downloads-aero.css)
skin/classic/aero/browser/feeds/feedIcon.png (feeds/feedIcon-aero.png)
skin/classic/aero/browser/feeds/feedIcon16.png (feeds/feedIcon16-aero.png)
skin/classic/aero/browser/feeds/audioFeedIcon.png (feeds/feedIcon-aero.png)

View File

@ -74,6 +74,7 @@ skip-if = os == "android"
# Bug 676978: tests hang on Android
skip-if = os == "android"
[include:browser/components/dirprovider/tests/unit/xpcshell.ini]
[include:browser/components/downloads/test/unit/xpcshell.ini]
[include:browser/components/feeds/test/unit/xpcshell.ini]
[include:browser/components/migration/tests/unit/xpcshell.ini]
[include:browser/components/places/tests/unit/xpcshell.ini]

View File

@ -326,7 +326,7 @@ nsDownloadManager::CloseDB()
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = mUpdateDownloadStatement->Finalize();
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = mDBConn->Close();
rv = mDBConn->AsyncClose(nsnull);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
@ -899,6 +899,11 @@ nsDownloadManager::Init()
nsCOMPtr<nsINavHistoryService> history =
do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID);
(void)mObserverService->NotifyObservers(
static_cast<nsIDownloadManager *>(this),
"download-manager-initialized",
nsnull);
// The following AddObserver calls must be the last lines in this function,
// because otherwise, this function may fail (and thus, this object would be not
// completely initialized), but the observerservice would still keep a reference
@ -933,6 +938,19 @@ nsDownloadManager::GetRetentionBehavior()
rv = pref->GetIntPref(PREF_BDM_RETENTION, &val);
NS_ENSURE_SUCCESS(rv, 0);
// Allow the Downloads Panel to change the retention behavior. We do this to
// allow proper migration to the new feature when using the same profile on
// multiple versions of the product (bug 697678). Implementation note: in
// order to allow observers to change the retention value, we have to pass an
// object in the aSubject parameter, we cannot use aData for that.
nsCOMPtr<nsISupportsPRInt32> retentionBehavior =
do_CreateInstance(NS_SUPPORTS_PRINT32_CONTRACTID);
retentionBehavior->SetData(val);
(void)mObserverService->NotifyObservers(retentionBehavior,
"download-manager-change-retention",
nsnull);
retentionBehavior->GetData(&val);
return val;
}
@ -1841,6 +1859,12 @@ nsDownloadManager::SwitchDatabaseTypeTo(enum nsDownloadManager::DatabaseType aTy
rv = RestoreDatabaseState();
NS_ENSURE_SUCCESS(rv, rv);
// Notify that the database type changed before resuming current downloads
(void)mObserverService->NotifyObservers(
static_cast<nsIDownloadManager *>(this),
"download-manager-database-type-changed",
nsnull);
rv = RestoreActiveDownloads();
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to restore all active downloads");

View File

@ -106,6 +106,13 @@ function test()
if (win)
win.close();
// Ensure that the download manager callbacks and nsIDownloadManagerUI always
// use the window UI instead of the panel in the browser's window.
Services.prefs.setBoolPref("browser.download.useToolkitUI", true);
registerCleanupFunction(function() {
Services.prefs.clearUserPref("browser.download.useToolkitUI");
});
// OK, now that all the data is in, let's pull up the UI
Cc["@mozilla.org/download-manager-ui;1"].
getService(Ci.nsIDownloadManagerUI).show();

View File

@ -68,6 +68,7 @@ let initTable = [
["console", "@mozilla.org/consoleservice;1", "nsIConsoleService"],
["contentPrefs", "@mozilla.org/content-pref/service;1", "nsIContentPrefService"],
["cookies", "@mozilla.org/cookiemanager;1", "nsICookieManager2"],
["downloads", "@mozilla.org/download-manager;1", "nsIDownloadManager"],
["droppedLinkHandler", "@mozilla.org/content/dropped-link-handler;1", "nsIDroppedLinkHandler"],
["eTLD", "@mozilla.org/network/effective-tld-service;1", "nsIEffectiveTLDService"],
["io", "@mozilla.org/network/io-service;1", "nsIIOService2"],

View File

@ -37,6 +37,7 @@ let dm = Cc["@mozilla.org/download-manager;1"]
let os = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
let checkDestination = false,
@ -114,6 +115,10 @@ let downloadListener = {
};
function init() {
// Ensure that the download manager callbacks always use the window UI instead
// of the panel in the browser's window.
Services.prefs.setBoolPref("browser.download.useToolkitUI", true);
ww.registerNotification(windowObserver);
PlacesUtils.annotations.addObserver(annoObserver, false);
dm.addListener(downloadListener);
@ -162,6 +167,8 @@ function endTest() {
.getMostRecentWindow("Download:Manager")
.close();
Services.prefs.clearUserPref("browser.download.useToolkitUI");
waitForClearHistory(SimpleTest.finish);
}

View File

@ -59,6 +59,8 @@ const kTaskbarID = "@mozilla.org/windows-taskbar;1";
const DOWNLOAD_MANAGER_URL = "chrome://mozapps/content/downloads/downloads.xul";
const DLMGR_UI_DONE = "download-manager-ui-done";
Components.utils.import("resource://gre/modules/Services.jsm");
let DownloadTaskbarProgress, TaskbarService, observerService, wwatch, chromeWindow;
let gGen = null;
@ -86,6 +88,9 @@ function continueTest() {
}
function doTest() {
// Ensure that the download manager callbacks always use the window UI instead
// of the panel in the browser's window.
Services.prefs.setBoolPref("browser.download.useToolkitUI", true);
let tempScope = {};
Components.utils.import("resource://gre/modules/DownloadTaskbarProgress.jsm", tempScope);
@ -144,6 +149,8 @@ function doTest() {
// original window still exists
checkActiveTaskbar(false, window);
Services.prefs.clearUserPref("browser.download.useToolkitUI");
browserWindow.close();
SimpleTest.finish();
yield;

View File

@ -55,6 +55,8 @@
<script type="application/javascript">
<![CDATA[
Components.utils.import("resource://gre/modules/Services.jsm");
function test()
{
var dmui = getDMUI();
@ -69,9 +71,9 @@ function test()
// Empty any old downloads
dm.DBConnection.executeSimpleSQL("DELETE FROM moz_downloads");
let setClose = function(aVal) Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch).
setBoolPref("browser.download.manager.closeWhenDone", aVal);
function setClose(aVal) {
Services.prefs.setBoolPref("browser.download.manager.closeWhenDone", aVal);
}
// Close the UI if necessary
let wm = Cc["@mozilla.org/appshell/window-mediator;1"].
@ -79,6 +81,10 @@ function test()
let win = wm.getMostRecentWindow("Download:Manager");
if (win) win.close();
// Ensure that the download manager callbacks always use the window UI instead
// of the panel in the browser's window.
Services.prefs.setBoolPref("browser.download.useToolkitUI", true);
let os = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
const DLMGR_UI_DONE = "download-manager-ui-done";
@ -101,11 +107,9 @@ function test()
setClose(false);
os.removeObserver(testObs, DLMGR_UI_DONE);
try {
Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch).
clearUserPref("browser.download.manager.closeWhenDone");
} catch (err) { }
Services.prefs.clearUserPref("browser.download.manager.closeWhenDone");
Services.prefs.clearUserPref("browser.download.useToolkitUI");
SimpleTest.finish();
}
};