Bug 1124400 - [ReadingList] Add section to bookmarks popup for reading list items and actions. r=Unfocused, a=lsblakk, l10n=comment-only
authorFlorian Quèze <florian@queze.net>
Mon, 23 Feb 2015 13:58:36 +0100
changeset 259071 3095f0eb1b3c
parent 259070 1304475d63b7
child 259072 e8f0fd3fbd3b
push id721
push userjlund@mozilla.com
push date2015-04-21 23:03 +0000
treeherdermozilla-release@d27c9211ebb3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersUnfocused, lsblakk
bugs1124400
milestone38.0a2
Bug 1124400 - [ReadingList] Add section to bookmarks popup for reading list items and actions. r=Unfocused, a=lsblakk, l10n=comment-only
browser/base/content/browser-menubar.inc
browser/base/content/browser-readinglist.js
browser/base/content/browser.js
browser/base/content/browser.xul
browser/components/customizableui/content/panelUI.inc.xul
browser/locales/en-US/chrome/browser/browser.dtd
browser/themes/linux/browser.css
browser/themes/linux/jar.mn
browser/themes/osx/browser.css
browser/themes/osx/jar.mn
browser/themes/shared/readinglist/readinglist-icon.svg
browser/themes/windows/browser.css
browser/themes/windows/jar.mn
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -439,16 +439,38 @@
         <menupopup id="bookmarksToolbarFolderPopup"
 #ifndef XP_MACOSX
                    placespopup="true"
 #endif
                    context="placesContext"
                    onpopupshowing="if (!this.parentNode._placesView)
                                      new PlacesMenu(event, 'place:folder=TOOLBAR');"/>
       </menu>
+#ifndef XP_MACOSX
+# Disabled on Mac because we can't fill native menupopups asynchronously
+      <menuseparator/>
+      <menu id="menu_readingList"
+            class="menu-iconic bookmark-item"
+            label="&readingList.label;"
+            container="true">
+        <observes element="readingListSidebar" attribute="hidden"/>
+        <menupopup id="readingListPopup"
+#ifndef XP_MACOSX
+                   placespopup="true"
+#endif
+                   onpopupshowing="ReadingListUI.onReadingListPopupShowing(this);">
+          <menuseparator id="viewReadingListSidebarSeparator"/>
+          <menuitem id="viewReadingListSidebar" class="subviewbutton"
+                    oncommand="SidebarUI.toggle('readingListSidebar');"
+                    label="&readingList.showSidebar.label;">
+            <observes element="readingListSidebar" attribute="checked"/>
+          </menuitem>
+        </menupopup>
+      </menu>
+#endif
       <menuseparator id="bookmarksMenuItemsSeparator"/>
       <!-- Bookmarks menu items -->
       <menuseparator builder="end"
                      class="hide-if-empty-places-result"/>
       <menuitem id="menu_unsortedBookmarks"
                 label="&unsortedBookmarksCmd.label;"
                 oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks');"/>
     </menupopup>
--- a/browser/base/content/browser-readinglist.js
+++ b/browser/base/content/browser-readinglist.js
@@ -1,14 +1,17 @@
 /*
 # 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, "ReadingList",
+  "resource:///modules/readinglist/ReadingList.jsm");
+
 let ReadingListUI = {
   /**
    * Initialize the ReadingList UI.
    */
   init() {
     Preferences.observe("browser.readinglist.enabled", this.updateUI, this);
     this.updateUI();
   },
@@ -60,9 +63,75 @@ let ReadingListUI = {
   /**
    * Hide the ReadingList sidebar, if it is currently shown.
    */
   hideSidebar() {
     if (this.isSidebarOpen) {
       SidebarUI.hide();
     }
   },
+
+  onReadingListPopupShowing(target) {
+    if (target.id == "BMB_readingListPopup") {
+      // Setting this class in the .xul file messes with the way
+      // browser-places.js inserts bookmarks in the menu.
+      document.getElementById("BMB_viewReadingListSidebar")
+              .classList.add("panel-subview-footer");
+    }
+
+    while (!target.firstChild.id)
+      target.firstChild.remove();
+
+    let classList = "menuitem-iconic bookmark-item menuitem-with-favicon";
+    let insertPoint = target.firstChild;
+    if (insertPoint.classList.contains("subviewbutton"))
+      classList += " subviewbutton";
+
+    ReadingList.getItems().then(items => {
+      for (let item of items) {
+        let menuitem = document.createElement("menuitem");
+        menuitem.setAttribute("label", item.title || item.url.spec);
+        menuitem.setAttribute("class", classList);
+
+        let node = menuitem._placesNode = {
+          // Passing the PlacesUtils.nodeIsURI check is required for the
+          // onCommand handler to load our URI.
+          type: Ci.nsINavHistoryResultNode.RESULT_TYPE_URI,
+
+          // makes PlacesUIUtils.canUserRemove return false.
+          // The context menu is broken without this.
+          parent: {type: Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER},
+
+          // A -1 id makes this item a non-bookmark, which avoids calling
+          // PlacesUtils.annotations.itemHasAnnotation to check if the
+          // bookmark should be opened in the sidebar (this call fails for
+          // readinglist item, and breaks loading our URI).
+          itemId: -1,
+
+          // Used by the tooltip and onCommand handlers.
+          uri: item.url.spec,
+
+          // Used by the tooltip.
+          title: item.title
+        };
+
+        Favicons.getFaviconURLForPage(item.url, uri => {
+          if (uri) {
+            menuitem.setAttribute("image",
+                                  Favicons.getFaviconLinkForIcon(uri).spec);
+          }
+        });
+
+        target.insertBefore(menuitem, insertPoint);
+      }
+
+      if (!items.length) {
+        let menuitem = document.createElement("menuitem");
+        let bundle =
+          Services.strings.createBundle("chrome://browser/locale/places/places.properties");
+        menuitem.setAttribute("label", bundle.GetStringFromName("bookmarksMenuEmptyFolder"));
+        menuitem.setAttribute("class", "bookmark-item");
+        menuitem.setAttribute("disabled", true);
+        target.insertBefore(menuitem, insertPoint);
+      }
+    });
+  }
 };
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -32,16 +32,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "GMPInstallManager",
                                   "resource://gre/modules/GMPInstallManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
                                   "resource://gre/modules/NewTabUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
                                   "resource:///modules/ContentSearch.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AboutHome",
                                   "resource:///modules/AboutHome.jsm");
+XPCOMUtils.defineLazyServiceGetter(this, "Favicons",
+                                   "@mozilla.org/browser/favicon-service;1",
+                                   "mozIAsyncFavicons");
 XPCOMUtils.defineLazyServiceGetter(this, "gDNSService",
                                    "@mozilla.org/network/dns-service;1",
                                    "nsIDNSService");
 
 const nsIWebNavigation = Ci.nsIWebNavigation;
 
 var gLastBrowserCharset = null;
 var gProxyFavIcon = null;
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -945,16 +945,32 @@
                   container="true">
               <menupopup id="BMB_unsortedBookmarksPopup"
                          placespopup="true"
                          context="placesContext"
                          onpopupshowing="if (!this.parentNode._placesView)
                                            new PlacesMenu(event, 'place:folder=UNFILED_BOOKMARKS',
                                                           PlacesUIUtils.getViewForNode(this.parentNode.parentNode).options);"/>
             </menu>
+            <menuseparator>
+              <observes element="readingListSidebar" attribute="hidden"/>
+            </menuseparator>
+            <menu id="BMB_readingList"
+                  class="menu-iconic bookmark-item subviewbutton"
+                  label="&readingList.label;"
+                  container="true">
+              <observes element="readingListSidebar" attribute="hidden"/>
+              <menupopup id="BMB_readingListPopup"
+                         placespopup="true"
+                         onpopupshowing="ReadingListUI.onReadingListPopupShowing(this);">
+                <menuitem id="BMB_viewReadingListSidebar" class="subviewbutton"
+                          oncommand="SidebarUI.show('readingListSidebar');"
+                          label="&readingList.showSidebar.label;"/>
+              </menupopup>
+            </menu>
             <menuseparator/>
             <!-- Bookmarks menu items will go here -->
             <menuitem id="BMB_bookmarksShowAll"
                       class="subviewbutton panel-subview-footer"
                       label="&showAllBookmarks2.label;"
                       command="Browser:ShowAllBookmarks"
                       key="manBookmarkKb"/>
           </menupopup>
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -121,16 +121,27 @@
         <toolbarbutton id="panelMenu_bookmarksToolbar"
                        label="&personalbarCmd.label;"
                        class="subviewbutton cui-withicon"
                        oncommand="PlacesCommandHook.showPlacesOrganizer('BookmarksToolbar'); PanelUI.hide();"/>
         <toolbarbutton id="panelMenu_unsortedBookmarks"
                        label="&unsortedBookmarksCmd.label;"
                        class="subviewbutton cui-withicon"
                        oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks'); PanelUI.hide();"/>
+        <toolbarseparator>
+          <observes element="readingListSidebar" attribute="hidden"/>
+        </toolbarseparator>
+        <toolbarbutton id="panelMenu_viewReadingListSidebar"
+                       label="&readingList.showSidebar.label;"
+                       class="subviewbutton"
+                       key="key_readingListSidebar"
+                       oncommand="SidebarUI.toggle('readingListSidebar'); PanelUI.hide();">
+          <observes element="readingListSidebar" attribute="checked"/>
+          <observes element="readingListSidebar" attribute="hidden"/>
+        </toolbarbutton>
         <toolbarseparator class="small-separator"/>
         <toolbaritem id="panelMenu_bookmarksMenu"
                      orient="vertical"
                      smoothscroll="false"
                      onclick="if (event.button == 1) BookmarkingUI.onPanelMenuViewCommand(event, this._placesView);"
                      oncommand="BookmarkingUI.onPanelMenuViewCommand(event, this._placesView);"
                      flatList="true"
                      tooltip="bhTooltip">
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -842,17 +842,16 @@ just addresses the organization to follo
 <!ENTITY emeLearnMoreContextMenu.accesskey        "D">
 <!ENTITY emeNotificationsNotNow.label             "Not now">
 <!ENTITY emeNotificationsNotNow.accesskey         "N">
 <!ENTITY emeNotificationsDontAskAgain.label       "Don't ask me again">
 <!ENTITY emeNotificationsDontAskAgain.accesskey   "D">
 
 <!ENTITY readingList.label                        "Reading List">
 <!ENTITY readingList.sidebar.commandKey           "R">
-<!-- Pre-landed string for bug 1124400 -->
 <!ENTITY readingList.showSidebar.label            "Show Reading List Sidebar">
 <!-- Pre-landed string for bug 1124153 -->
 <!ENTITY readingList.sidebar.showMore.label       "Show moreā€¦">
 <!-- Pre-landed string for bug 1133662 -->
 <!ENTITY readingList.sidebar.emptyText            "Add articles to your Reading List to save them for later and find them easily when you need them.">
 <!-- Pre-landed string for bug 1123525 -->
 <!ENTITY readingList.sidebar.delete.tooltip       "Remove this from your Reading List">
 <!-- Pre-landed strings for bug 1123519 -->
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -513,16 +513,21 @@ menuitem:not([type]):not(.menuitem-toolt
   list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png");
 }
 
 #BMB_unsortedBookmarks,
 #panelMenu_unsortedBookmarks {
   list-style-image: url("chrome://browser/skin/places/unsortedBookmarks.png");
 }
 
+#menu_readingList,
+#BMB_readingList {
+  list-style-image: url("chrome://browser/skin/readinglist/readinglist-icon.svg");
+}
+
 #menu_openDownloads {
   list-style-image: url("chrome://browser/skin/Toolbar-small.png");
   -moz-image-region: rect(0px 16px 16px 0px);
 }
 
 #menu_openAddons {
   list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.png");
 }
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -86,16 +86,17 @@ browser.jar:
   skin/classic/browser/Toolbar-inverted.png
   skin/classic/browser/Toolbar-small.png
   skin/classic/browser/undoCloseTab.png                        (../shared/undoCloseTab.png)
   skin/classic/browser/urlbar-arrow.png
   skin/classic/browser/session-restore.svg                  (../shared/incontent-icons/session-restore.svg)
   skin/classic/browser/tab-crashed.svg                      (../shared/incontent-icons/tab-crashed.svg)
   skin/classic/browser/welcome-back.svg                     (../shared/incontent-icons/welcome-back.svg)
   skin/classic/browser/reader-mode-16.png             (../shared/reader/reader-mode-16.png)
+  skin/classic/browser/readinglist/readinglist-icon.svg (../shared/readinglist/readinglist-icon.svg)
   skin/classic/browser/readinglist/sidebar.css        (../shared/readinglist/sidebar.css)
   skin/classic/browser/webRTC-shareDevice-16.png
   skin/classic/browser/webRTC-shareDevice-64.png
   skin/classic/browser/webRTC-sharingDevice-16.png    (../shared/webrtc/webRTC-sharingDevice-16.png)
   skin/classic/browser/webRTC-shareMicrophone-16.png
   skin/classic/browser/webRTC-shareMicrophone-64.png
   skin/classic/browser/webRTC-sharingMicrophone-16.png (../shared/webrtc/webRTC-sharingMicrophone-16.png)
   skin/classic/browser/webRTC-shareScreen-16.png      (../shared/webrtc/webRTC-shareScreen-16.png)
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -558,16 +558,21 @@ toolbarpaletteitem[place="palette"] > #p
     list-style-image: url("chrome://browser/skin/places/bookmarksToolbar@2x.png");
   }
 
   #BMB_unsortedBookmarks {
     list-style-image: url("chrome://browser/skin/places/unfiledBookmarks@2x.png");
   }
 }
 
+/* #menu_readingList, svg icons don't work in the mac native menubar */
+#BMB_readingList {
+  list-style-image: url("chrome://browser/skin/readinglist/readinglist-icon.svg");
+}
+
 /* ----- PRIMARY TOOLBAR BUTTONS ----- */
 
 toolbar .toolbarbutton-1:not([type="menu-button"]),
 .toolbarbutton-1 > .toolbarbutton-menubutton-button,
 .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
   -moz-box-orient: vertical;
   height: 24px;
   padding: 0;
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -137,16 +137,17 @@ browser.jar:
   skin/classic/browser/urlbar-arrow@2x.png
   skin/classic/browser/urlbar-popup-blocked.png
   skin/classic/browser/urlbar-popup-blocked@2x.png
   skin/classic/browser/session-restore.svg            (../shared/incontent-icons/session-restore.svg)
   skin/classic/browser/tab-crashed.svg                (../shared/incontent-icons/tab-crashed.svg)
   skin/classic/browser/welcome-back.svg               (../shared/incontent-icons/welcome-back.svg)
   skin/classic/browser/reader-mode-16.png             (../shared/reader/reader-mode-16.png)
   skin/classic/browser/reader-mode-16@2x.png          (../shared/reader/reader-mode-16@2x.png)
+  skin/classic/browser/readinglist/readinglist-icon.svg (../shared/readinglist/readinglist-icon.svg)
   skin/classic/browser/readinglist/sidebar.css        (../shared/readinglist/sidebar.css)
   skin/classic/browser/webRTC-shareDevice-16.png
   skin/classic/browser/webRTC-shareDevice-16@2x.png
   skin/classic/browser/webRTC-shareDevice-64.png
   skin/classic/browser/webRTC-shareDevice-64@2x.png
   skin/classic/browser/webRTC-sharingDevice-16.png    (../shared/webrtc/webRTC-sharingDevice-16.png)
   skin/classic/browser/webRTC-sharingDevice-16@2x.png (../shared/webrtc/webRTC-sharingDevice-16@2x.png)
   skin/classic/browser/webRTC-shareMicrophone-16.png
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/readinglist/readinglist-icon.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16">
+  <rect x="4.8" y="6.4" fill="#808080" width="11.2" height="3.2"/>
+  <rect x="4.8" y="11.2" fill="#808080" width="11.2" height="3.2"/>
+  <rect x="4.8" y="1.6" fill="#808080" width="11.2" height="3.2"/>
+  <circle fill="#808080" cx="1.6" cy="3.2" r="1.6"/>
+  <circle fill="#808080" cx="1.6" cy="8" r="1.6"/>
+  <circle fill="#808080" cx="1.6" cy="12.8" r="1.6"/>
+</svg>
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -2521,16 +2521,22 @@ notification[value="translation"] {
 }
 
 #BMB_unsortedBookmarks,
 #panelMenu_unsortedBookmarks {
   list-style-image: url("chrome://browser/skin/places/unsortedBookmarks.png");
   -moz-image-region: auto;
 }
 
+#menu_readingList,
+#BMB_readingList {
+  list-style-image: url("chrome://browser/skin/readinglist/readinglist-icon.svg");
+  -moz-image-region: auto;
+}
+
 /* ::::: Keyboard UI Panel ::::: */
 
 .KUI-panel {
   -moz-appearance: none;
   background: rgba(27%,27%,27%,.9) url(KUI-background.png) repeat-x;
   color: white;
   border-style: none;
   border-radius: 20px;
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -105,16 +105,17 @@ browser.jar:
         skin/classic/browser/undoCloseTab@2x.png                     (../shared/undoCloseTab@2x.png)
         skin/classic/browser/urlbar-arrow.png
         skin/classic/browser/urlbar-popup-blocked.png
         skin/classic/browser/urlbar-history-dropmarker.png
         skin/classic/browser/session-restore.svg                     (../shared/incontent-icons/session-restore.svg)
         skin/classic/browser/tab-crashed.svg                         (../shared/incontent-icons/tab-crashed.svg)
         skin/classic/browser/welcome-back.svg                        (../shared/incontent-icons/welcome-back.svg)
         skin/classic/browser/reader-mode-16.png                      (../shared/reader/reader-mode-16.png)
+        skin/classic/browser/readinglist/readinglist-icon.svg        (../shared/readinglist/readinglist-icon.svg)
         skin/classic/browser/readinglist/sidebar.css                 (../shared/readinglist/sidebar.css)
         skin/classic/browser/notification-pluginNormal.png           (../shared/plugins/notification-pluginNormal.png)
         skin/classic/browser/notification-pluginAlert.png            (../shared/plugins/notification-pluginAlert.png)
         skin/classic/browser/notification-pluginBlocked.png          (../shared/plugins/notification-pluginBlocked.png)
         skin/classic/browser/webRTC-shareDevice-16.png
         skin/classic/browser/webRTC-shareDevice-64.png
         skin/classic/browser/webRTC-sharingDevice-16.png             (../shared/webrtc/webRTC-sharingDevice-16.png)
         skin/classic/browser/webRTC-shareMicrophone-16.png
@@ -571,16 +572,17 @@ browser.jar:
         skin/classic/aero/browser/undoCloseTab@2x.png                     (../shared/undoCloseTab@2x.png)
         skin/classic/aero/browser/urlbar-arrow.png
         skin/classic/aero/browser/urlbar-popup-blocked.png
         skin/classic/aero/browser/urlbar-history-dropmarker.png
         skin/classic/aero/browser/session-restore.svg               (../shared/incontent-icons/session-restore.svg)
         skin/classic/aero/browser/tab-crashed.svg                   (../shared/incontent-icons/tab-crashed.svg)
         skin/classic/aero/browser/welcome-back.svg                  (../shared/incontent-icons/welcome-back.svg)
         skin/classic/aero/browser/reader-mode-16.png                (../shared/reader/reader-mode-16.png)
+        skin/classic/aero/browser/readinglist/readinglist-icon.svg  (../shared/readinglist/readinglist-icon.svg)
         skin/classic/aero/browser/readinglist/sidebar.css           (../shared/readinglist/sidebar.css)
         skin/classic/aero/browser/notification-pluginNormal.png     (../shared/plugins/notification-pluginNormal.png)
         skin/classic/aero/browser/notification-pluginAlert.png      (../shared/plugins/notification-pluginAlert.png)
         skin/classic/aero/browser/notification-pluginBlocked.png    (../shared/plugins/notification-pluginBlocked.png)
         skin/classic/aero/browser/webRTC-shareDevice-16.png
         skin/classic/aero/browser/webRTC-shareDevice-64.png
         skin/classic/aero/browser/webRTC-sharingDevice-16.png             (../shared/webrtc/webRTC-sharingDevice-16.png)
         skin/classic/aero/browser/webRTC-shareMicrophone-16.png