Commit c3acd03b authored by Gijs Kruitbosch's avatar Gijs Kruitbosch
Browse files

Bug 1397447 - add UI and automatic toggles to make the auto-hide functionality more seamless, r=mak

MozReview-Commit-ID: 9xN3N4aLwfv

--HG--
extra : rebase_source : 54333982cce1dcb7cb84331734f170d4d79fbc29
parent 3f3bcb5b
Loading
Loading
Loading
Loading
+124 −0
Original line number Diff line number Diff line
@@ -21,6 +21,10 @@ const kKeepBroadcastAttributes = "keepbroadcastattributeswhencustomizing";
const kPanelItemContextMenu = "customizationPanelItemContextMenu";
const kPaletteItemContextMenu = "customizationPaletteItemContextMenu";

const kDownloadAutohideCheckboxId = "downloads-button-autohide-checkbox";
const kDownloadAutohidePanelId = "downloads-button-autohide-panel";
const kDownloadAutoHidePref = "browser.download.autohideButton";

Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/CustomizableUI.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@@ -354,6 +358,8 @@ CustomizeMode.prototype = {

      this._updateLWThemeButtonIcon();

      this._setupDownloadAutoHideToggle();

      this._handler.isEnteringCustomizeMode = false;

      CustomizableUI.dispatchToolboxEvent("customizationready", {}, window);
@@ -395,6 +401,8 @@ CustomizeMode.prototype = {

    this._removeExtraToolbarsIfEmpty();

    this._teardownDownloadAutoHideToggle();

    CustomizableUI.removeListener(this);

    this.document.removeEventListener("keypress", this);
@@ -472,6 +480,8 @@ CustomizeMode.prototype = {
      for (let toolbar of customizableToolbars)
        toolbar.removeAttribute("customizing");

      this._maybeMoveDownloadsButtonToNavBar();

      delete this._lastLightweightTheme;
      this._changed = false;
      this._transitioning = false;
@@ -616,6 +626,12 @@ CustomizeMode.prototype = {
    if (aNode.localName == "toolbarpaletteitem" && aNode.firstChild) {
      aNode = aNode.firstChild;
    }

    // If the user explicitly moves this item, turn off autohide.
    if (aNode.id == "downloads-button") {
      Services.prefs.setBoolPref(kDownloadAutoHidePref, false);
    }

    CustomizableUI.addWidgetToArea(aNode.id, CustomizableUI.AREA_NAVBAR);
    if (!this._customizing) {
      CustomizableUI.dispatchToolboxEvent("customizationchange");
@@ -627,6 +643,12 @@ CustomizeMode.prototype = {
    if (aNode.localName == "toolbarpaletteitem" && aNode.firstChild) {
      aNode = aNode.firstChild;
    }

    // If the user explicitly moves this item, turn off autohide.
    if (aNode.id == "downloads-button") {
      Services.prefs.setBoolPref(kDownloadAutoHidePref, false);
    }

    let panel = CustomizableUI.AREA_FIXED_OVERFLOW_PANEL;
    CustomizableUI.addWidgetToArea(aNode.id, panel);
    if (!this._customizing) {
@@ -655,6 +677,10 @@ CustomizeMode.prototype = {
    if (aNode.localName == "toolbarpaletteitem" && aNode.firstChild) {
      aNode = aNode.firstChild;
    }
    // If the user explicitly removes this item, turn off autohide.
    if (aNode.id == "downloads-button") {
      Services.prefs.setBoolPref(kDownloadAutoHidePref, false);
    }
    CustomizableUI.removeWidgetFromArea(aNode.id);
    if (!this._customizing) {
      CustomizableUI.dispatchToolboxEvent("customizationchange");
@@ -1081,6 +1107,7 @@ CustomizeMode.prototype = {
      this._updateResetButton();
      this._updateUndoResetButton();
      this._updateEmptyPaletteNotice();
      this._moveDownloadsButtonToNavBar = false;
      this.resetting = false;
      if (!this._wantToBeInCustomizeMode) {
        this.exit();
@@ -1107,6 +1134,7 @@ CustomizeMode.prototype = {
      this._updateResetButton();
      this._updateUndoResetButton();
      this._updateEmptyPaletteNotice();
      this._moveDownloadsButtonToNavBar = false;
      this.resetting = false;
    })().catch(log.error);
  },
@@ -1173,6 +1201,9 @@ CustomizeMode.prototype = {
        this.visiblePalette.appendChild(paletteItem);
      }
    }
    if (aNodeToChange.id == "downloads-button") {
      this._showDownloadsAutoHidePanel();
    }
  },

  onWidgetDestroyed(aWidgetId) {
@@ -1757,6 +1788,11 @@ CustomizeMode.prototype = {
    } catch (ex) {
      log.error(ex, ex.stack);
    }

    // If the user explicitly moves this item, turn off autohide.
    if (draggedItemId == "downloads-button") {
      Services.prefs.setBoolPref(kDownloadAutoHidePref, false);
    }
  },

  _applyDrop(aEvent, aTargetArea, aOriginArea, aDraggedItemId, aTargetNode) {
@@ -2246,6 +2282,94 @@ CustomizeMode.prototype = {
    doc.getElementById("customizationPanelItemContextMenuUnpin").hidden = !inPermanentArea;
    doc.getElementById("customizationPanelItemContextMenuPin").hidden = inPermanentArea;
  },

  _checkForDownloadsClick(event) {
    if (event.target.closest("#wrapper-downloads-button") && event.button == 0) {
      event.view.gCustomizeMode._showDownloadsAutoHidePanel();
    }
  },

  _setupDownloadAutoHideToggle() {
    this.document.getElementById(kDownloadAutohidePanelId).removeAttribute("hidden");
    this.window.addEventListener("click", this._checkForDownloadsClick, true);
  },

  _teardownDownloadAutoHideToggle() {
    this.window.removeEventListener("click", this._checkForDownloadsClick, true);
    this.document.getElementById(kDownloadAutohidePanelId).hidePopup();
  },

  _maybeMoveDownloadsButtonToNavBar() {
    // If the user toggled the autohide checkbox while the item was in the
    // palette, and hasn't moved it since, move the item to the default
    // location in the navbar for them.
    if (!CustomizableUI.getPlacementOfWidget("downloads-button") &&
        this._moveDownloadsButtonToNavBar &&
        this.window.DownloadsButton.autoHideDownloadsButton) {
      let navbarPlacements = CustomizableUI.getWidgetIdsInArea("nav-bar");
      let insertionPoint = navbarPlacements.indexOf("urlbar-container");
      while (++insertionPoint < navbarPlacements.length) {
        let widget = navbarPlacements[insertionPoint];
        // If we find a non-searchbar, non-spacer node, break out of the loop:
        if (widget != "search-container" &&
             !(CustomizableUI.isSpecialWidget(widget) && widget.includes("spring"))) {
          break;
        }
      }
      CustomizableUI.addWidgetToArea("downloads-button", "nav-bar", insertionPoint);
    }
  },

  _showDownloadsAutoHidePanel() {
    let doc = this.document;
    let panel = doc.getElementById(kDownloadAutohidePanelId);
    panel.hidePopup();
    let button = doc.getElementById("downloads-button");
    // We don't show the tooltip if the button is in the panel.
    if (button.closest("#widget-overflow-fixed-list")) {
      return;
    }

    let checkbox = doc.getElementById(kDownloadAutohideCheckboxId);
    if (this.window.DownloadsButton.autoHideDownloadsButton) {
      checkbox.setAttribute("checked", "true");
    } else {
      checkbox.removeAttribute("checked");
    }

    let offsetX = 0, offsetY = 0;
    let position;
    if (button.closest("#nav-bar")) {
      let navbarWidgets = CustomizableUI.getWidgetIdsInArea("nav-bar");
      if (navbarWidgets.indexOf("urlbar-container") > navbarWidgets.indexOf("downloads-button")) {
        // Tested in RTL, these get inverted automatically, so this does the
        // right thing without taking RTL into account explicitly.
        position = "rightcenter topleft";
        offsetX = -8;
      } else {
        position = "leftcenter topright";
        offsetX = 8;
      }
    } else if (button.closest("#customization-palette")) {
      position = "topcenter bottomleft";
      offsetY = 10;
    } else {
      // For non-navbar toolbars, this works better than guessing whether
      // left or right is a better place to position:
      position = "bottomcenter topleft";
      offsetY = -5;
    }
    // We don't use the icon to anchor because it might be resizing because of
    // the animations for drag/drop. Hence the use of offsets.
    panel.openPopup(button, position, offsetX, offsetY);
  },

  onDownloadsAutoHideChange(event) {
    let checkbox = event.target.ownerDocument.getElementById(kDownloadAutohideCheckboxId);
    Services.prefs.setBoolPref(kDownloadAutoHidePref, checkbox.checked);
    // Ensure we move the button (back) after the user leaves customize mode.
    event.view.gCustomizeMode._moveDownloadsButtonToNavBar = checkbox.checked;
  },
};

function __dumpDragData(aEvent, caller) {
+14 −0
Original line number Diff line number Diff line
@@ -753,3 +753,17 @@
    </panelview>
  </photonpanelmultiview>
</panel>

<panel id="downloads-button-autohide-panel"
       role="group"
       type="arrow"
       hidden="true"
       onpopupshown="gCustomizeMode._downloadPanelAutoHideTimeout = setTimeout(() => event.target.hidePopup(), 4000);"
       onmouseover="clearTimeout(gCustomizeMode._downloadPanelAutoHideTimeout);"
       onmouseout="gCustomizeMode._downloadPanelAutoHideTimeout = setTimeout(() => event.target.hidePopup(), 2000);"
       onpopuphidden="clearTimeout(gCustomizeMode._downloadPanelAutoHideTimeout);"
       >
  <checkbox id="downloads-button-autohide-checkbox"
            label="&customizeMode.autoHideDownloadsButton.label;" checked="true"
            oncommand="gCustomizeMode.onDownloadsAutoHideChange(event)"/>
</panel>
+25 −6
Original line number Diff line number Diff line
@@ -28,9 +28,15 @@ add_task(async function checkStateDuringPrefFlips() {
  gCustomizeMode.addToPanel(downloadsButton);
  ok(!downloadsButton.hasAttribute("hidden"),
     "Button shouldn't be hidden in the panel");
  ok(!Services.prefs.getBoolPref(kDownloadAutoHidePref),
     "Pref got set to false when the user moved the button");
  gCustomizeMode.addToToolbar(downloadsButton);
  ok(!Services.prefs.getBoolPref(kDownloadAutoHidePref),
     "Pref remains false when the user moved the button");
  Services.prefs.setBoolPref(kDownloadAutoHidePref, true);
  ok(downloadsButton.hasAttribute("hidden"),
     "Button should be hidden again in the toolbar");
     "Button should be hidden again in the toolbar " +
     "now that we flipped the pref");
  Services.prefs.setBoolPref(kDownloadAutoHidePref, false);
  ok(!downloadsButton.hasAttribute("hidden"),
     "Button shouldn't be hidden with autohide turned off");
@@ -47,7 +53,9 @@ add_task(async function checkStateDuringPrefFlips() {
  ok(!downloadsButton.hasAttribute("hidden"),
     "Button should still not be hidden with autohide turned back on " +
     "because it's in the panel");
  gCustomizeMode.addToToolbar(downloadsButton);
  // Use CUI directly instead of the customize mode APIs,
  // to avoid tripping the "automatically turn off autohide" code.
  CustomizableUI.addWidgetToArea("downloads-button", "nav-bar");
  ok(downloadsButton.hasAttribute("hidden"),
     "Button should be hidden again in the toolbar");
  gCustomizeMode.removeFromArea(downloadsButton);
@@ -68,6 +76,11 @@ add_task(async function checkStateInCustomizeMode() {
  await promiseCustomizeStart();
  ok(!downloadsButton.hasAttribute("hidden"),
     "Button should be shown in customize mode.");
  await promiseCustomizeEnd();
  ok(downloadsButton.hasAttribute("hidden"),
     "Button should be hidden if it's in the toolbar " +
     "after customize mode without any moves.");
  await promiseCustomizeStart();
  gCustomizeMode.addToPanel(downloadsButton);
  ok(!downloadsButton.hasAttribute("hidden"),
     "Button should be shown in customize mode when moved to the panel");
@@ -89,8 +102,9 @@ add_task(async function checkStateInCustomizeMode() {
  await promiseCustomizeStart();
  gCustomizeMode.addToToolbar(downloadsButton);
  await promiseCustomizeEnd();
  ok(downloadsButton.hasAttribute("hidden"),
     "Button should be hidden if it's in the toolbar after customize mode.");
  ok(!downloadsButton.hasAttribute("hidden"),
     "Button should be shown in the toolbar after " +
     "customize mode because we moved it.");
  await promiseCustomizeStart();
  await gCustomizeMode.reset();
  ok(!downloadsButton.hasAttribute("hidden"),
@@ -124,13 +138,16 @@ add_task(async function checkStateInCustomizeModeMultipleWindows() {
  ok(otherDownloadsButton.hasAttribute("hidden"),
     "Button should be hidden in the other window.");

  gCustomizeMode.addToPanel(downloadsButton);
  // Use CUI directly instead of the customize mode APIs,
  // to avoid tripping the "automatically turn off autohide" code.
  CustomizableUI.addWidgetToArea("downloads-button",
                                 CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
  ok(!downloadsButton.hasAttribute("hidden"),
     "Button should still be shown in customize mode.");
  ok(!otherDownloadsButton.hasAttribute("hidden"),
     "Button should be shown in the other window too because it's in a panel.");

  gCustomizeMode.addToToolbar(downloadsButton);
  CustomizableUI.addWidgetToArea("downloads-button", CustomizableUI.AREA_NAVBAR);
  ok(!downloadsButton.hasAttribute("hidden"),
     "Button should still be shown in customize mode.");
  ok(otherDownloadsButton.hasAttribute("hidden"),
@@ -156,6 +173,8 @@ add_task(async function checkStateInCustomizeModeMultipleWindows() {
     "Button should be shown in the other window too because it's in a panel.");

  gCustomizeMode.removeFromArea(downloadsButton);
  ok(!Services.prefs.getBoolPref(kDownloadAutoHidePref),
     "Autohide pref turned off by moving the button");
  ok(!downloadsButton.hasAttribute("hidden"),
     "Button should still be shown in customize mode.");
  // Don't need to assert in the other window - button is gone there.
+2 −0
Original line number Diff line number Diff line
@@ -866,6 +866,8 @@ you can use these alternative items. Otherwise, their values should be empty. -
<!ENTITY customizeMode.uidensity.menuTouch.accessKey "T">
<!ENTITY customizeMode.uidensity.autoTouchMode.checkbox.label "Use Touch for Tablet Mode">

<!ENTITY customizeMode.autoHideDownloadsButton.label "Auto-hide">

<!ENTITY getUserMedia.selectCamera.label "Camera to share:">
<!ENTITY getUserMedia.selectCamera.accesskey "C">
<!ENTITY getUserMedia.selectMicrophone.label "Microphone to share:">
+9 −0
Original line number Diff line number Diff line
@@ -497,3 +497,12 @@ toolbarpaletteitem[place=toolbar] > toolbarspring {
    background-image: url("chrome://browser/skin/customizableui/empty-overflow-panel@2x.png");
  }
}

#downloads-button-autohide-panel > .panel-arrowcontainer > .panel-arrowcontent {
  padding: 5px 12px;
}

#downloads-button-autohide-checkbox {
  margin: 0;
  padding: 0;
}