Commit 18a86022 authored by henry's avatar henry Committed by Pier Angelo Vendrame
Browse files

BB 41581: Hide NoScript extension's toolbar button by default.

This hides it from both the toolbar and the unified extensions panel.

We also hide the unified-extension-button if the panel would be empty:
not including the NoScript button when it is hidden. As a result, this
will be hidden by default until a user installs another extension (or
shows the NoScript button and unpins it).
parent a772e355
Loading
Loading
Loading
Loading
+69 −1
Original line number Diff line number Diff line
@@ -30,6 +30,9 @@ ChromeUtils.defineLazyGetter(lazy, "l10n", function () {
  );
});

const HIDE_NO_SCRIPT_PREF = "extensions.hideNoScript";
const HIDE_UNIFIED_WHEN_EMPTY_PREF = "extensions.hideUnifiedWhenEmpty";

/**
 * Mapping of error code -> [error-id, local-error-id]
 *
@@ -2019,6 +2022,18 @@ var gUnifiedExtensions = {

    Glean.extensionsButton.prefersHiddenButton.set(!this.buttonAlwaysVisible);

    // Listen out for changes in extensions.hideNoScript and
    // extension.hideUnifiedWhenEmpty, which can effect the visibility of the
    // unified-extensions-button.
    // See tor-browser#41581.
    this._hideNoScriptObserver = () => this._updateVisibility();
    Services.prefs.addObserver(HIDE_NO_SCRIPT_PREF, this._hideNoScriptObserver);
    Services.prefs.addObserver(
      HIDE_UNIFIED_WHEN_EMPTY_PREF,
      this._hideNoScriptObserver
    );
    this._updateVisibility();

    this._initialized = true;
  },

@@ -2040,6 +2055,15 @@ var gUnifiedExtensions = {
    gNavToolbox.removeEventListener("aftercustomization", this);
    CustomizableUI.removeListener(this);
    AddonManager.removeManagerListener(this);

    Services.prefs.removeObserver(
      HIDE_NO_SCRIPT_PREF,
      this._hideNoScriptObserver
    );
    Services.prefs.removeObserver(
      HIDE_UNIFIED_WHEN_EMPTY_PREF,
      this._hideNoScriptObserver
    );
  },

  onBlocklistAttentionUpdated() {
@@ -2213,6 +2237,15 @@ var gUnifiedExtensions = {
        return false;
      }

      // When an extensions is about to be removed, it may still appear in
      // getActiveExtensions.
      // This is needed for hasExtensionsInPanel, when called through
      // onWidgetDestroy when an extension is being removed.
      // See tor-browser#41581.
      if (extension.hasShutdown) {
        return false;
      }

      // Ignore hidden and extensions that cannot access the current window
      // (because of PB mode when we are in a private window), since users
      // cannot do anything with those extensions anyway.
@@ -2227,6 +2260,21 @@ var gUnifiedExtensions = {
    return policies;
  },

  /**
   * Potentially hide the unified-extensions-button if it would be empty.
   */
  // See tor-browser#41581.
  // The behaviour overlaps with a proposal in mozilla Bug 1778684, which has
  // not yet been implemented as of June 2024 (start of ESR 128).
  // See tor-browser#42635
  _updateVisibility() {
    this.button.classList.toggle(
      "hide-empty",
      Services.prefs.getBoolPref(HIDE_UNIFIED_WHEN_EMPTY_PREF, true) &&
        !this.hasExtensionsInPanel()
    );
  },

  /**
   * Returns true when there are active extensions listed/shown in the unified
   * extensions panel, and false otherwise (e.g. when extensions are pinned in
@@ -2235,7 +2283,13 @@ var gUnifiedExtensions = {
   * @returns {boolean} Whether there are extensions listed in the panel.
   */
  hasExtensionsInPanel() {
    const policies = this.getActivePolicies();
    let policies = this.getActivePolicies();
    // If the NoScript button is hidden, we won't count it towards the list of
    // extensions in the panel.
    // See tor-browser#41581.
    if (Services.prefs.getBoolPref(HIDE_NO_SCRIPT_PREF, true)) {
      policies = policies.filter(policy => !policy.extension?.isNoScript);
    }

    return !!policies
      .map(policy => this.browserActionFor(policy)?.widget)
@@ -2805,7 +2859,17 @@ var gUnifiedExtensions = {
    }
  },

  onWidgetRemoved() {
    this._updateVisibility();
  },

  onWidgetDestroyed() {
    this._updateVisibility();
  },

  onWidgetAdded(aWidgetId, aArea) {
    this._updateVisibility();

    // When we pin a widget to the toolbar from a narrow window, the widget
    // will be overflowed directly. In this case, we do not want to change the
    // class name since it is going to be changed by `onWidgetOverflow()`
@@ -2821,6 +2885,8 @@ var gUnifiedExtensions = {
  },

  onWidgetOverflow(aNode) {
    this._updateVisibility();

    // We register a CUI listener for each window so we make sure that we
    // handle the event for the right window here.
    if (window !== aNode.ownerGlobal) {
@@ -2831,6 +2897,8 @@ var gUnifiedExtensions = {
  },

  onWidgetUnderflow(aNode) {
    this._updateVisibility();

    // We register a CUI listener for each window so we make sure that we
    // handle the event for the right window here.
    if (window !== aNode.ownerGlobal) {
+16 −0
Original line number Diff line number Diff line
@@ -280,6 +280,22 @@ this.browserAction = class extends ExtensionAPIPersistent {
        node.append(rowWrapper, messagebarWrapper);
        node.viewButton = button;

        if (extension.isNoScript) {
          // Hide NoScript by default.
          // See tor-browser#41581.
          const HIDE_NO_SCRIPT_PREF = "extensions.hideNoScript";
          const changeNoScriptVisibility = () => {
            node.hidden = Services.prefs.getBoolPref(HIDE_NO_SCRIPT_PREF, true);
          };
          // Since we expect the NoScript widget to only be destroyed on exit,
          // we do not set up to remove the observer.
          Services.prefs.addObserver(
            HIDE_NO_SCRIPT_PREF,
            changeNoScriptVisibility
          );
          changeNoScriptVisibility();
        }

        return node;
      },

+18 −0
Original line number Diff line number Diff line
@@ -294,3 +294,21 @@ unified-extensions-item.unified-extensions-item {
    }
  }
}

/* Extra rule for tor-browser. See tor-browser#41581.
 * We want to hide the unified-extensions-button when it is empty.
 * However, this button is needed as an anchor for addon notifications. E.g.
 * when installing another addon and permissions pop up.
 * If we simply marked it as "hidden" then it would not be used as an anchor, so
 * the popup would fall back to using the identity button as an anchor instead.
 * So instead, we use "visibility: collapse" whilst it is empty *and* it is not
 * being used as an anchor (the open attribute is missing). */
#unified-extensions-button.hide-empty:not([open]) {
  visibility: collapse;
  /* Ensure getBoundingClientRect().width returns 0.
   * Even though this button is collapsed, and therefore should not take up any
   * layout space, getBoundingClientRect will still measure the padding.
   * If this was not zero, OverflowableToolbar#getOverflowInfo would
   * over-measure the children width and would always overflow. */
  padding-inline: 0;
}
+2 −1
Original line number Diff line number Diff line
@@ -4275,8 +4275,9 @@ export class Extension extends ExtensionData {
        });
        this.permissions.delete(PRIVATE_ALLOWED_PERMISSION);
      }
    }

    // Bug 40253: Explicitly allow NoScript in Private Browsing mode.
    // tor-browser#40253: Explicitly allow NoScript in Private Browsing mode.
    if (this.isNoScript) {
      lazy.ExtensionPermissions.add(this.id, {
        permissions: [PRIVATE_ALLOWED_PERMISSION],
+26 −0
Original line number Diff line number Diff line
@@ -565,6 +565,32 @@
          <div class="addon-detail-mlmodel">
            <addon-mlmodel-details></addon-mlmodel-details>
          </div>
          <!-- Add an option to show the NoScript toolbar button, if this is the
             - NoScript addon. See tor-browser#41581. -->
          <div
            class="addon-detail-row addon-detail-row-noscript-visibility"
            role="radiogroup"
            hidden="hidden"
          >
            <span
              class="addon-noscript-visibility-label"
              data-l10n-id="basebrowser-addon-noscript-visibility-label"
            ></span>
            <div class="addon-detail-actions">
              <label class="radio-container-with-text">
                <input type="radio" name="noscript-visibility" value="show" />
                <span
                  data-l10n-id="basebrowser-addon-noscript-visibility-show"
                ></span>
              </label>
              <label class="radio-container-with-text">
                <input type="radio" name="noscript-visibility" value="hide" />
                <span
                  data-l10n-id="basebrowser-addon-noscript-visibility-hide"
                ></span>
              </label>
            </div>
          </div>
          <div
            class="addon-detail-row addon-detail-row-updates"
            role="group"
Loading