Bug 1354536 - Part 3 - When the Library view is shown, populate a new 'Recent Highlights' section with at most 12 items as in about:newtab. r=Gijs
authorMike de Boer <mdeboer@mozilla.com>
Tue, 19 Sep 2017 16:17:16 +0200
changeset 381653 df4f51e1809091f05384bf2a5e18512201b42416
parent 381652 ea4c53366f8dbedbe1c8d4bf717c6cfc9c09e591
child 381654 50d08bf45f3df9a5eacfc4531aafd85fd32875fd
push id32535
push userkwierso@gmail.com
push dateTue, 19 Sep 2017 21:06:08 +0000
treeherdermozilla-central@c0d1f9eb2a40 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGijs
bugs1354536
milestone57.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 1354536 - Part 3 - When the Library view is shown, populate a new 'Recent Highlights' section with at most 12 items as in about:newtab. r=Gijs MozReview-Commit-ID: Bs1RzL0uewH
browser/app/profile/firefox.js
browser/base/content/browser.css
browser/components/customizableui/content/panelUI.inc.xul
browser/components/customizableui/content/panelUI.js
browser/themes/shared/customizableui/panelUI.inc.css
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1271,16 +1271,18 @@ pref("browser.newtabpage.columns", 5);
 // directory tiles download URL
 pref("browser.newtabpage.directory.source", "https://tiles.services.mozilla.com/v3/links/fetch/%LOCALE%/%CHANNEL%");
 
 // activates Activity Stream
 pref("browser.newtabpage.activity-stream.enabled", true);
 pref("browser.newtabpage.activity-stream.prerender", true);
 pref("browser.newtabpage.activity-stream.aboutHome.enabled", true);
 
+pref("browser.library.activity-stream.enabled", true);
+
 // Enable the DOM fullscreen API.
 pref("full-screen-api.enabled", true);
 
 // Startup Crash Tracking
 // number of startup crashes that can occur before starting into safe mode automatically
 // (this pref has no effect if more than 6 hours have passed since the last crash)
 pref("toolkit.startup.max_resumed_crashes", 3);
 
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -500,16 +500,17 @@ toolbar:not(#TabsToolbar) > #personal-bo
 
 #PanelUI-feeds > .feed-toolbarbutton:-moz-locale-dir(rtl) {
   direction: rtl;
 }
 
 #appMenu_historyMenu > .bookmark-item,
 #appMenu-library-recentlyClosedTabs > .panel-subview-body > .bookmark-item,
 #appMenu-library-recentlyClosedWindows > .panel-subview-body > .bookmark-item,
+#appMenu-library-recentHighlights > .bookmark-item,
 #panelMenu_bookmarksMenu > .bookmark-item {
   max-width: none;
 }
 
 #main-window:-moz-lwtheme {
   background-repeat: no-repeat;
   background-position: top right;
 }
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -716,16 +716,26 @@
                        label="&libraryDownloads.label;"
                        closemenu="none"
                        oncommand="DownloadsSubview.show(this);"/>
         <toolbarbutton id="appMenu-library-remotetabs-button"
                        class="subviewbutton subviewbutton-iconic subviewbutton-nav"
                        label="&appMenuRemoteTabs.label;"
                        closemenu="none"
                        oncommand="PanelUI.showSubView('PanelUI-remotetabs', this)"/>
+        <toolbarseparator/>
+        <label value="&appMenuRecentHighlights.label;"
+               class="subview-subheader"/>
+        <toolbaritem id="appMenu-library-recentHighlights"
+                     orient="vertical"
+                     smoothscroll="false"
+                     flatList="true"
+                     tooltip="bhTooltip">
+          <!-- Recent Highlights will go here -->
+        </toolbaritem>
       </vbox>
     </panelview>
 
     <panelview id="PanelUI-bookmarkingTools" class="PanelUI-subView">
       <vbox class="panel-subview-body">
         <toolbarbutton id="panelMenu_toggleBookmarksMenu"
                        label="&addBookmarksMenu.label;"
                        label-checked="&removeBookmarksMenu.label;"
--- a/browser/components/customizableui/content/panelUI.js
+++ b/browser/components/customizableui/content/panelUI.js
@@ -1,16 +1,18 @@
 /* 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/. */
 
+XPCOMUtils.defineLazyModuleGetter(this, "AppMenuNotifications",
+                                  "resource://gre/modules/AppMenuNotifications.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
+                                  "resource://gre/modules/NewTabUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ScrollbarSampler",
                                   "resource:///modules/ScrollbarSampler.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "AppMenuNotifications",
-                                  "resource://gre/modules/AppMenuNotifications.jsm");
 
 /**
  * Maintains the state and dispatches events for the main menu panel.
  */
 
 const PanelUI = {
   /** Panel events that we listen for. **/
   get kEvents() {
@@ -20,16 +22,17 @@ const PanelUI = {
    * Used for lazily getting and memoizing elements from the document. Lazy
    * getters are set in init, and memoizing happens after the first retrieval.
    */
   get kElements() {
     return {
       mainView: "appMenu-mainView",
       multiView: "appMenu-multiView",
       helpView: "PanelUI-helpView",
+      libraryView: "appMenu-libraryView",
       menuButton: "PanelUI-menu-button",
       panel: "appMenu-popup",
       notificationPanel: "appMenu-notification-popup",
       addonNotificationContainer: "appMenu-addon-banners",
       overflowFixedList: "widget-overflow-fixed-list",
       overflowPanel: "widget-overflow",
       navbar: "nav-bar",
     };
@@ -70,16 +73,22 @@ const PanelUI = {
 
     if (this.autoHideToolbarInFullScreen) {
       window.addEventListener("fullscreen", this);
     } else {
       window.addEventListener("MozDOMFullscreen:Entered", this);
       window.addEventListener("MozDOMFullscreen:Exited", this);
     }
 
+    XPCOMUtils.defineLazyPreferenceGetter(this, "libraryRecentHighlightsEnabled",
+      "browser.library.activity-stream.enabled", false, (pref, previousValue, newValue) => {
+        if (!newValue)
+          this.clearLibraryRecentHighlights();
+      });
+
     window.addEventListener("activate", this);
     window.matchMedia("(-moz-overlay-scrollbars)").addListener(this._overlayScrollListenerBoundFn);
     CustomizableUI.addListener(this);
 
     for (let event of this.kEvents) {
       this.notificationPanel.addEventListener(event, this);
     }
 
@@ -145,16 +154,17 @@ const PanelUI = {
     window.removeEventListener("MozDOMFullscreen:Exited", this);
     window.removeEventListener("fullscreen", this);
     window.removeEventListener("activate", this);
     this.menuButton.removeEventListener("mousedown", this);
     this.menuButton.removeEventListener("keypress", this);
     window.matchMedia("(-moz-overlay-scrollbars)").removeListener(this._overlayScrollListenerBoundFn);
     CustomizableUI.removeListener(this);
     this._overlayScrollListenerBoundFn = null;
+    this.libraryView.removeEventListener("ViewShowing", this);
   },
 
   /**
    * Customize mode extracts the mainView and puts it somewhere else while the
    * user customizes. Upon completion, this function can be called to put the
    * panel back to where it belongs in normal browsing mode.
    *
    * @param aMainView
@@ -288,16 +298,21 @@ const PanelUI = {
         this.toggle(aEvent);
         break;
       case "MozDOMFullscreen:Entered":
       case "MozDOMFullscreen:Exited":
       case "fullscreen":
       case "activate":
         this._updateNotifications();
         break;
+      case "ViewShowing":
+        if (aEvent.target == this.libraryView) {
+          this.onLibraryViewShowing(aEvent.target);
+        }
+        break;
     }
   },
 
   get isReady() {
     return !!this._isReady;
   },
 
   get isNotificationPanelOpen() {
@@ -379,16 +394,18 @@ const PanelUI = {
       return;
     }
 
     if (!aAnchor) {
       Cu.reportError("Expected an anchor when opening subview with id: " + aViewId);
       return;
     }
 
+    this.ensureLibraryInitialized(viewNode);
+
     let container = aAnchor.closest("panelmultiview,photonpanelmultiview");
     if (container) {
       container.showSubView(aViewId, aAnchor);
     } else if (!aAnchor.open) {
       aAnchor.open = true;
 
       let tempPanel = document.createElement("panel");
       tempPanel.setAttribute("type", "arrow");
@@ -477,16 +494,105 @@ const PanelUI = {
       tempPanel.openPopup(anchor, {
         position: "bottomcenter topright",
         triggerEvent: domEvent,
       });
     }
   },
 
   /**
+   * Sets up the event listener for when the Library view is shown.
+   *
+   * @param {panelview} viewNode The library view.
+   */
+  ensureLibraryInitialized(viewNode) {
+    if (viewNode != this.libraryView || viewNode._initialized)
+      return;
+
+    viewNode._initialized = true;
+    viewNode.addEventListener("ViewShowing", this);
+  },
+
+  /**
+   * When the Library view is showing, we can start fetching and populating the
+   * list of Recent Highlights.
+   * This is done asynchronously and may finish when the view is already visible.
+   *
+   * @param {panelview} viewNode The library view.
+   */
+  async onLibraryViewShowing(viewNode) {
+    if (this._loadingRecentHighlights) {
+      return;
+    }
+    this._loadingRecentHighlights = true;
+
+    // Since the library is the first view shown, we don't want to add a blocker
+    // to the event, which would make PanelMultiView wait to show it.
+    let container = this.clearLibraryRecentHighlights();
+    if (!this.libraryRecentHighlightsEnabled) {
+      this._loadingRecentHighlights = false;
+      return;
+    }
+
+    let highlights = await NewTabUtils.activityStreamLinks.getHighlights({ withFavicons: true });
+    // If there's nothing to display, or the panel is already hidden, get out.
+    if (!highlights.length || viewNode.panelMultiView.getAttribute("panelopen") != "true") {
+      this._loadingRecentHighlights = false;
+      return;
+    }
+
+    container.hidden = container.previousSibling.hidden =
+      container.previousSibling.previousSibling.hidden = false;
+    let fragment = document.createDocumentFragment();
+    for (let highlight of highlights) {
+      let button = document.createElement("toolbarbutton");
+      button.classList.add("subviewbutton", "highlight", "subviewbutton-iconic", "bookmark-item");
+      let title = highlight.title || highlight.url;
+      button.setAttribute("label", title);
+      button.setAttribute("tooltiptext", title);
+      button.setAttribute("type", "highlight-" + highlight.type);
+      button.setAttribute("onclick", "PanelUI.onLibraryHighlightClick(event)");
+      if (highlight.favicon) {
+        button.setAttribute("image", highlight.favicon);
+      }
+      button._highlight = highlight;
+      fragment.appendChild(button);
+    }
+    container.appendChild(fragment);
+
+    this._loadingRecentHighlights = false;
+  },
+
+  /**
+   * Remove all the nodes from the 'Recent Highlights' section and hide it as well.
+   */
+  clearLibraryRecentHighlights() {
+    let container = document.getElementById("appMenu-library-recentHighlights")
+    while (container.firstChild) {
+      container.firstChild.remove();
+    }
+    container.hidden = container.previousSibling.hidden =
+      container.previousSibling.previousSibling.hidden = true;
+    return container;
+  },
+
+  /**
+   * Event handler; invoked when an item of the Recent Highlights is clicked.
+   *
+   * @param {MouseEvent} event Click event, originating from the Highlight.
+   */
+  onLibraryHighlightClick(event) {
+    let button = event.target;
+    if (event.button > 1 || !button._highlight) {
+      return;
+    }
+    window.openUILink(button._highlight.url, event);
+  },
+
+  /**
    * NB: The enable- and disableSingleSubviewPanelAnimations methods only
    * affect the hiding/showing animations of single-subview panels (tempPanel
    * in the showSubView method).
    */
   disableSingleSubviewPanelAnimations() {
     this._disableAnimations = true;
   },
 
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -1301,16 +1301,34 @@ panelview .toolbarbutton-1,
 }
 
 .subviewbutton[shortcut]::after,
 .subviewbutton[shortcut]::after,
 .PanelUI-subView .subviewbutton-nav::after {
   margin-inline-start: 10px;
 }
 
+.subviewbutton[type="highlight-bookmark"]::after {
+  content: url("chrome://browser/skin/bookmark-hollow.svg");
+}
+
+.subviewbutton[type="highlight-history"]::after {
+  content: url("chrome://browser/skin/history.svg");
+}
+
+.subviewbutton[type="highlight-bookmark"]::after,
+.subviewbutton[type="highlight-history"]::after {
+  -moz-context-properties: fill;
+  fill: GrayText;
+  float: right;
+  opacity: .5;
+  /* Centers the icon and resizes it to 12px square. */
+  transform: translateY(2px) scaleX(.75);
+}
+
 /* This is a <label> but it should fit in with the menu font- and colorwise. */
 #PanelUI-characterEncodingView-autodetect-label {
   font: menu;
   color: inherit;
 }
 
 /* START photon adjustments */