Bug 1563350 - Add popover to the Touch Bar that displays when the Urlbar has focus. r=mikedeboer,spohl,fluent-reviewers,Pike,flod
authorharry <htwyford@mozilla.com>
Tue, 08 Oct 2019 00:52:07 +0000
changeset 496763 355b0329bd95d2a9573c04ece889c734da00f080
parent 496762 653caa0c494a9058a9a1d5b2299bbf61b06268c2
child 496764 86ed8b9bee5f00fab8e1a5bfbdfa7ada92882711
push id36667
push useraiakab@mozilla.com
push dateTue, 08 Oct 2019 21:45:57 +0000
treeherdermozilla-central@e1a65223d498 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmikedeboer, spohl, fluent-reviewers, Pike, flod
bugs1563350
milestone71.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1563350 - Add popover to the Touch Bar that displays when the Urlbar has focus. r=mikedeboer,spohl,fluent-reviewers,Pike,flod Differential Revision: https://phabricator.services.mozilla.com/D38563
browser/components/touchbar/MacTouchBar.js
browser/components/urlbar/UrlbarInput.jsm
browser/locales/en-US/browser/touchbar/touchbar.ftl
widget/cocoa/nsTouchBar.mm
widget/nsITouchBarHelper.idl
--- a/browser/components/touchbar/MacTouchBar.js
+++ b/browser/components/touchbar/MacTouchBar.js
@@ -156,16 +156,58 @@ const kBuiltInInputs = {
   // Scrubbers are not yet generally implemented.
   // See follow-up bug 1502539.
   Share: {
     title: "share",
     image: "chrome://browser/skin/share.svg",
     type: kInputTypes.SCRUBBER,
     callback: () => execCommand("cmd_share", "Share"),
   },
+  SearchPopover: {
+    title: "search-popover",
+    image: "chrome://browser/skin/search-glass.svg",
+    type: kInputTypes.POPOVER,
+    children: {
+      SearchScrollViewLabel: {
+        title: "search-search-in",
+        type: kInputTypes.LABEL,
+      },
+      SearchScrollView: {
+        key: "search-scrollview",
+        type: kInputTypes.SCROLLVIEW,
+        children: {
+          Bookmarks: {
+            title: "search-bookmarks",
+            type: kInputTypes.BUTTON,
+            callback: () => console.log("Bookmarks success!"), // FIXME: Bug 1563351
+          },
+          History: {
+            title: "search-history",
+            type: kInputTypes.BUTTON,
+            callback: () => console.log("History success!"), // FIXME: Bug 1563351
+          },
+          OpenTabs: {
+            title: "search-opentabs",
+            type: kInputTypes.BUTTON,
+            callback: () => console.log("Open Tabs success!"), // FIXME: Bug 1563351
+          },
+          Tags: {
+            title: "search-tags",
+            type: kInputTypes.BUTTON,
+            callback: () => console.log("Tags success!"), // FIXME: Bug 1563351
+          },
+          Titles: {
+            title: "search-titles",
+            type: kInputTypes.BUTTON,
+            callback: () => console.log("Titles success!"), // FIXME: Bug 1563351
+          },
+        },
+      },
+    },
+  },
 };
 
 const kHelperObservers = new Set([
   "bookmark-icon-updated",
   "reader-mode-available",
   "touchbar-location-change",
   "quit-application",
   "intl:app-locales-changed",
@@ -177,19 +219,23 @@ const kHelperObservers = new Set([
  * JS-implemented TouchBarHelper class.
  * Provides services to the Mac Touch Bar.
  */
 class TouchBarHelper {
   constructor() {
     for (let topic of kHelperObservers) {
       Services.obs.addObserver(this, topic);
     }
+    // We cache our search popover since otherwise it is frequently
+    // created/destroyed for the urlbar-focus/blur events.
+    this._searchPopover = this.getTouchBarInput("SearchPopover");
   }
 
   destructor() {
+    this._searchPopover = null;
     for (let topic of kHelperObservers) {
       Services.obs.removeObserver(this, topic);
     }
   }
 
   get activeTitle() {
     let tabbrowser = TouchBarHelper.window.ownerGlobal.gBrowser;
     let activeTitle;
@@ -217,23 +263,31 @@ class TouchBarHelper {
 
     return layoutItems;
   }
 
   static get window() {
     return BrowserWindowTracker.getTopWindow();
   }
 
+  get isUrlbarFocused() {
+    return TouchBarHelper.window.gURLBar.focused;
+  }
+
   static get baseWindow() {
     return TouchBarHelper.window.docShell.treeOwner.QueryInterface(
       Ci.nsIBaseWindow
     );
   }
 
   getTouchBarInput(inputName) {
+    if (inputName == "SearchPopover" && this._searchPopover) {
+      return this._searchPopover;
+    }
+
     // inputName might be undefined if an input's context() returns undefined.
     if (!inputName || !kBuiltInInputs.hasOwnProperty(inputName)) {
       return null;
     }
 
     // context() may specify that one named input "point" to another.
     if (typeof kBuiltInInputs[inputName].context == "function") {
       inputName = kBuiltInInputs[inputName].context();
@@ -315,18 +369,39 @@ class TouchBarHelper {
           : (kBuiltInInputs.AddBookmark.image =
               "chrome://browser/skin/bookmark-hollow.svg");
         this._updateTouchBarInputs("AddBookmark");
         break;
       case "reader-mode-available":
         kBuiltInInputs.ReaderView.disabled = false;
         this._updateTouchBarInputs("ReaderView");
         break;
+      case "urlbar-focus":
+        if (!this._searchPopover) {
+          this._searchPopover = this.getTouchBarInput("SearchPopover");
+        }
+        gTouchBarUpdater.showPopover(
+          TouchBarHelper.baseWindow,
+          this._searchPopover,
+          true
+        );
+        break;
+      case "urlbar-blur":
+        if (!this._searchPopover) {
+          this._searchPopover = this.getTouchBarInput("SearchPopover");
+        }
+        gTouchBarUpdater.showPopover(
+          TouchBarHelper.baseWindow,
+          this._searchPopover,
+          false
+        );
+        break;
       case "intl:app-locales-changed":
         // On locale change, refresh all inputs after loading new localTitle.
+        this._searchPopover = null;
         for (let input in kBuiltInInputs) {
           delete input.localTitle;
         }
         this._updateTouchBarInputs(...kBuiltInInputs.keys());
         break;
       case "quit-application":
         this.destructor();
         break;
--- a/browser/components/urlbar/UrlbarInput.jsm
+++ b/browser/components/urlbar/UrlbarInput.jsm
@@ -1769,16 +1769,18 @@ class UrlbarInput {
     if (!UrlbarPrefs.get("ui.popup.disable_autohide")) {
       this.view.close();
     }
 
     // We may have hidden popup notifications, show them again if necessary.
     if (this.getAttribute("pageproxystate") != "valid") {
       this.window.UpdatePopupNotificationsVisibility();
     }
+
+    Services.obs.notifyObservers(null, "urlbar-blur");
   }
 
   _on_click(event) {
     if (
       event.target == this.inputField ||
       event.target == this._inputContainer
     ) {
       this.startLayoutExtend();
@@ -1809,16 +1811,18 @@ class UrlbarInput {
 
     this._updateUrlTooltip();
     this.formatValue();
 
     // Hide popup notifications, to reduce visual noise.
     if (this.getAttribute("pageproxystate") != "valid") {
       this.window.UpdatePopupNotificationsVisibility();
     }
+
+    Services.obs.notifyObservers(null, "urlbar-focus");
   }
 
   _on_mouseover(event) {
     this._updateUrlTooltip();
   }
 
   _on_mousedown(event) {
     switch (event.currentTarget) {
--- a/browser/locales/en-US/browser/touchbar/touchbar.ftl
+++ b/browser/locales/en-US/browser/touchbar/touchbar.ftl
@@ -13,8 +13,22 @@ find = Find
 new-tab = New tab
 add-bookmark = Add bookmark
 reader-view = Reader View
 # Meant to match the string displayed in an empty URL bar.
 open-location = Search or enter address
 share = Share
 close-window = Close Window
 open-sidebar = Sidebars
+
+# This string describes shortcuts for search.
+search-popover = Search shortcuts
+# Describes searches limited to a specific scope
+# (e.g. searching only in history).
+search-search-in = Search in:
+## Various categories of shortcuts for search.
+
+search-bookmarks = Bookmarks
+search-history = History
+search-opentabs = Open Tabs
+search-tags = Tags
+search-titles = Titles
+##
--- a/widget/cocoa/nsTouchBar.mm
+++ b/widget/cocoa/nsTouchBar.mm
@@ -14,16 +14,22 @@
 
 static const NSTouchBarItemIdentifier BaseIdentifier = @"com.mozilla.firefox.touchbar";
 
 // Non-JS scrubber implemention for the Share Scrubber,
 // since it is defined by an Apple API.
 static NSTouchBarItemIdentifier ShareScrubberIdentifier =
     [TouchBarInput nativeIdentifierWithType:@"scrubber" withKey:@"share"];
 
+// The search popover needs to show/hide depending on if the Urlbar is focused
+// when it is created. We keep track of its identifier to accomodate this
+// special handling.
+static NSTouchBarItemIdentifier SearchPopoverIdentifier =
+    [TouchBarInput nativeIdentifierWithType:@"popover" withKey:@"search-popover"];
+
 // Used to tie action strings to buttons.
 static char sIdentifierAssociationKey;
 
 static const NSArray<NSString*>* kAllowedInputTypes = @[
   @"button",
   @"mainButton",
   @"scrubber",
   @"popover",
@@ -92,17 +98,17 @@ static const uint32_t kInputIconSize = 1
       self.customizationAllowedItemIdentifiers = [orderedIdentifiers copy];
 
       NSArray* defaultItemIdentifiers = @[
         [TouchBarInput nativeIdentifierWithType:@"button" withKey:@"back"],
         [TouchBarInput nativeIdentifierWithType:@"button" withKey:@"forward"],
         [TouchBarInput nativeIdentifierWithType:@"button" withKey:@"reload"],
         [TouchBarInput nativeIdentifierWithType:@"mainButton" withKey:@"open-location"],
         [TouchBarInput nativeIdentifierWithType:@"button" withKey:@"new-tab"],
-        ShareScrubberIdentifier
+        ShareScrubberIdentifier, SearchPopoverIdentifier
       ];
       self.defaultItemIdentifiers = [defaultItemIdentifiers copy];
     } else {
       NSMutableArray* defaultItemIdentifiers = [NSMutableArray arrayWithCapacity:[aInputs count]];
       for (TouchBarInput* input in aInputs) {
         self.mappedLayoutItems[[input nativeIdentifier]] = input;
         [defaultItemIdentifiers addObject:[input nativeIdentifier]];
       }
@@ -475,17 +481,20 @@ static const uint32_t kInputIconSize = 1
   mTouchBarHelper = nil;
 
   for (NSTouchBarItemIdentifier identifier in self.mappedLayoutItems) {
     TouchBarInput* input = self.mappedLayoutItems[identifier];
     if (!input) {
       continue;
     }
 
-    if ([[input type] hasSuffix:@"popover"]) {
+    // Childless popovers contain the default Touch Bar as its popoverTouchBar.
+    // We check for [input children] since the default Touch Bar contains a
+    // popover (search-popover), so this would infinitely loop if there was no check.
+    if ([[input type] hasSuffix:@"popover"] && [input children]) {
       NSTouchBarItem* item = [self itemForIdentifier:identifier];
       [(nsTouchBar*)[(NSPopoverTouchBarItem*)item popoverTouchBar] releaseJSObjects];
     }
 
     [input setCallback:nil];
     [input setDocument:nil];
     [input setImageURI:nil];
 
--- a/widget/nsITouchBarHelper.idl
+++ b/widget/nsITouchBarHelper.idl
@@ -18,16 +18,21 @@ interface nsITouchBarHelper : nsISupport
   readonly attribute AString activeUrl;
 
   /**
    * Return the active browser's page title.
    */
   readonly attribute AString activeTitle;
 
   /**
+   * Return true if the Urlbar has focus.
+   */
+  readonly attribute boolean isUrlbarFocused;
+
+  /**
    * Returns all available Touch Bar Inputs in an nsIArray
    * of nsITouchBarInput objects.
    */
   attribute nsIArray allItems;
 
   /**
    * Returns the requested TouchBarInput.
    * Exposed for testing.