Bug 1156878 - Send a request to the server when clicking the Pocket toolbar button, r=jaws.
authorFlorian Quèze <florian@queze.net>
Mon, 27 Apr 2015 11:49:21 +0200
changeset 260415 16e406d46c18
parent 260414 3e9805c11aa3
child 260416 1c86609b511c
push id776
push userjwein@mozilla.com
push date2015-05-07 17:59 +0000
treeherdermozilla-release@53b766c68811 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws
bugs1156878
milestone38.0
Bug 1156878 - Send a request to the server when clicking the Pocket toolbar button, r=jaws.
browser/app/profile/firefox.js
browser/components/customizableui/CustomizableWidgets.jsm
browser/components/customizableui/content/panelUI.inc.xul
browser/components/customizableui/content/panelUI.js
browser/components/pocket/Pocket.jsm
browser/components/pocket/moz.build
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1896,11 +1896,12 @@ pref("browser.readinglist.sidebarEverOpe
 pref("readinglist.scheduler.enabled", false);
 pref("readinglist.server", "https://readinglist.services.mozilla.com/v1");
 
 pref("browser.reader.detectedFirstArticle", false);
 // Don't limit how many nodes we care about on desktop:
 pref("reader.parse-node-limit", 0);
 
 pref("browser.pocket.enabled", false);
+pref("browser.pocket.hostname", "localhost");
 pref("browser.pocket.removedByUser", false);
 pref("browser.pocket.useLocaleList", true);
 pref("browser.pocket.enabledLocales", "en-US");
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -13,22 +13,26 @@ Cu.import("resource://gre/modules/XPCOMU
 XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
   "resource:///modules/BrowserUITelemetry.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUIUtils",
   "resource:///modules/PlacesUIUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "RecentlyClosedTabsAndWindowsMenuUtils",
   "resource:///modules/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Pocket",
+  "resource:///modules/Pocket.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils",
   "resource://gre/modules/ShortcutUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu",
   "resource://gre/modules/CharsetMenu.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode",
+  "resource://gre/modules/ReaderMode.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "CharsetBundle", function() {
   const kCharsetBundle = "chrome://global/locale/charsetMenu.properties";
   return Services.strings.createBundle(kCharsetBundle);
 });
 XPCOMUtils.defineLazyGetter(this, "BrandBundle", function() {
   const kBrandBundle = "chrome://branding/locale/brand.properties";
   return Services.strings.createBundle(kBrandBundle);
@@ -1121,31 +1125,55 @@ if (Services.prefs.getBoolPref("browser.
         addTagsField.addEventListener("input", this);
         addTagsButton.addEventListener("command", this);
       },
       onViewShowing(event) {
         let doc = event.target.ownerDocument;
 
         let loginView = doc.getElementById("pocket-login-required");
         let pageSavedView = doc.getElementById("pocket-page-saved");
-        let showPageSaved = Math.random() < 0.5;
-        loginView.hidden = !showPageSaved;
-        pageSavedView.hidden = showPageSaved;
+        let showPageSaved = Pocket.isLoggedIn;
+        loginView.hidden = showPageSaved;
+        pageSavedView.hidden = !showPageSaved;
+
+        if (!showPageSaved)
+          return;
+
+        let gBrowser = doc.defaultView.gBrowser;
+        let uri = gBrowser.currentURI;
+        if (uri.schemeIs("about"))
+          uri = ReaderMode.getOriginalUrl(uri.spec);
+        else
+          uri = uri.spec;
+        if (!uri)
+          return; //TODO should prevent the panel from showing
+
+        Pocket.save(uri, gBrowser.contentTitle).then(
+          item => {
+            doc.getElementById("pocket-remove-page").itemId = item.item_id;
+          },
+          error => {dump(error + "\n");}
+        );
+      },
+      onViewHiding(event) {
+        let doc = event.target.ownerDocument;
+        doc.getElementById("pocket-remove-page").itemId = null;
       },
 
       handleEvent: function(event) {
         let doc = event.target.ownerDocument;
         let field = doc.getElementById("pocket-page-tags-field");
         let button = doc.getElementById("pocket-page-tags-add");
         switch (event.type) {
           case "input":
             button.disabled = !field.value.trim();
             break;
           case "command":
-            //XXXjaws Send tag to the Pocket server
+            Pocket.tag(doc.getElementById("pocket-remove-page").itemId,
+                       field.value);
             field.value = "";
             break;
         }
       },
 
       USER_REMOVED_PREF: "browser.pocket.removedByUser",
       onWidgetAdded(aWidgetId, aArea, aPosition) {
         if (aWidgetId != this.id) {
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -241,17 +241,18 @@
           </description>
           <label id="pocket-account-question"/>
           <label id="pocket-login-now" class="text-link"/>
         </vbox>
         <vbox id="pocket-page-saved" hidden="true">
           <label id="pocket-page-saved-header" class="pocket-header"/>
           <hbox id="pocket-page-saved-next-steps" pack="center">
             <label id="pocket-open-pocket" class="text-link"/>
-            <label id="pocket-remove-page" class="text-link"/>
+            <label id="pocket-remove-page" class="text-link"
+                   onclick="Pocket.remove(this.itemId);"/>
           </hbox>
           <hbox id="pocket-separator">
             <box class="pocket-separator-colorstop"/>
             <box class="pocket-separator-colorstop"/>
             <box class="pocket-separator-colorstop"/>
             <box class="pocket-separator-colorstop"/>
           </hbox>
           <vbox id="pocket-page-tags">
--- a/browser/components/customizableui/content/panelUI.js
+++ b/browser/components/customizableui/content/panelUI.js
@@ -1,20 +1,23 @@
 /* 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, "CustomizableUI",
                                   "resource:///modules/CustomizableUI.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ScrollbarSampler",
                                   "resource:///modules/ScrollbarSampler.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Pocket",
+                                  "resource:///modules/Pocket.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
                                   "resource://gre/modules/Promise.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils",
                                   "resource://gre/modules/ShortcutUtils.jsm");
+
 /**
  * Maintains the state and dispatches events for the main menu panel.
  */
 
 const PanelUI = {
   /** Panel events that we listen for. **/
   get kEvents() ["popupshowing", "popupshown", "popuphiding", "popuphidden"],
   /**
@@ -399,17 +402,17 @@ const PanelUI = {
     }
     if (!aIsRemoval &&
         (this.panel.state == "open" ||
          document.documentElement.hasAttribute("customizing"))) {
       this._adjustLabelsForAutoHyphens(aNode);
     }
   },
 
-  /** 
+  /**
    * Signal that we're about to make a lot of changes to the contents of the
    * panels all at once. For performance, we ignore the mutations.
    */
   beginBatchUpdate: function() {
     this._ensureEventListenersAdded();
     this.multiView.ignoreMutations = true;
   },
 
@@ -522,9 +525,8 @@ function getLocale() {
 
   try {
     return Services.prefs.getCharPref(PREF_SELECTED_LOCALE);
   }
   catch (e) { }
 
   return "en-US";
 }
-
new file mode 100644
--- /dev/null
+++ b/browser/components/pocket/Pocket.jsm
@@ -0,0 +1,109 @@
+/* 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/. */
+
+"use strict";
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+this.EXPORTED_SYMBOLS = ["Pocket"];
+
+Cu.import("resource://gre/modules/Http.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+let Pocket = {
+  get isLoggedIn() {
+    return !!this._accessToken;
+  },
+
+  prefBranch: Services.prefs.getBranch("browser.pocket.settings."),
+
+  get hostname() Services.prefs.getCharPref("browser.pocket.hostname"),
+
+  get _accessToken() {
+    let sessionId, accessToken;
+    let cookies = Services.cookies.getCookiesFromHost(this.hostname);
+    while (cookies.hasMoreElements()) {
+      let cookie = cookies.getNext().QueryInterface(Ci.nsICookie2);
+      if (cookie.name == "ftv1")
+        accessToken = cookie.value;
+      else if (cookie.name == "fsv1")
+        sessionId = cookie.value;
+    }
+
+    if (!accessToken)
+      return null;
+
+    let lastSessionId;
+    try {
+      lastSessionId = this.prefBranch.getCharPref("sessionId");
+    } catch (e) { }
+    if (sessionId != lastSessionId)
+      this.prefBranch.deleteBranch("");
+    this.prefBranch.setCharPref("sessionId", sessionId);
+
+    return accessToken;
+  },
+
+  save(url, title) {
+    let since = "0";
+    try {
+      since = this.prefBranch.getCharPref("latestSince");
+    } catch (e) { }
+
+    let data = {url: url, since: since, title: title};
+
+    return new Promise((resolve, reject) => {
+      this._send("firefox/save", data,
+        data => {
+          this.prefBranch.setCharPref("latestSince", data.since);
+          resolve(data.item);
+        },
+        error => { reject(error); }
+      );
+    });
+  },
+
+  remove(itemId) {
+    let actions = [{ action: "delete", item_id: itemId }];
+    this._send("send", {actions: JSON.stringify(actions)});
+  },
+
+  tag(itemId, tags) {
+    let actions = [{ action: "tags_add", item_id: itemId, tags: tags }];
+    this._send("send", {actions: JSON.stringify(actions)});
+  },
+
+  _send(url, data, onSuccess, onError) {
+    let token = this._accessToken;
+    if (!token)
+      throw "Attempted to send a request to Pocket while not logged in";
+
+    let browserLocale = Cc["@mozilla.org/chrome/chrome-registry;1"]
+                          .getService(Ci.nsIXULChromeRegistry)
+                          .getSelectedLocale("browser");
+
+    let postData = [
+      ["access_token", token],
+      ["consumer_key", "40249-e88c401e1b1f2242d9e441c4"],
+      ["locale_lang", browserLocale]
+    ];
+
+    for (let key in data)
+      postData.push([key, data[key]]);
+
+    httpRequest("https://" + this.hostname + "/v3/" + url, {
+      headers: [["X-Accept", "application/json"]],
+      postData: postData,
+      onLoad: (responseText) => {
+        if (onSuccess)
+          onSuccess(JSON.parse(responseText));
+      },
+      onError: function(error, responseText, xhr) {
+        if (!onError)
+          return;
+        let errorMessage = xhr.getResponseHeader("X-Error");
+        onError(new Error(error + " - " + errorMessage));
+      }
+    });
+  }
+};
--- a/browser/components/pocket/moz.build
+++ b/browser/components/pocket/moz.build
@@ -1,5 +1,7 @@
-# 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/.
-
-JAR_MANIFESTS += ['jar.mn']
+# 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/.
+
+JAR_MANIFESTS += ['jar.mn']
+
+EXTRA_JS_MODULES += ['Pocket.jsm']