Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/browser/components/downloads/content/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 18 kB image not shown  

Quelle  indicator.js   Sprache: JAVA

 
/* -*- 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/. */

/* eslint-env mozilla/browser-window */

/**
 * 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 = {
  /**
   * 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");
  },

  /**
   * Indicates whether toolbar customization is in progress.
   */

  _customizing: false,

  /**
   * 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();
  },

  /**
   * 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 button is not in the document.
      return null;
    }

    indicator.open = this._anchorRequested;

    let widget = CustomizableUI.getWidget("downloads-button");
    // Determine if the indicator is located on an invisible toolbar.
    if (
      !isElementVisible(indicator.parentNode) &&
      widget.areaType == CustomizableUI.TYPE_TOOLBAR
    ) {
      return null;
    }

    return DownloadsIndicatorView.indicatorAnchor;
  },

  /**
   * 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.
   *
   * @return Anchor 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() {
    // Do not allow anchoring the panel to the element while customizing.
    if (this._customizing) {
      return null;
    }

    this._anchorRequested = true;
    return this._getAnchorInternal();
  },

  /**
   * Allows the temporary anchor to be hidden.
   */

  releaseAnchor() {
    this._anchorRequested = false;
    this._getAnchorInternal();
  },

  /**
   * Unhide the button. Generally, this only needs to use the placeholder.
   * However, when starting customize mode, if the button is in the palette,
   * we need to unhide it before customize mode is entered, otherwise it
   * gets ignored by customize mode. To do this, we pass true for
   * `includePalette`. We don't always look in the palette because it's
   * inefficient (compared to getElementById), shouldn't be necessary, and
   * if _placeholder returned the node even if in the palette, other checks
   * would break.
   *
   * @param includePalette  whether to search the palette, too. Defaults to false.
   */

  unhide(includePalette = false) {
    let button = this._placeholder;
    let wasHidden = false;
    if (!button && includePalette) {
      button = gNavToolbox.palette.querySelector("#downloads-button");
    }
    if (button && button.hasAttribute("hidden")) {
      button.removeAttribute("hidden");
      if (this._navBar.contains(button)) {
        this._navBar.setAttribute("downloadsbuttonshown""true");
      }
      wasHidden = true;
    }
    return wasHidden;
  },

  hide() {
    let button = this._placeholder;
    if (this.autoHideDownloadsButton && button && button.closest("toolbar")) {
      DownloadsPanel.hidePanel();
      button.hidden = true;
      this._navBar.removeAttribute("downloadsbuttonshown");
    }
  },

  startAutoHide() {
    if (DownloadsIndicatorView.hasDownloads) {
      this.unhide();
    } else {
      this.hide();
    }
  },

  checkForAutoHide() {
    let button = this._placeholder;
    if (
      !this._customizing &&
      this.autoHideDownloadsButton &&
      button &&
      button.closest("toolbar")
    ) {
      this.startAutoHide();
    } else {
      this.unhide();
    }
  },

  // Callback from CustomizableUI when nodes get moved around.
  // We use this to track whether our node has moved somewhere
  // where we should (not) autohide it.
  onWidgetAfterDOMChange(node) {
    if (node == this._placeholder) {
      this.checkForAutoHide();
    }
  },

  /**
   * 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.
   */

  onCustomizeStart(win) {
    if (win == window) {
      // 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.unhide(true);
    }
  },

  onCustomizeEnd(win) {
    if (win == window) {
      this._customizing = false;
      this.checkForAutoHide();
      DownloadsIndicatorView.afterCustomize();
    }
  },

  init() {
    XPCOMUtils.defineLazyPreferenceGetter(
      this,
      "autoHideDownloadsButton",
      "browser.download.autohideButton",
      true,
      this.checkForAutoHide.bind(this)
    );

    CustomizableUI.addListener(this);
    this.checkForAutoHide();
  },

  uninit() {
    CustomizableUI.removeListener(this);
  },

  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);
    window.addEventListener("visibilitychange"this);
    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);
    window.removeEventListener("visibilitychange"this);
    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.percentComplete = 0;
    this.attention = DownloadsCommon.ATTENTION_NONE;
  },

  /**
   * Ensures that the user interface elements required to display the indicator
   * are loaded.
   */

  _ensureOperational() {
    if (this._operational) {
      return;
    }

    // If we don't have a _placeholder, there's no chance that everything
    // will load correctly: bail (and don't set _operational to true!)
    if (!DownloadsButton._placeholder) {
      return;
    }

    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);
    }
  },

  // Direct control functions

  /**
   * Set to the type ("start" or "finish") when display of a notification is in-progress
   */

  _currentNotificationType: null,

  /**
   * Set to the type ("start" or "finish") when a notification arrives while we
   * are waiting for the timeout of the previous notification
   */

  _nextNotificationType: 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";
  },

  /**
   * Display or enqueue 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;
    }

    // enqueue this notification while the current one is being displayed
    if (this._currentNotificationType) {
      // only queue up the notification if it is different to the current one
      if (this._currentNotificationType != aType) {
        this._nextNotificationType = aType;
      }
    } else {
      this._showNotification(aType);
    }
  },

  /**
   * 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.
   */

  _showNotification(aType) {
    let anchor = DownloadsButton._placeholder;
    if (!anchor || !isElementVisible(anchor.parentNode)) {
      // Our container isn't visible, so can't show the animation:
      return;
    }

    if (anchor.ownerGlobal.matchMedia("(prefers-reduced-motion)").matches) {
      // User has prefers-reduced-motion enabled, so we shouldn't show the animation.
      return;
    }

    anchor.setAttribute("notification", aType);
    anchor.setAttribute("animate""");

    // are we animating from an initially-hidden state?
    anchor.toggleAttribute("washidden", !!this._wasHidden);
    delete this._wasHidden;

    this._currentNotificationType = aType;

    const onNotificationAnimEnd = event => {
      if (
        event.animationName !== "downloadsButtonNotification" &&
        event.animationName !== "downloadsButtonFinishedNotification"
      ) {
        return;
      }
      anchor.removeEventListener("animationend", onNotificationAnimEnd);

      requestAnimationFrame(() => {
        anchor.removeAttribute("notification");
        anchor.removeAttribute("animate");

        requestAnimationFrame(() => {
          let nextType = this._nextNotificationType;
          this._currentNotificationType = null;
          this._nextNotificationType = null;
          if (nextType && isElementVisible(anchor.parentNode)) {
            this._showNotification(nextType);
          }
        });
      });
    };
    anchor.addEventListener("animationend", onNotificationAnimEnd);
  },

  // 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
      // operational
      if (aValue) {
        this._wasHidden = DownloadsButton.unhide();
        this._ensureOperational();
      } else {
        DownloadsButton.checkForAutoHide();
      }
    }
  },
  get hasDownloads() {
    return this._hasDownloads;
  },
  _hasDownloads: false,

  /**
   * Progress indication to display, from 0 to 100, or -1 if unknown.
   * Progress is not visible if the current progress is unknown.
   */

  set percentComplete(aValue) {
    if (!this._operational) {
      return;
    }
    aValue = Math.min(100, aValue);
    if (this._percentComplete !== aValue) {
      // Initial progress may fire before the start event gets to us.
      // To avoid flashing, trip the start event first.
      if (this._percentComplete < 0 && aValue >= 0) {
        this.showEventNotification("start");
      }
      this._percentComplete = aValue;
      this._refreshAttention();
      this._maybeScheduleProgressUpdate();
    }
  },

  _maybeScheduleProgressUpdate() {
    if (
      this.indicator &&
      !this._progressRaf &&
      document.visibilityState == "visible"
    ) {
      this._progressRaf = requestAnimationFrame(() => {
        // indeterminate downloads (unknown content-length) will show up as aValue = 0
        if (this._percentComplete >= 0) {
          if (!this.indicator.hasAttribute("progress")) {
            this.indicator.setAttribute("progress""true");
          }
          // For arrow type only: Set the % complete on the pie-chart.
          // We use a minimum of 10% to ensure something is always visible
          this._progressIcon.style.setProperty(
            "--download-progress-pcent",
            `${Math.max(10, this._percentComplete)}%`
          );
        } else {
          this.indicator.removeAttribute("progress");
          this._progressIcon.style.setProperty(
            "--download-progress-pcent",
            "0%"
          );
        }
        this._progressRaf = null;
      });
    }
  },
  _percentComplete: -1,

  /**
   * Set when the indicator should draw user attention to itself.
   */

  set attention(aValue) {
    if (!this._operational) {
      return;
    }
    if (this._attention != aValue) {
      this._attention = aValue;
      this._refreshAttention();
    }
  },

  _refreshAttention() {
    // 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_PANEL;

    // For arrow-Styled indicator, suppress success attention if we have
    // progress in toolbar
    let suppressAttention =
      !inMenu &&
      this._attention == DownloadsCommon.ATTENTION_SUCCESS &&
      this._percentComplete >= 0;

    if (
      suppressAttention ||
      this._attention == DownloadsCommon.ATTENTION_NONE
    ) {
      this.indicator.removeAttribute("attention");
    } else {
      this.indicator.setAttribute("attention"this._attention);
    }
  },
  _attention: DownloadsCommon.ATTENTION_NONE,

  // User interface event functions
  handleEvent(aEvent) {
    switch (aEvent.type) {
      case "unload":
        this.ensureTerminated();
        break;

      case "visibilitychange":
        this._maybeScheduleProgressUpdate();
        break;
    }
  },

  onCommand(aEvent) {
    if (
      // On Mac, ctrl-click will send a context menu event from the widget, so
      // we don't want to bring up the panel when ctrl key is pressed.
      (aEvent.type == "mousedown" &&
        (aEvent.button != 0 ||
          (AppConstants.platform == "macosx" && aEvent.ctrlKey))) ||
      (aEvent.type == "keypress" && aEvent.key != " " && aEvent.key != "Enter")
    ) {
      return;
    }

    DownloadsPanel.showPanel(
      /* openedManually */ true,
      aEvent.type.startsWith("key")
    );
    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,
        null,
        link.name,
        null,
        true,
        true,
        null,
        null,
        sourceDoc
      );
      handled = true;
    }
    if (handled) {
      aEvent.preventDefault();
    }
  },

  _indicator: null,
  __progressIcon: 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) {
      this._indicator = document.getElementById("downloads-button");
    }

    return this._indicator;
  },

  get indicatorAnchor() {
    let widgetGroup = CustomizableUI.getWidget("downloads-button");
    if (widgetGroup.areaType == CustomizableUI.TYPE_PANEL) {
      let overflowIcon = widgetGroup.forWindow(window).anchor;
      return overflowIcon.icon;
    }

    return this.indicator.badgeStack;
  },

  get _progressIcon() {
    return (
      this.__progressIcon ||
      (this.__progressIcon = document.getElementById(
        "downloads-indicator-progress-inner"
      ))
    );
  },

  _onCustomizedAway() {
    this._indicator = null;
    this.__progressIcon = 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,
});

Messung V0.5
C=90 H=97 G=93

¤ Dauer der Verarbeitung: 0.29 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.