Bug 1162713 - Implement "Save Link to Pocket" context menu item. r+a=dolske, l10n=dolske
authorJared Wein <jwein@mozilla.com>
Thu, 14 May 2015 14:04:05 -0400
changeset 260518 e13a7a312aa5
parent 260517 ecbce7532a0a
child 260519 24524667128b
push id805
push userryanvm@gmail.com
push date2015-05-18 17:06 +0000
treeherdermozilla-release@4bfd19d00ed4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1162713
milestone38.0.5
Bug 1162713 - Implement "Save Link to Pocket" context menu item. r+a=dolske, l10n=dolske
browser/base/content/browser-context.inc
browser/base/content/browser-pocket-de.properties
browser/base/content/browser-pocket-es-ES.properties
browser/base/content/browser-pocket-ja.properties
browser/base/content/browser-pocket-ru.properties
browser/base/content/browser-pocket.dtd
browser/base/content/nsContextMenu.js
browser/components/pocket/Pocket.jsm
--- a/browser/base/content/browser-context.inc
+++ b/browser/base/content/browser-context.inc
@@ -74,16 +74,20 @@
       <menuitem id="context-sharelink"
                 label="&shareLink.label;"
                 accesskey="&shareLink.accesskey;"
                 oncommand="gContextMenu.shareLink();"/>
       <menuitem id="context-savelink"
                 label="&saveLinkCmd.label;"
                 accesskey="&saveLinkCmd.accesskey;"
                 oncommand="gContextMenu.saveLink();"/>
+      <menuitem id="context-savelinktopocket"
+                label="&saveLinkToPocketCmd.label;"
+                accesskey="&saveLinkToPocketCmd.accesskey;"
+                oncommand="gContextMenu.saveLinkToPocket();"/>
       <menu id="context-marklinkMenu" label="&social.marklinkMenu.label;"
             accesskey="&social.marklinkMenu.accesskey;">
         <menupopup/>
       </menu>
       <menuitem id="context-copyemail"
                 label="&copyEmailCmd.label;"
                 accesskey="&copyEmailCmd.accesskey;"
                 oncommand="gContextMenu.copyEmail();"/>
@@ -264,17 +268,17 @@
                 oncommand="SocialShare.sharePage();"/>
       <menuitem id="context-savepage"
                 label="&savePageCmd.label;"
                 accesskey="&savePageCmd.accesskey2;"
                 oncommand="gContextMenu.savePageAs();"/>
       <menuitem id="context-pocket"
                 label="&saveToPocketCmd.label;"
                 accesskey="&saveToPocketCmd.accesskey;"
-                oncommand="gContextMenu.saveToPocket();"/>
+                oncommand="gContextMenu.savePageToPocket();"/>
       <menu id="context-markpageMenu" label="&social.markpageMenu.label;"
             accesskey="&social.markpageMenu.accesskey;">
         <menupopup/>
       </menu>
       <menuseparator id="context-sep-viewbgimage"/>
       <menuitem id="context-viewbgimage"
                 label="&viewBGImageCmd.label;"
                 accesskey="&viewBGImageCmd.accesskey;"
--- a/browser/base/content/browser-pocket-de.properties
+++ b/browser/base/content/browser-pocket-de.properties
@@ -6,9 +6,11 @@
 # browser.properties in the usual L10N location.
 
 pocket-button.label = Pocket
 pocket-button.tooltiptext = Bei Pocket speichern
 
 # From browser-pocket.dtd
 saveToPocketCmd.label = Seite bei Pocket speichern
 saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Link in Pocket speichern
+saveLinkToPocketCmd.accesskey = o
 pocketMenuitem.label = Pocket-Liste anzeigen
--- a/browser/base/content/browser-pocket-es-ES.properties
+++ b/browser/base/content/browser-pocket-es-ES.properties
@@ -6,9 +6,11 @@
 # browser.properties in the usual L10N location.
 
 pocket-button.label = Pocket
 pocket-button.tooltiptext = Guardar en Pocket
 
 # From browser-pocket.dtd
 saveToPocketCmd.label = Guardar página en Pocket
 saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Guardar enlace en Pocket
+saveLinkToPocketCmd.accesskey = k
 pocketMenuitem.label = Ver lista de Pocket
--- a/browser/base/content/browser-pocket-ja.properties
+++ b/browser/base/content/browser-pocket-ja.properties
@@ -6,9 +6,11 @@
 # browser.properties in the usual L10N location.
 
 pocket-button.label = Pocket
 pocket-button.tooltiptext = Pocket に保存
 
 # From browser-pocket.dtd
 saveToPocketCmd.label = Pocket にページを保存
 saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Pocket にリンクを保存
+saveLinkToPocketCmd.accesskey = o
 pocketMenuitem.label = Pocket のマイリストを表示
--- a/browser/base/content/browser-pocket-ru.properties
+++ b/browser/base/content/browser-pocket-ru.properties
@@ -6,9 +6,11 @@
 # browser.properties in the usual L10N location.
 
 pocket-button.label = Pocket
 pocket-button.tooltiptext = Сохранить в Pocket
 
 # From browser-pocket.dtd
 saveToPocketCmd.label = Сохранить страницу в Pocket
 saveToPocketCmd.accesskey = х
+saveLinkToPocketCmd.label = Сохранить ссылку в Pocket
+saveLinkToPocketCmd.accesskey = P
 pocketMenuitem.label = Показать список Pocket
--- a/browser/base/content/browser-pocket.dtd
+++ b/browser/base/content/browser-pocket.dtd
@@ -2,9 +2,11 @@
    - 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/. -->
 
 <!-- This is a temporary file and not meant for localization; later versions
    - of Firefox include these strings in browser.dtd -->
 
 <!ENTITY saveToPocketCmd.label     "Save Page to Pocket">
 <!ENTITY saveToPocketCmd.accesskey "k">
+<!ENTITY saveLinkToPocketCmd.label     "Save Link to Pocket">
+<!ENTITY saveLinkToPocketCmd.accesskey "o">
 <!ENTITY pocketMenuitem.label      "View Pocket List">
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -1,16 +1,22 @@
 /* vim: set ts=2 sw=2 sts=2 et tw=80: */
 # 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/.
 
 Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm");
 Components.utils.import("resource://gre/modules/BrowserUtils.jsm");
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
+  "resource:///modules/CustomizableUI.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Pocket",
+  "resource:///modules/Pocket.jsm");
 
 var gContextMenuContentData = null;
 
 function nsContextMenu(aXulMenu, aIsShift) {
   this.shouldDisplay = true;
   this.initMenu(aXulMenu, aIsShift);
 }
 
@@ -224,46 +230,57 @@ nsContextMenu.prototype = {
     // to be already loaded, since we load it on startup in nsBrowserGlue,
     // and CastingApps isn't, so check SimpleServiceDiscovery.services first
     // to avoid needing to load CastingApps.jsm if we don't need to.
     shouldShowCast = shouldShowCast && this.mediaURL &&
                      SimpleServiceDiscovery.services.length > 0 &&
                      CastingApps.getServicesForVideo(this.target).length > 0;
     this.setItemAttr("context-castvideo", "disabled", !shouldShowCast);
 
-    let canPocket = false;
-    if (shouldShow && window.gBrowser &&
-        this.browser.getTabBrowser() == window.gBrowser) {
-      let uri = this.browser.currentURI;
-      canPocket =
-        CustomizableUI.getPlacementOfWidget("pocket-button") &&
-        (uri.schemeIs("http") || uri.schemeIs("https") ||
-         (uri.schemeIs("about") && ReaderMode.getOriginalUrl(uri.spec)));
-      if (canPocket) {
-        let locale = Cc["@mozilla.org/chrome/chrome-registry;1"].
-                     getService(Ci.nsIXULChromeRegistry).
-                     getSelectedLocale("browser");
-        if (locale != "en-US") {
-          if (locale == "ja-JP-mac")
-            locale = "ja";
-          let url = "chrome://browser/content/browser-pocket-" + locale + ".properties";
-          let bundle = Services.strings.createBundle(url);
-          let item = document.getElementById("context-pocket");
-          try {
-            item.setAttribute("label", bundle.GetStringFromName("saveToPocketCmd.label"));
-            item.setAttribute("accesskey", bundle.GetStringFromName("saveToPocketCmd.accesskey"));
-          } catch (err) {
-            // GetStringFromName throws when the bundle doesn't exist.  In that
-            // case, the item will retain the browser-pocket.dtd en-US string that
-            // it has in the markup.
-          }
+    this.initPocketItems();
+  },
+
+  initPocketItems: function CM_initPocketItems() {
+    var showSaveCurrentPageToPocket = !(this.onTextInput || this.onLink ||
+                                        this.isContentSelected || this.onImage ||
+                                        this.onCanvas || this.onVideo || this.onAudio);
+    let targetURI = (this.onSaveableLink || this.onPlainTextLink) ? this.linkURI : this.browser.currentURI;
+    let canPocket = CustomizableUI.getPlacementOfWidget("pocket-button") &&
+                    window.pktApi && window.pktApi.isUserLoggedIn();
+    canPocket = canPocket && (targetURI.schemeIs("http") || targetURI.schemeIs("https") ||
+                              (targetURI.schemeIs("about") && ReaderMode.getOriginalUrl(targetURI.spec)));
+    canPocket = canPocket && window.gBrowser && this.browser.getTabBrowser() == window.gBrowser;
+
+    if (canPocket) {
+      let locale = Cc["@mozilla.org/chrome/chrome-registry;1"].
+                   getService(Ci.nsIXULChromeRegistry).
+                   getSelectedLocale("browser");
+      if (locale != "en-US") {
+        if (locale == "ja-JP-mac")
+          locale = "ja";
+        let url = "chrome://browser/content/browser-pocket-" + locale + ".properties";
+        let bundle = Services.strings.createBundle(url);
+        let saveToPocketItem = document.getElementById("context-pocket");
+        let saveLinkToPocketItem = document.getElementById("context-savelinktopocket");
+        try {
+          saveToPocketItem.setAttribute("label", bundle.GetStringFromName("saveToPocketCmd.label"));
+          saveToPocketItem.setAttribute("accesskey", bundle.GetStringFromName("saveToPocketCmd.accesskey"));
+          saveLinkToPocketItem.setAttribute("label", bundle.GetStringFromName("saveLinkToPocketCmd.label"));
+          saveLinkToPocketItem.setAttribute("accesskey", bundle.GetStringFromName("saveLinkToPocketCmd.accesskey"));
+        } catch (err) {
+          // GetStringFromName throws when the bundle doesn't exist.  In that
+          // case, the item will retain the browser-pocket.dtd en-US string that
+          // it has in the markup.
         }
       }
     }
-    this.showItem("context-pocket", canPocket && window.pktApi && window.pktApi.isUserLoggedIn());
+    this.showItem("context-pocket", canPocket && showSaveCurrentPageToPocket);
+    let showSaveLinkToPocket = canPocket && !showSaveCurrentPageToPocket &&
+                               (this.onSaveableLink || this.onPlainTextLink);
+    this.showItem("context-savelinktopocket", showSaveLinkToPocket);
   },
 
   initViewItems: function CM_initViewItems() {
     // View source is always OK, unless in directory listing.
     this.showItem("context-viewpartialsource-selection",
                   this.isContentSelected);
     this.showItem("context-viewpartialsource-mathml",
                   this.onMathML && !this.isContentSelected);
@@ -1673,30 +1690,22 @@ nsContextMenu.prototype = {
   shareSelect: function CM_shareSelect(selection) {
     SocialShare.sharePage(null, { url: this.browser.currentURI.spec, text: selection }, this.target);
   },
 
   savePageAs: function CM_savePageAs() {
     saveDocument(this.browser.contentDocumentAsCPOW);
   },
 
-  saveToPocket: function CM_saveToPocket() {
-    let pocketWidget = document.getElementById("pocket-button");
-    let placement = CustomizableUI.getPlacementOfWidget("pocket-button");
-    if (!placement)
-      return;
+  saveLinkToPocket: function CM_saveLinkToPocket() {
+    Pocket.savePage(this.browser, this.linkURL);
+  },
 
-    if (placement.area == CustomizableUI.AREA_PANEL) {
-      PanelUI.show().then(function() {
-        pocketWidget = document.getElementById("pocket-button");
-        pocketWidget.doCommand();
-      });
-    } else {
-      pocketWidget.doCommand();
-    }
+  savePageToPocket: function CM_saveToPocket() {
+    Pocket.savePage(this.browser, this.browser.currentURI.spec, this.browser.contentTitle);
   },
 
   printFrame: function CM_printFrame() {
     PrintUtils.print(this.target.ownerDocument.defaultView);
   },
 
   switchPageDirection: function CM_switchPageDirection() {
     SwitchDocumentDirection(this.browser.contentWindowAsCPOW);
--- a/browser/components/pocket/Pocket.jsm
+++ b/browser/components/pocket/Pocket.jsm
@@ -22,24 +22,31 @@ let Pocket = {
   /**
    * Functions related to the Pocket panel UI.
    */
   onPanelViewShowing(event) {
     let document = event.target.ownerDocument;
     let window = document.defaultView;
     let iframe = document.getElementById('pocket-panel-iframe');
 
+    let urlToSave = Pocket._urlToSave;
+    let titleToSave = Pocket._titleToSave;
+    Pocket._urlToSave = null;
+    Pocket._titleToSave = null;
     // ViewShowing fires immediately before it creates the contents,
     // in lieu of an AfterViewShowing event, just spin the event loop.
     window.setTimeout(function() {
-      window.pktUI.pocketButtonOnCommand();
+      if (urlToSave) {
+        window.pktUI.tryToSaveUrl(urlToSave, titleToSave);
+      } else {
+        window.pktUI.pocketButtonOnCommand();
+      }
 
       if (iframe.contentDocument &&
-          iframe.contentDocument.readyState == "complete")
-      {
+          iframe.contentDocument.readyState == "complete") {
         window.pktUI.pocketPanelDidShow();
       } else {
         // iframe didn't load yet. This seems to always be the case when in
         // the toolbar panel, but never the case for a subview.
         // XXX this only being fired when it's a _capturing_ listener!
         iframe.addEventListener("load", Pocket.onFrameLoaded, true);
       }
     }, 0);
@@ -77,9 +84,31 @@ let Pocket = {
         node.disabled = win.pktApi.isUserLoggedIn() &&
                         !locationURI.schemeIs("http") &&
                         !locationURI.schemeIs("https") &&
                         !(locationURI.schemeIs("about") &&
                           locationURI.spec.toLowerCase().startsWith("about:reader?url="));
       }
     }
   },
+
+  _urlToSave: null,
+  _titleToSave: null,
+  savePage(browser, url, title) {
+    let document = browser.ownerDocument;
+    let pocketWidget = document.getElementById("pocket-button");
+    let placement = CustomizableUI.getPlacementOfWidget("pocket-button");
+    if (!placement)
+      return;
+
+    this._urlToSave = url;
+    this._titleToSave = title;
+    if (placement.area == CustomizableUI.AREA_PANEL) {
+      let win = document.defaultView;
+      win.PanelUI.show().then(function() {
+        pocketWidget = document.getElementById("pocket-button");
+        pocketWidget.doCommand();
+      });
+    } else {
+      pocketWidget.doCommand();
+    }
+  },
 };