summaryrefslogtreecommitdiffstats
path: root/browser/components/downloads/content/indicator.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/downloads/content/indicator.js')
-rw-r--r--browser/components/downloads/content/indicator.js606
1 files changed, 0 insertions, 606 deletions
diff --git a/browser/components/downloads/content/indicator.js b/browser/components/downloads/content/indicator.js
deleted file mode 100644
index 4c22a6e5d..000000000
--- a/browser/components/downloads/content/indicator.js
+++ /dev/null
@@ -1,606 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 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() {
- return "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 asynchronously just after window initialization.
- *
- * NOTE: This function should limit the input/output it performs to improve
- * startup time.
- */
- initializeIndicator() {
- DownloadsIndicatorView.ensureInitialized();
- },
-
- /**
- * 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() {
- // Prevent the indicator from being displayed as a temporary anchor
- // during customization, even if requested using the getAnchor method.
- this._customizing = true;
- this._anchorRequested = false;
- },
-
- /**
- * This function is called when toolbar customization ends.
- */
- customizeDone() {
- this._customizing = false;
- DownloadsIndicatorView.afterCustomize();
- },
-
- /**
- * 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.
- */
- _getAnchorInternal() {
- let indicator = DownloadsIndicatorView.indicator;
- if (!indicator) {
- // Exit now if the indicator overlay isn't loaded yet, or if the button
- // is not in the document.
- return null;
- }
-
- indicator.open = this._anchorRequested;
-
- let widget = CustomizableUI.getWidget("downloads-button")
- .forWindow(window);
- // Determine if the indicator is located on an invisible toolbar.
- if (!isElementVisible(indicator.parentNode) && !widget.overflowed) {
- return null;
- }
-
- return DownloadsIndicatorView.indicatorAnchor;
- },
-
- /**
- * Checks whether the indicator is, or will soon be visible in the browser
- * window.
- *
- * @param aCallback
- * Called once the indicator overlay has loaded. Gets a boolean
- * argument representing the indicator visibility.
- */
- checkIsVisible(aCallback) {
- DownloadsOverlayLoader.ensureOverlayLoaded(this.kIndicatorOverlay, () => {
- if (!this._placeholder) {
- aCallback(false);
- } else {
- let element = DownloadsIndicatorView.indicator || this._placeholder;
- aCallback(isElementVisible(element.parentNode));
- }
- });
- },
-
- /**
- * 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(aCallback) {
- // Do not allow anchoring the panel to the element while customizing.
- if (this._customizing) {
- aCallback(null);
- return;
- }
-
- DownloadsOverlayLoader.ensureOverlayLoaded(this.kIndicatorOverlay, () => {
- this._anchorRequested = true;
- aCallback(this._getAnchorInternal());
- });
- },
-
- /**
- * Allows the temporary anchor to be hidden.
- */
- releaseAnchor() {
- this._anchorRequested = false;
- this._getAnchorInternal();
- },
-
- get _tabsToolbar() {
- delete this._tabsToolbar;
- return this._tabsToolbar = document.getElementById("TabsToolbar");
- },
-
- get _navBar() {
- delete this._navBar;
- return this._navBar = document.getElementById("nav-bar");
- }
-};
-
-Object.defineProperty(this, "DownloadsButton", {
- value: DownloadsButton,
- enumerable: true,
- writable: false
-});
-
-////////////////////////////////////////////////////////////////////////////////
-//// 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() {
- if (this._initialized) {
- return;
- }
- this._initialized = true;
-
- window.addEventListener("unload", this.onWindowUnload, false);
- DownloadsCommon.getIndicatorData(window).addView(this);
- },
-
- /**
- * Frees the internal resources related to the indicator.
- */
- ensureTerminated() {
- if (!this._initialized) {
- return;
- }
- this._initialized = false;
-
- window.removeEventListener("unload", this.onWindowUnload, false);
- DownloadsCommon.getIndicatorData(window).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 = DownloadsCommon.ATTENTION_NONE;
- },
-
- /**
- * Ensures that the user interface elements required to display the indicator
- * are loaded, then invokes the given callback.
- */
- _ensureOperational(aCallback) {
- if (this._operational) {
- if (aCallback) {
- aCallback();
- }
- return;
- }
-
- // If we don't have a _placeholder, there's no chance that the overlay
- // will load correctly: bail (and don't set _operational to true!)
- if (!DownloadsButton._placeholder) {
- return;
- }
-
- DownloadsOverlayLoader.ensureOverlayLoaded(
- DownloadsButton.kIndicatorOverlay,
- () => {
- 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.getIndicatorData(window).refreshView(this);
- }
-
- if (aCallback) {
- aCallback();
- }
- });
- },
-
- //////////////////////////////////////////////////////////////////////////////
- //// Direct control functions
-
- /**
- * Set while we are waiting for a notification to fade out.
- */
- _notificationTimeout: null,
-
- /**
- * Check if the panel containing aNode is open.
- * @param aNode
- * the node whose panel we're interested in.
- */
- _isAncestorPanelOpen(aNode) {
- while (aNode && aNode.localName != "panel") {
- aNode = aNode.parentNode;
- }
- return aNode && aNode.state == "open";
- },
-
- /**
- * 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.
- *
- * @param aType
- * Set to "start" for new downloads, "finish" for completed downloads.
- */
- showEventNotification(aType) {
- if (!this._initialized) {
- return;
- }
-
- if (!DownloadsCommon.animateNotifications) {
- return;
- }
-
- // No need to show visual notification if the panel is visible.
- if (DownloadsPanel.isPanelShowing) {
- return;
- }
-
- let anchor = DownloadsButton._placeholder;
- let widgetGroup = CustomizableUI.getWidget("downloads-button");
- let widget = widgetGroup.forWindow(window);
- if (widget.overflowed || widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL) {
- if (anchor && this._isAncestorPanelOpen(anchor)) {
- // If the containing panel is open, don't do anything, because the
- // notification would appear under the open panel. See
- // https://bugzilla.mozilla.org/show_bug.cgi?id=984023
- return;
- }
-
- // Otherwise, try to use the anchor of the panel:
- anchor = widget.anchor;
- }
- if (!anchor || !isElementVisible(anchor.parentNode)) {
- // Our container isn't visible, so can't show the animation:
- return;
- }
-
- if (this._notificationTimeout) {
- clearTimeout(this._notificationTimeout);
- }
-
- // The notification element is positioned to show in the same location as
- // the downloads button. It's not in the downloads button itself in order to
- // be able to anchor the notification elsewhere if required, and to ensure
- // the notification isn't clipped by overflow properties of the anchor's
- // container.
- let notifier = this.notifier;
- if (notifier.style.transform == '') {
- let anchorRect = anchor.getBoundingClientRect();
- let notifierRect = notifier.getBoundingClientRect();
- let topDiff = anchorRect.top - notifierRect.top;
- let leftDiff = anchorRect.left - notifierRect.left;
- let heightDiff = anchorRect.height - notifierRect.height;
- let widthDiff = anchorRect.width - notifierRect.width;
- let translateX = (leftDiff + .5 * widthDiff) + "px";
- let translateY = (topDiff + .5 * heightDiff) + "px";
- notifier.style.transform = "translate(" + translateX + ", " + translateY + ")";
- }
- notifier.setAttribute("notification", aType);
- this._notificationTimeout = setTimeout(() => {
- notifier.removeAttribute("notification");
- notifier.style.transform = '';
- }, 1000);
- },
-
- //////////////////////////////////////////////////////////////////////////////
- //// 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._operational && aValue)) {
- this._hasDownloads = aValue;
-
- // If there is at least one download, ensure that the view elements are
- if (aValue) {
- this._ensureOperational();
- }
- }
- 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;
-
- // Check if the downloads button is in the menu panel, to determine which
- // button needs to get a badge.
- let widgetGroup = CustomizableUI.getWidget("downloads-button");
- let inMenu = widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL;
-
- if (aValue == DownloadsCommon.ATTENTION_NONE) {
- this.indicator.removeAttribute("attention");
- if (inMenu) {
- gMenuButtonBadgeManager.removeBadge(gMenuButtonBadgeManager.BADGEID_DOWNLOAD);
- }
- } else {
- this.indicator.setAttribute("attention", aValue);
- if (inMenu) {
- let badgeClass = "download-" + aValue;
- gMenuButtonBadgeManager.addBadge(gMenuButtonBadgeManager.BADGEID_DOWNLOAD, badgeClass);
- }
- }
- }
- return aValue;
- },
- _attention: DownloadsCommon.ATTENTION_NONE,
-
- //////////////////////////////////////////////////////////////////////////////
- //// User interface event functions
-
- onWindowUnload() {
- // This function is registered as an event listener, we can't use "this".
- DownloadsIndicatorView.ensureTerminated();
- },
-
- onCommand(aEvent) {
- // If the downloads button is in the menu panel, open the Library
- let widgetGroup = CustomizableUI.getWidget("downloads-button");
- if (widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL) {
- DownloadsPanel.showDownloadsHistory();
- } else {
- DownloadsPanel.showPanel();
- }
-
- aEvent.stopPropagation();
- },
-
- onDragOver(aEvent) {
- browserDragAndDrop.dragOver(aEvent);
- },
-
- onDrop(aEvent) {
- let dt = aEvent.dataTransfer;
- // If dragged item is from our source, do not try to
- // redownload already downloaded file.
- if (dt.mozGetDataAt("application/x-moz-file", 0))
- return;
-
- let links = browserDragAndDrop.dropLinks(aEvent);
- if (!links.length)
- return;
- let sourceDoc = dt.mozSourceNode ? dt.mozSourceNode.ownerDocument : document;
- let handled = false;
- for (let link of links) {
- if (link.url.startsWith("about:"))
- continue;
- saveURL(link.url, link.name, null, true, true, null, sourceDoc);
- handled = true;
- }
- if (handled) {
- aEvent.preventDefault();
- }
- },
-
- _indicator: null,
- __indicatorCounter: null,
- __indicatorProgress: null,
-
- /**
- * Returns a reference to the main indicator element, or null if the element
- * is not present in the browser window yet.
- */
- get indicator() {
- if (this._indicator) {
- return this._indicator;
- }
-
- let indicator = document.getElementById("downloads-button");
- if (!indicator || indicator.getAttribute("indicator") != "true") {
- return null;
- }
-
- return this._indicator = indicator;
- },
-
- get indicatorAnchor() {
- let widget = CustomizableUI.getWidget("downloads-button")
- .forWindow(window);
- if (widget.overflowed) {
- return widget.anchor;
- }
- return document.getElementById("downloads-indicator-anchor");
- },
-
- get _indicatorCounter() {
- return this.__indicatorCounter ||
- (this.__indicatorCounter = document.getElementById("downloads-indicator-counter"));
- },
-
- get _indicatorProgress() {
- return this.__indicatorProgress ||
- (this.__indicatorProgress = document.getElementById("downloads-indicator-progress"));
- },
-
- get notifier() {
- return this._notifier ||
- (this._notifier = document.getElementById("downloads-notification-anchor"));
- },
-
- _onCustomizedAway() {
- this._indicator = null;
- this.__indicatorCounter = null;
- this.__indicatorProgress = null;
- },
-
- afterCustomize() {
- // If the cached indicator is not the one currently in the document,
- // invalidate our references
- if (this._indicator != document.getElementById("downloads-button")) {
- this._onCustomizedAway();
- this._operational = false;
- this.ensureTerminated();
- this.ensureInitialized();
- }
- },
-};
-
-Object.defineProperty(this, "DownloadsIndicatorView", {
- value: DownloadsIndicatorView,
- enumerable: true,
- writable: false
-});