bug 853151 refactoring recommend into SocialMark, r=felipe
☠☠ backed out by ed39a9db0fb1 ☠ ☠
authorShane Caraveo <scaraveo@mozilla.com>
Wed, 24 Apr 2013 12:58:36 -0700
changeset 140790 8a9a40bfa8e3ad6c79333ec63a541dce0f503c44
parent 140789 f5adb2a4213572742ee737b50667acd8b87db333
child 140791 83a790e5acd8a9b1b4b1a13ee39b15a7adc751e1
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfelipe
bugs853151
milestone23.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 853151 refactoring recommend into SocialMark, r=felipe
browser/base/content/browser-context.inc
browser/base/content/browser-sets.inc
browser/base/content/browser-social.js
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/nsContextMenu.js
browser/base/content/test/social/Makefile.in
browser/base/content/test/social/browser_social_markButton.js
browser/base/content/test/social/browser_social_multiprovider.js
browser/base/content/test/social/browser_social_shareButton.js
browser/base/content/test/social/head.js
browser/base/content/test/social/social_mark_image.png
browser/base/content/test/social/social_share_image.png
browser/base/content/test/social/social_worker.js
browser/base/content/test/test_contextmenu.html
browser/locales/en-US/chrome/browser/browser.dtd
browser/locales/en-US/chrome/browser/browser.properties
browser/modules/Social.jsm
browser/themes/linux/browser.css
browser/themes/osx/browser.css
browser/themes/windows/browser.css
toolkit/components/social/SocialService.jsm
toolkit/components/social/WorkerAPI.jsm
--- a/browser/base/content/browser-context.inc
+++ b/browser/base/content/browser-context.inc
@@ -32,16 +32,20 @@
                 label="&openLinkInPrivateWindowCmd.label;"
                 accesskey="&openLinkInPrivateWindowCmd.accesskey;"
                 oncommand="gContextMenu.openLinkInPrivateWindow();"/>
       <menuseparator id="context-sep-open"/>
       <menuitem id="context-bookmarklink"
                 label="&bookmarkThisLinkCmd.label;"
                 accesskey="&bookmarkThisLinkCmd.accesskey;"
                 oncommand="gContextMenu.bookmarkLink();"/>
+      <menuitem id="context-marklink"
+                label="&social.marklink.label;"
+                accesskey="&social.marklink.accesskey;"
+                oncommand="gContextMenu.markLink();"/>
       <menuitem id="context-savelink"
                 label="&saveLinkCmd.label;"
                 accesskey="&saveLinkCmd.accesskey;"
                 oncommand="gContextMenu.saveLink();"/>
       <menuitem id="context-copyemail"
                 label="&copyEmailCmd.label;"
                 accesskey="&copyEmailCmd.accesskey;"
                 oncommand="gContextMenu.copyEmail();"/>
@@ -217,16 +221,20 @@
                 label="&stopCmd.label;"
                 accesskey="&stopCmd.accesskey;"
                 command="Browser:Stop"/>
       <menuseparator id="context-sep-stop"/>
       <menuitem id="context-bookmarkpage"
                 label="&bookmarkPageCmd2.label;"
                 accesskey="&bookmarkPageCmd2.accesskey;"
                 oncommand="gContextMenu.bookmarkThisPage();"/>
+      <menuitem id="context-markpage"
+                label="&social.markpage.label;"
+                accesskey="&social.markpage.accesskey;"
+                command="Social:TogglePageMark"/>
       <menuitem id="context-savepage"
                 label="&savePageCmd.label;"
                 accesskey="&savePageCmd.accesskey2;"
                 oncommand="gContextMenu.savePageAs();"/>
       <menuseparator id="context-sep-viewbgimage"/>
       <menuitem id="context-viewbgimage"
                 label="&viewBGImageCmd.label;"
                 accesskey="&viewBGImageCmd.accesskey;"
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -104,18 +104,17 @@
     <command id="Tools:DevToolsConnect" oncommand="gDevToolsBrowser.openConnectScreen(gBrowser)" disabled="true" hidden="true"/>
     <command id="Tools:Sanitize"
      oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
     <command id="Tools:PrivateBrowsing"
       oncommand="OpenBrowserWindow({private: true});"/>
     <command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
     <command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
     <command id="Browser:ToggleAddonBar" oncommand="toggleAddonBar();"/>
-    <command id="Social:SharePage" oncommand="SocialShareButton.sharePage();" disabled="true"/>
-    <command id="Social:UnsharePage" oncommand="SocialShareButton.unsharePage();"/>
+    <command id="Social:TogglePageMark" oncommand="SocialMark.togglePageMark();" disabled="true"/>
     <command id="Social:ToggleSidebar" oncommand="Social.toggleSidebar();"/>
     <command id="Social:ToggleNotifications" oncommand="Social.toggleNotifications();" hidden="true"/>
     <command id="Social:FocusChat" oncommand="SocialChatBar.focus();" hidden="true" disabled="true"/>
     <command id="Social:Toggle" oncommand="Social.toggle();" hidden="true"/>
     <command id="Social:Addons" oncommand="BrowserOpenAddonsMgr('addons://list/service');"/>
   </commandset>
 
   <commandset id="placesCommands">
@@ -345,18 +344,18 @@
     <key id="manBookmarkKb" key="&bookmarksGtkCmd.commandkey;" command="Browser:ShowAllBookmarks" modifiers="accel,shift"/>
 #endif
     <key id="viewBookmarksSidebarKb" key="&bookmarksCmd.commandkey;" command="viewBookmarksSidebar" modifiers="accel"/>
 #ifdef XP_WIN
 # Cmd+I is conventially mapped to Info on MacOS X, thus it should not be
 # overridden for other purposes there.
     <key id="viewBookmarksSidebarWinKb" key="&bookmarksWinCmd.commandkey;" command="viewBookmarksSidebar" modifiers="accel"/>
 #endif
-    
-    <key id="sharePage" key="&sharePageCmd.commandkey;" command="Social:SharePage" modifiers="accel,shift"/>
+
+    <key id="markPage" key="&markPageCmd.commandkey;" command="Social:TogglePageMark" modifiers="accel,shift"/>
     <key id="focusChatBar" key="&social.chatBar.commandkey;" command="Social:FocusChat" modifiers="accel,shift"/>
 
     <key id="key_stop" keycode="VK_ESCAPE" command="Browser:Stop"/>
 
 #ifdef XP_MACOSX
     <key id="key_stop_mac" modifiers="accel" key="&stopCmd.macCommandKey;" command="Browser:Stop"/>
 #endif
 
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -1,17 +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/.
 
 // the "exported" symbols
 let SocialUI,
     SocialChatBar,
     SocialFlyout,
-    SocialShareButton,
+    SocialMark,
     SocialMenu,
     SocialToolbar,
     SocialSidebar;
 
 (function() {
 
 // The minimum sizes for the auto-resize panel code.
 const PANEL_MIN_HEIGHT = 100;
@@ -20,34 +20,34 @@ const PANEL_MIN_WIDTH = 330;
 XPCOMUtils.defineLazyModuleGetter(this, "SharedFrame",
   "resource:///modules/SharedFrame.jsm");
 
 SocialUI = {
   // Called on delayed startup to initialize the UI
   init: function SocialUI_init() {
     Services.obs.addObserver(this, "social:ambient-notification-changed", false);
     Services.obs.addObserver(this, "social:profile-changed", false);
-    Services.obs.addObserver(this, "social:recommend-info-changed", false);
+    Services.obs.addObserver(this, "social:page-mark-config", false);
     Services.obs.addObserver(this, "social:frameworker-error", false);
     Services.obs.addObserver(this, "social:provider-set", false);
     Services.obs.addObserver(this, "social:providers-changed", false);
 
     Services.prefs.addObserver("social.sidebar.open", this, false);
     Services.prefs.addObserver("social.toast-notifications.enabled", this, false);
 
     gBrowser.addEventListener("ActivateSocialFeature", this._activationEventHandler.bind(this), true, true);
 
     // Called when we enter DOM full-screen mode.
     window.addEventListener("mozfullscreenchange", function () {
       SocialSidebar.update();
       SocialChatBar.update();
     });
 
     SocialChatBar.init();
-    SocialShareButton.init();
+    SocialMark.init();
     SocialMenu.init();
     SocialToolbar.init();
     SocialSidebar.init();
 
     if (!Social.initialized) {
       Social.init();
     } else {
       // social was previously initialized, so it's not going to notify us of
@@ -56,17 +56,17 @@ SocialUI = {
       this.observe(null, "social:provider-set", Social.provider ? Social.provider.origin : null);
     }
   },
 
   // Called on window unload
   uninit: function SocialUI_uninit() {
     Services.obs.removeObserver(this, "social:ambient-notification-changed");
     Services.obs.removeObserver(this, "social:profile-changed");
-    Services.obs.removeObserver(this, "social:recommend-info-changed");
+    Services.obs.removeObserver(this, "social:page-mark-config");
     Services.obs.removeObserver(this, "social:frameworker-error");
     Services.obs.removeObserver(this, "social:provider-set");
     Services.obs.removeObserver(this, "social:providers-changed");
 
     Services.prefs.removeObserver("social.sidebar.open", this);
     Services.prefs.removeObserver("social.toast-notifications.enabled", this);
   },
 
@@ -83,17 +83,17 @@ SocialUI = {
           // Social.provider has changed (possibly to null), update any state
           // which depends on it.
           this._updateActiveUI();
           this._updateMenuItems();
 
           SocialFlyout.unload();
           SocialChatBar.update();
           SocialSidebar.update();
-          SocialShareButton.update();
+          SocialMark.update();
           SocialToolbar.update();
           SocialMenu.populate();
           break;
         case "social:providers-changed":
           // the list of providers changed - this may impact the "active" UI.
           this._updateActiveUI();
           // and the multi-provider menu
           SocialToolbar.populateProviderMenus();
@@ -104,23 +104,23 @@ SocialUI = {
           if (this._matchesCurrentProvider(data)) {
             SocialToolbar.updateButton();
             SocialMenu.populate();
           }
           break;
         case "social:profile-changed":
           if (this._matchesCurrentProvider(data)) {
             SocialToolbar.updateProfile();
-            SocialShareButton.update();
+            SocialMark.update();
             SocialChatBar.update();
           }
           break;
-        case "social:recommend-info-changed":
+        case "social:page-mark-config":
           if (this._matchesCurrentProvider(data)) {
-            SocialShareButton.updateShareState();
+            SocialMark.updateMarkState();
           }
           break;
         case "social:frameworker-error":
           if (this.enabled && Social.provider.origin == data) {
             SocialSidebar.setSidebarErrorMessage();
           }
           break;
 
@@ -561,156 +561,91 @@ SocialFlyout = {
       // that the docShell of this frame is created
       panel.firstChild.clientTop;
       Social.setErrorListener(iframe, this.setFlyoutErrorMessage.bind(this))
     }
     this.yOffset = yOffset;
   }
 }
 
-SocialShareButton = {
+SocialMark = {
   // Called once, after window load, when the Social.provider object is initialized
   init: function SSB_init() {
   },
 
-  // Called when the Social.provider changes
-  update: function() {
-    this._updateButtonHiddenState();
-    let profileRow = document.getElementById("unsharePopupHeader");
-    let profile = SocialUI.enabled ? Social.provider.profile : null;
-    if (profile && profile.displayName) {
-      profileRow.hidden = false;
-      let portrait = document.getElementById("socialUserPortrait");
-      if (profile.portrait) {
-        portrait.setAttribute("src", profile.portrait);
-      } else {
-        portrait.removeAttribute("src");
-      }
-      let displayName = document.getElementById("socialUserDisplayName");
-      displayName.setAttribute("label", profile.displayName);
-    } else {
-      profileRow.hidden = true;
-    }
+  get button() {
+    return document.getElementById("social-mark-button");
   },
 
-  get shareButton() {
-    return document.getElementById("share-button");
-  },
-  get unsharePopup() {
-    return document.getElementById("unsharePopup");
-  },
-
-  dismissUnsharePopup: function SSB_dismissUnsharePopup() {
-    this.unsharePopup.hidePopup();
-  },
-
-  canSharePage: function SSB_canSharePage(aURI) {
+  canMarkPage: function SSB_canMarkPage(aURI) {
     // We only allow sharing of http or https
     return aURI && (aURI.schemeIs('http') || aURI.schemeIs('https'));
   },
 
-  _updateButtonHiddenState: function SSB_updateButtonHiddenState() {
-    let shareButton = this.shareButton;
-    if (shareButton)
-      shareButton.hidden = !SocialUI.enabled || Social.provider.recommendInfo == null ||
-                           !Social.haveLoggedInUser() ||
-                           !this.canSharePage(gBrowser.currentURI);
+  // Called when the Social.provider changes
+  update: function SSB_updateButtonState() {
+    let markButton = this.button;
+    // always show button if provider supports marks
+    markButton.hidden = !SocialUI.enabled || Social.provider.pageMarkInfo == null;
+    markButton.disabled = markButton.hidden || !this.canMarkPage(gBrowser.currentURI);
 
     // also update the relevent command's disabled state so the keyboard
     // shortcut only works when available.
-    let cmd = document.getElementById("Social:SharePage");
-    cmd.setAttribute("disabled", shareButton.hidden ? "true" : "false");
-  },
-
-  onClick: function SSB_onClick(aEvent) {
-    if (aEvent.button != 0)
-      return;
-
-    // Don't bubble to the textbox, to avoid unwanted selection of the address.
-    aEvent.stopPropagation();
-
-    this.sharePage();
-  },
-
-  panelShown: function SSB_panelShown(aEvent) {
-    function updateElement(id, attrs) {
-      let el = document.getElementById(id);
-      Object.keys(attrs).forEach(function(attr) {
-        el.setAttribute(attr, attrs[attr]);
-      });
-    }
-    let continueSharingButton = document.getElementById("unsharePopupContinueSharingButton");
-    continueSharingButton.focus();
-    let recommendInfo = Social.provider.recommendInfo;
-    updateElement("unsharePopupContinueSharingButton",
-                  {label: recommendInfo.messages.unshareCancelLabel,
-                   accesskey: recommendInfo.messages.unshareCancelAccessKey});
-    updateElement("unsharePopupStopSharingButton",
-                  {label: recommendInfo.messages.unshareConfirmLabel,
-                  accesskey: recommendInfo.messages.unshareConfirmAccessKey});
-    updateElement("socialUserPortrait",
-                  {"aria-label": recommendInfo.messages.portraitLabel});
-    updateElement("socialUserRecommendedText",
-                  {value: recommendInfo.messages.unshareLabel});
+    let cmd = document.getElementById("Social:TogglePageMark");
+    cmd.setAttribute("disabled", markButton.disabled ? "true" : "false");
   },
 
-  sharePage: function SSB_sharePage() {
-    this.unsharePopup.hidden = false;
-
-    let uri = gBrowser.currentURI;
-    if (!Social.isPageShared(uri)) {
-      Social.sharePage(uri);
-      this.updateShareState();
-    } else {
-      this.unsharePopup.openPopup(this.shareButton, "bottomcenter topright");
-    }
+  togglePageMark: function(aCallback) {
+    if (this.button.disabled)
+      return;
+    this.toggleURIMark(gBrowser.currentURI, aCallback)
   },
-
-  unsharePage: function SSB_unsharePage() {
-    Social.unsharePage(gBrowser.currentURI);
-    this.updateShareState();
-    this.dismissUnsharePopup();
+  
+  toggleURIMark: function(aURI, aCallback) {
+    let update = function(marked) {
+      this._updateMarkState(marked);
+      if (aCallback)
+        aCallback(marked);
+    }.bind(this);
+    Social.isURIMarked(aURI, function(marked) {
+      if (marked) {
+        Social.unmarkURI(aURI, update);
+      } else {
+        Social.markURI(aURI, update);
+      }
+    });
   },
 
-  updateShareState: function SSB_updateShareState() {
-    this._updateButtonHiddenState();
-
-    let shareButton = this.shareButton;
-    let currentPageShared = shareButton && !shareButton.hidden && Social.isPageShared(gBrowser.currentURI);
+  updateMarkState: function SSB_updateMarkState() {
+    this.update();
+    Social.isURIMarked(gBrowser.currentURI, this._updateMarkState.bind(this));
+  },
 
-    let recommendInfo = SocialUI.enabled ? Social.provider.recommendInfo : null;
-    // Provide a11y-friendly notification of share.
-    let status = document.getElementById("share-button-status");
-    if (status) {
-      // XXX - this should also be capable of reflecting that the page was
-      // unshared (ie, it needs to manage three-states: (1) nothing done, (2)
-      // shared, (3) shared then unshared)
-      // Note that we *do* have an appropriate string from the provider for
-      // this (recommendInfo.messages.unsharedLabel) but currently lack a way of
-      // tracking this state)
-      let statusString = currentPageShared && recommendInfo ?
-                           recommendInfo.messages.sharedLabel : "";
-      status.setAttribute("value", statusString);
-    }
+  _updateMarkState: function(currentPageMarked) {
+    // callback for isURIMarked
+    let markButton = this.button;
+    let pageMarkInfo = SocialUI.enabled ? Social.provider.pageMarkInfo : null;
 
-    // Update the share button, if present
-    if (!shareButton || shareButton.hidden)
+    // Update the mark button, if present
+    if (!markButton || markButton.hidden || !pageMarkInfo)
       return;
 
     let imageURL;
-    if (currentPageShared) {
-      shareButton.setAttribute("shared", "true");
-      shareButton.setAttribute("tooltiptext", recommendInfo.messages.unshareTooltip);
-      imageURL = recommendInfo.images.unshare;
+    if (!markButton.disabled && currentPageMarked) {
+      markButton.setAttribute("marked", "true");
+      markButton.setAttribute("label", pageMarkInfo.messages.markedLabel);
+      markButton.setAttribute("tooltiptext", pageMarkInfo.messages.markedTooltip);
+      imageURL = pageMarkInfo.images.marked;
     } else {
-      shareButton.removeAttribute("shared");
-      shareButton.setAttribute("tooltiptext", recommendInfo.messages.shareTooltip);
-      imageURL = recommendInfo.images.share;
+      markButton.removeAttribute("marked");
+      markButton.setAttribute("label", pageMarkInfo.messages.unmarkedLabel);
+      markButton.setAttribute("tooltiptext", pageMarkInfo.messages.unmarkedTooltip);
+      imageURL = pageMarkInfo.images.unmarked;
     }
-    shareButton.src = imageURL;
+    markButton.style.listStyleImage = "url(" + imageURL + ")";
   }
 };
 
 SocialMenu = {
   init: function SocialMenu_init() {
   },
 
   populate: function SocialMenu_populate() {
@@ -789,18 +724,22 @@ SocialToolbar = {
       while (parent.hasChildNodes()) {
         let frame = parent.firstChild;
         SharedFrame.forgetGroup(frame.id);
         parent.removeChild(frame);
       }
 
       let tbi = document.getElementById("social-toolbar-item");
       if (tbi) {
-        while (tbi.lastChild != tbi.firstChild)
-          tbi.removeChild(tbi.lastChild);
+        // SocialMark is the last button allways
+        let next = SocialMark.button.previousSibling;
+        while (next != tbi.firstChild) {
+          tbi.removeChild(next);
+          next = SocialMark.button.previousSibling;
+        }
       }
     }
   },
 
   updateProfile: function SocialToolbar_updateProfile() {
     // Profile may not have been initialized yet, since it depends on a worker
     // response. In that case we'll be called again when it's available, via
     // social:profile-changed
@@ -938,17 +877,17 @@ SocialToolbar = {
       let ariaLabel = icon.label;
       // if there is a badge value, we must use a localizable string to insert it.
       if (badge)
         ariaLabel = gNavigatorBundle.getFormattedString("social.aria.toolbarButtonBadgeText",
                                                         [ariaLabel, badge]);
       toolbarButton.setAttribute("aria-label", ariaLabel);
     }
     let socialToolbarItem = document.getElementById("social-toolbar-item");
-    socialToolbarItem.appendChild(toolbarButtons);
+    socialToolbarItem.insertBefore(toolbarButtons, SocialMark.button);
 
     for (let frame of createdFrames) {
       if (frame.socialErrorListener) {
         frame.socialErrorListener.remove();
       }
       if (frame.docShell) {
         frame.docShell.isActive = false;
         Social.setErrorListener(frame, this.setPanelErrorMessage.bind(this));
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3400,17 +3400,17 @@ function BrowserToolboxCustomizeDone(aTo
   UpdateUrlbarSearchSplitterState();
   setUrlAndSearchBarWidthForConditionalForwardButton();
 
   // Update the urlbar
   if (gURLBar) {
     URLBarSetURI();
     XULBrowserWindow.asyncUpdateUI();
     BookmarksMenuButton.updateStarState();
-    SocialShareButton.updateShareState();
+    SocialMark.updateMarkState();
   }
 
   TabsInTitlebar.allowedBy("customizing-toolbars", true);
 
   // Re-enable parts of the UI we disabled during the dialog
   var menubar = document.getElementById("main-menubar");
   for (let childNode of menubar.childNodes)
     childNode.setAttribute("disabled", false);
@@ -3874,17 +3874,17 @@ var XULBrowserWindow = {
         this.reloadCommand.removeAttribute("disabled");
       }
 
       if (gURLBar) {
         URLBarSetURI(aLocationURI);
 
         // Update starring UI
         BookmarksMenuButton.updateStarState();
-        SocialShareButton.updateShareState();
+        SocialMark.updateMarkState();
       }
 
       // Show or hide browser chrome based on the whitelist
       if (this.hideChromeForLocation(location)) {
         document.documentElement.setAttribute("disablechrome", "true");
       } else {
         let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
         if (ss.getTabValue(gBrowser.selectedTab, "appOrigin"))
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -200,62 +200,16 @@
                   autofocus="autofocus"
                   label="&social.ok.label;"
                   accesskey="&social.ok.accesskey;"
                   oncommand="SocialUI.activationPanel.hidePopup();"/>
         </hbox>
       </vbox>
     </panel>
 
-    <panel id="unsharePopup"
-           type="arrow"
-           orient="vertical"
-           ignorekeys="true"
-           hidden="true"
-           onpopupshown="SocialShareButton.panelShown(event);"
-           consumeoutsideclicks="true"
-           level="top">
-      <!-- Note that 'label', 'accesskey', 'value' and 'aria-label' attributes
-           for many of these elements are supplied by the provider and filled
-           in at runtime
-      -->
-      <row id="unsharePopupHeader" align="center">
-        <vbox align="center">
-          <image id="socialUserPortrait" onclick="SocialUI.showProfile();"/>
-        </vbox>
-        <vbox id="unsharePopupText">
-          <button id="socialUserDisplayName" pack="start"
-                  oncommand="SocialUI.showProfile();"/>
-          <spacer flex="1"/>
-          <label id="socialUserRecommendedText"/>
-        </vbox>
-      </row>
-      <hbox id="unsharePopupBottomButtons" pack="end">
-#ifdef XP_UNIX
-        <button id="unsharePopupStopSharingButton"
-                class="unsharePopupBottomButton"
-                command="Social:UnsharePage"/>
-        <button id="unsharePopupContinueSharingButton"
-                class="unsharePopupBottomButton"
-                default="true"
-                autofocus="autofocus"
-                oncommand="SocialShareButton.dismissUnsharePopup();"/>
-#else
-        <button id="unsharePopupContinueSharingButton"
-                class="unsharePopupBottomButton"
-                default="true"
-                autofocus="autofocus"
-                oncommand="SocialShareButton.dismissUnsharePopup();"/>
-        <button id="unsharePopupStopSharingButton"
-                class="unsharePopupBottomButton"
-                command="Social:UnsharePage"/>
-#endif
-      </hbox>
-    </panel>
-
     <panel id="social-notification-panel"
            class="social-panel"
            type="arrow"
            hidden="true"
            noautofocus="true"/>
     <panel id="social-flyout-panel"
            class="social-panel"
            onpopupshown="SocialFlyout.onShown()"
@@ -608,23 +562,16 @@
             <label id="urlbar-display" value="&urlbar.switchToTab.label;"/>
           </box>
           <hbox id="urlbar-icons">
             <image id="page-report-button"
                    class="urlbar-icon"
                    hidden="true"
                    tooltiptext="&pageReportIcon.tooltip;"
                    onclick="gPopupBlockerObserver.onReportButtonClick(event);"/>
-
-            <label id="share-button-status" collapsed="true" role="status"/>
-            <image id="share-button"
-                   class="urlbar-icon"
-                   hidden="true"
-                   onclick="SocialShareButton.onClick(event);"/>
-
             <image id="go-button"
                    class="urlbar-icon"
                    tooltiptext="&goEndCap.tooltip;"
                    onclick="gURLBar.handleCommand(event);"/>
           </hbox>
           <toolbarbutton id="urlbar-go-button"
                          class="chromeclass-toolbar-additional"
                          onclick="gURLBar.handleCommand(event);"
@@ -797,16 +744,19 @@
             <menuseparator class="social-provider-menu" hidden="true"/>
             <menuitem class="social-addons-menuitem" command="Social:Addons"
                       label="&social.addons.label;"/>
             <menuitem label="&social.learnMore.label;"
                       accesskey="&social.learnMore.accesskey;"
                       oncommand="SocialUI.showLearnMore();"/>
           </menupopup>
         </toolbarbutton>
+        <toolbarbutton id="social-mark-button"
+                       class="toolbarbutton-1"
+                       command="Social:TogglePageMark"/>
       </toolbaritem>
 
       <hbox id="window-controls" hidden="true" pack="end">
         <toolbarbutton id="minimize-button"
                        tooltiptext="&fullScreenMinimize.tooltip;"
                        oncommand="window.minimize();"/>
 
         <toolbarbutton id="restore-button"
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -287,16 +287,42 @@ nsContextMenu.prototype = {
     }
 
     // BiDi UI
     this.showItem("context-sep-bidi", top.gBidiUI);
     this.showItem("context-bidi-text-direction-toggle",
                   this.onTextInput && top.gBidiUI);
     this.showItem("context-bidi-page-direction-toggle",
                   !this.onTextInput && top.gBidiUI);
+    
+    // SocialMarks
+    let marksEnabled = SocialUI.enabled && Social.provider.pageMarkInfo;
+    let enablePageMark = marksEnabled && !(this.isContentSelected ||
+                            this.onTextInput || this.onLink || this.onImage ||
+                            this.onVideo || this.onAudio || this.onSocial);
+    let enableLinkMark = marksEnabled && ((this.onLink && !this.onMailtoLink &&
+                                           !this.onSocial) || this.onPlainTextLink)
+    if (enablePageMark) {
+      Social.isURIMarked(gBrowser.currentURI, function(marked) {
+        let label = marked ? "social.unmarkpage.label" : "social.markpage.label";
+        let provider = Social.provider || Social.defaultProvider;
+        let menuLabel = gNavigatorBundle.getFormattedString(label, [provider.name]);
+        this.setItemAttr("context-markpage", "label", menuLabel);
+      }.bind(this));
+    }
+    this.showItem("context-markpage", enablePageMark);
+    if (enableLinkMark) {
+      Social.isURIMarked(this.linkURI, function(marked) {
+        let label = marked ? "social.unmarklink.label" : "social.marklink.label";
+        let provider = Social.provider || Social.defaultProvider;
+        let menuLabel = gNavigatorBundle.getFormattedString(label, [provider.name]);
+        this.setItemAttr("context-marklink", "label", menuLabel);
+      }.bind(this));
+    }
+    this.showItem("context-marklink", enableLinkMark);
   },
 
   initSpellingItems: function() {
     var canSpell = InlineSpellCheckerUI.canSpellCheck;
     var onMisspelling = InlineSpellCheckerUI.overMisspelling;
     var showUndo = canSpell && InlineSpellCheckerUI.canUndo();
     this.showItem("spell-check-enabled", canSpell);
     this.showItem("spell-separator", canSpell || this.onEditableArea);
@@ -1463,16 +1489,21 @@ nsContextMenu.prototype = {
     else {
       PlacesUIUtils.showBookmarkDialog({ action: "edit"
                                        , type: "bookmark"
                                        , itemId: itemId
                                        }, window.top);
     }
   },
 
+  markLink: function CM_markLink() {
+    // send link to social
+    SocialMark.toggleURIMark(this.linkURI);
+  },
+
   savePageAs: function CM_savePageAs() {
     saveDocument(this.browser.contentDocument);
   },
 
   printFrame: function CM_printFrame() {
     PrintUtils.print(this.target.ownerDocument.defaultView);
   },
 
--- a/browser/base/content/test/social/Makefile.in
+++ b/browser/base/content/test/social/Makefile.in
@@ -15,30 +15,30 @@ include $(DEPTH)/config/autoconf.mk
 		 blocklist.xml \
 		 blocklistEmpty.xml \
 		 browser_blocklist.js \
 		 browser_defaults.js \
 		 browser_addons.js \
                  browser_social_activation.js \
                  browser_social_perwindowPB.js \
                  browser_social_toolbar.js \
-                 browser_social_shareButton.js \
+                 browser_social_markButton.js \
                  browser_social_sidebar.js \
                  browser_social_flyout.js \
                  browser_social_mozSocial_API.js \
                  browser_social_isVisible.js \
                  browser_social_chatwindow.js \
                  browser_social_chatwindowfocus.js \
                  browser_social_multiprovider.js \
                  browser_social_errorPage.js \
                  browser_social_window.js \
                  social_activate.html \
                  social_activate_iframe.html \
                  social_panel.html \
-                 social_share_image.png \
+                 social_mark_image.png \
                  social_sidebar.html \
                  social_chat.html \
                  social_flyout.html \
                  social_window.html \
                  social_worker.js \
                  $(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social/browser_social_markButton.js
@@ -0,0 +1,215 @@
+/* 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/. */
+
+let prefName = "social.enabled",
+    gFinishCB;
+
+function test() {
+  waitForExplicitFinish();
+
+  // Need to load a http/https/ftp/ftps page for the social mark button to appear
+  let tab = gBrowser.selectedTab = gBrowser.addTab("https://example.com", {skipAnimation: true});
+  tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
+    tab.linkedBrowser.removeEventListener("load", tabLoad, true);
+    executeSoon(tabLoaded);
+  }, true);
+
+  registerCleanupFunction(function() {
+    Services.prefs.clearUserPref(prefName);
+    gBrowser.removeTab(tab);
+  });
+}
+
+function tabLoaded() {
+  ok(Social, "Social module loaded");
+
+  let manifest = { // normal provider
+    name: "provider 1",
+    origin: "https://example.com",
+    sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html",
+    workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
+    iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
+  };
+  runSocialTestWithProvider(manifest, function (finishcb) {
+    gFinishCB = finishcb;
+    testInitial();
+  });
+}
+
+function testInitial(finishcb) {
+  ok(Social.provider, "Social provider is active");
+  ok(Social.provider.enabled, "Social provider is enabled");
+  let port = Social.provider.getWorkerPort();
+  ok(port, "Social provider has a port to its FrameWorker");
+  port.close();
+
+  let markButton = SocialMark.button;
+  ok(markButton, "mark button exists");
+
+  // ensure the worker initialization and handshakes are all done and we
+  // have a profile and the worker has sent a page-mark-config msg.
+  waitForCondition(function() Social.provider.pageMarkInfo != null, function() {
+    is(markButton.hasAttribute("marked"), false, "SocialMark button should not have 'marked' attribute before mark button is clicked");
+    // Check the strings from our worker actually ended up on the button.
+    is(markButton.getAttribute("tooltiptext"), "Mark this page", "check tooltip text is correct");
+    // Check the relative URL was resolved correctly (note this image has offsets of zero...)
+    is(markButton.style.listStyleImage, 'url("https://example.com/browser/browser/base/content/test/social/social_mark_image.png")', "check image url is correct");
+
+    // Test the mark button command handler
+    SocialMark.togglePageMark(function() {
+      is(markButton.hasAttribute("marked"), true, "mark button should have 'marked' attribute after mark button is clicked");
+      is(markButton.getAttribute("tooltiptext"), "Unmark this page", "check tooltip text is correct");
+      // Check the URL and offsets were applied correctly
+      is(markButton.style.listStyleImage, 'url("https://example.com/browser/browser/base/content/test/social/social_mark_image.png")', "check image url is correct");
+      SocialMark.togglePageMark(function() {
+        executeSoon(function() {
+          testStillMarkedIn2Tabs();
+        });
+      });
+    });
+    markButton.click();
+  }, "provider didn't provide page-mark-config");
+}
+
+function testStillMarkedIn2Tabs() {
+  let toMark = "http://example.com";
+  let markUri = Services.io.newURI(toMark, null, null);
+  let markButton = SocialMark.button;
+  let initialTab = gBrowser.selectedTab;
+  if (markButton.hasAttribute("marked")) {
+    SocialMark.togglePageMark(testStillMarkedIn2Tabs);
+    return;
+  }
+  is(markButton.hasAttribute("marked"), false, "SocialMark button should not have 'marked' for the initial tab");
+  let tab1 = gBrowser.selectedTab = gBrowser.addTab(toMark);
+  let tab1b = gBrowser.getBrowserForTab(tab1);
+
+  tab1b.addEventListener("load", function tabLoad(event) {
+    tab1b.removeEventListener("load", tabLoad, true);
+    let tab2 = gBrowser.selectedTab = gBrowser.addTab(toMark);
+    let tab2b = gBrowser.getBrowserForTab(tab2);
+    tab2b.addEventListener("load", function tabLoad(event) {
+      tab2b.removeEventListener("load", tabLoad, true);
+      // should start without either page being marked.
+      is(markButton.hasAttribute("marked"), false, "SocialMark button should not have 'marked' before we've done anything");
+      Social.isURIMarked(markUri, function(marked) {
+        ok(!marked, "page is unmarked in annotations");
+        markButton.click();
+        waitForCondition(function() markButton.hasAttribute("marked"), function() {
+          Social.isURIMarked(markUri, function(marked) {
+            ok(marked, "page is marked in annotations");
+            // and switching to the first tab (with the same URL) should still reflect marked.
+            gBrowser.selectedTab = tab1;
+            is(markButton.hasAttribute("marked"), true, "SocialMark button should reflect the marked state");
+            // but switching back the initial one should reflect not marked.
+            gBrowser.selectedTab = initialTab;
+            waitForCondition(function() !markButton.hasAttribute("marked"), function() {
+              gBrowser.selectedTab = tab1;
+    
+              SocialMark.togglePageMark(function() {
+                Social.isURIMarked(gBrowser.currentURI, function(marked) {
+                  ok(!marked, "page is unmarked in annotations");
+                  waitForCondition(function() !markButton.hasAttribute("marked"), function() {
+                    is(markButton.hasAttribute("marked"), false, "SocialMark button should reflect the marked state");
+                    gBrowser.removeTab(tab1);
+                    gBrowser.removeTab(tab2);
+                    executeSoon(testStillMarkedAfterReopen);
+                  }, "button has been unmarked");
+                });
+              });
+            }, "button has been unmarked");
+          });
+        }, "button has been marked");
+      });
+
+    }, true);
+  }, true);
+}
+
+function testStillMarkedAfterReopen() {
+  let toMark = "http://example.com";
+  let markButton = SocialMark.button;
+
+  is(markButton.hasAttribute("marked"), false, "Reopen: SocialMark button should not have 'marked' for the initial tab");
+  let tab = gBrowser.selectedTab = gBrowser.addTab(toMark);
+  let tabb = gBrowser.getBrowserForTab(tab);
+  tabb.addEventListener("load", function tabLoad(event) {
+    tabb.removeEventListener("load", tabLoad, true);
+    SocialMark.togglePageMark(function() {
+      is(markButton.hasAttribute("marked"), true, "SocialMark button should reflect the marked state");
+      gBrowser.removeTab(tab);
+      // should be on the initial unmarked tab now.
+      waitForCondition(function() !markButton.hasAttribute("marked"), function() {
+        // now open the same URL - should be back to Marked.
+        tab = gBrowser.selectedTab = gBrowser.addTab(toMark, {skipAnimation: true});
+        tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
+          tab.linkedBrowser.removeEventListener("load", tabLoad, true);
+          executeSoon(function() {
+            is(markButton.hasAttribute("marked"), true, "New tab to previously marked URL should reflect marked state");
+            SocialMark.togglePageMark(function() {
+              gBrowser.removeTab(tab);
+              executeSoon(testOnlyMarkCertainUrlsTabSwitch);
+            });
+          });
+        }, true);
+      }, "button is now unmarked");
+    });
+  }, true);
+}
+
+function testOnlyMarkCertainUrlsTabSwitch() {
+  let toMark = "http://example.com";
+  let notSharable = "about:blank";
+  let markButton = SocialMark.button;
+  let tab = gBrowser.selectedTab = gBrowser.addTab(toMark);
+  let tabb = gBrowser.getBrowserForTab(tab);
+  tabb.addEventListener("load", function tabLoad(event) {
+    tabb.removeEventListener("load", tabLoad, true);
+    ok(!markButton.hidden, "SocialMark button not hidden for http url");
+    let tab2 = gBrowser.selectedTab = gBrowser.addTab(notSharable);
+    let tabb2 = gBrowser.getBrowserForTab(tab2);
+    tabb2.addEventListener("load", function tabLoad(event) {
+      tabb2.removeEventListener("load", tabLoad, true);
+      ok(markButton.disabled, "SocialMark button disabled for about:blank");
+      gBrowser.selectedTab = tab;
+      ok(!markButton.disabled, "SocialMark button re-shown when switching back to http: url");
+      gBrowser.selectedTab = tab2;
+      ok(markButton.disabled, "SocialMark button re-hidden when switching back to about:blank");
+      gBrowser.removeTab(tab);
+      gBrowser.removeTab(tab2);
+      executeSoon(testOnlyMarkCertainUrlsSameTab);
+    }, true);
+  }, true);
+}
+
+function testOnlyMarkCertainUrlsSameTab() {
+  let toMark = "http://example.com";
+  let notSharable = "about:blank";
+  let markButton = SocialMark.button;
+  let tab = gBrowser.selectedTab = gBrowser.addTab(toMark);
+  let tabb = gBrowser.getBrowserForTab(tab);
+  tabb.addEventListener("load", function tabLoad(event) {
+    tabb.removeEventListener("load", tabLoad, true);
+    ok(!markButton.disabled, "SocialMark button not disabled for http url");
+    tabb.addEventListener("load", function tabLoad(event) {
+      tabb.removeEventListener("load", tabLoad, true);
+      ok(markButton.disabled, "SocialMark button disabled for about:blank");
+      tabb.addEventListener("load", function tabLoad(event) {
+        tabb.removeEventListener("load", tabLoad, true);
+        ok(!markButton.disabled, "SocialMark button re-enabled http url");
+        gBrowser.removeTab(tab);
+        executeSoon(testDisable);
+      }, true);
+      tabb.loadURI(toMark);
+    }, true);
+    tabb.loadURI(notSharable);
+  }, true);
+}
+
+function testDisable() {
+  let markButton = SocialMark.button;
+  Services.prefs.setBoolPref(prefName, false);
+  is(markButton.hidden, true, "SocialMark button should be hidden when pref is disabled");
+  gFinishCB();
+}
--- a/browser/base/content/test/social/browser_social_multiprovider.js
+++ b/browser/base/content/test/social/browser_social_multiprovider.js
@@ -54,20 +54,16 @@ var tests = {
       });
       Social.activateFromOrigin("https://test1.example.com");
     });
   }
 }
 
 function checkUIStateMatchesProvider(provider) {
   let profileData = getExpectedProfileData(provider);
-  // Bug 789863 - share button uses 'displayName', toolbar uses 'userName'
-  // Check the "share button"
-  let displayNameEl = document.getElementById("socialUserDisplayName");
-  is(displayNameEl.getAttribute("label"), profileData.displayName, "display name matches provider profile");
   // The toolbar
   let loginStatus = document.getElementsByClassName("social-statusarea-loggedInStatus");
   for (let label of loginStatus) {
     is(label.value, profileData.userName, "username name matches provider profile");
   }
   // Sidebar
   is(document.getElementById("social-sidebar-browser").getAttribute("src"), provider.sidebarURL, "side bar URL is set");
 }
deleted file mode 100644
--- a/browser/base/content/test/social/browser_social_shareButton.js
+++ /dev/null
@@ -1,328 +0,0 @@
-/* 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/. */
-
-let prefName = "social.enabled",
-    gFinishCB;
-
-function test() {
-  waitForExplicitFinish();
-
-  // Need to load a http/https/ftp/ftps page for the social share button to appear
-  let tab = gBrowser.selectedTab = gBrowser.addTab("https://example.com", {skipAnimation: true});
-  tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
-    tab.linkedBrowser.removeEventListener("load", tabLoad, true);
-    executeSoon(tabLoaded);
-  }, true);
-
-  registerCleanupFunction(function() {
-    Services.prefs.clearUserPref(prefName);
-    gBrowser.removeTab(tab);
-  });
-}
-
-function tabLoaded() {
-  ok(Social, "Social module loaded");
-
-  let manifest = { // normal provider
-    name: "provider 1",
-    origin: "https://example.com",
-    sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html",
-    workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
-    iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
-  };
-  runSocialTestWithProvider(manifest, function (finishcb) {
-    gFinishCB = finishcb;
-    testInitial();
-  });
-}
-
-function testInitial(finishcb) {
-  ok(Social.provider, "Social provider is active");
-  ok(Social.provider.enabled, "Social provider is enabled");
-  let port = Social.provider.getWorkerPort();
-  ok(port, "Social provider has a port to its FrameWorker");
-  port.close();
-
-  let {shareButton, unsharePopup} = SocialShareButton;
-  ok(shareButton, "share button exists");
-  ok(unsharePopup, "share popup exists");
-
-  let okButton = document.getElementById("unsharePopupContinueSharingButton");
-  let undoButton = document.getElementById("unsharePopupStopSharingButton");
-  let shareStatusLabel = document.getElementById("share-button-status");
-
-  // ensure the worker initialization and handshakes are all done and we
-  // have a profile and the worker has responsed to the recommend-prompt msg.
-  waitForCondition(function() Social.provider.profile && Social.provider.recommendInfo != null, function() {
-    is(shareButton.hasAttribute("shared"), false, "Share button should not have 'shared' attribute before share button is clicked");
-    // check dom values
-    let profile = Social.provider.profile;
-    let portrait = document.getElementById("socialUserPortrait").getAttribute("src");
-    is(profile.portrait, portrait, "portrait is set");
-    let displayName = document.getElementById("socialUserDisplayName");
-    is(displayName.label, profile.displayName, "display name is set");
-    ok(!document.getElementById("unsharePopupHeader").hidden, "user profile is visible");
-
-    // Check the strings from our worker actually ended up on the button.
-    is(shareButton.getAttribute("tooltiptext"), "Share this page", "check tooltip text is correct");
-    is(shareStatusLabel.getAttribute("value"), "", "check status label text is blank");
-    // Check the relative URL was resolved correctly (note this image has offsets of zero...)
-    is(shareButton.src, 'https://example.com/browser/browser/base/content/test/social/social_share_image.png', "check image url is correct");
-
-    // Test clicking the share button
-    shareButton.addEventListener("click", function listener() {
-      shareButton.removeEventListener("click", listener);
-      is(shareButton.hasAttribute("shared"), true, "Share button should have 'shared' attribute after share button is clicked");
-      is(shareButton.getAttribute("tooltiptext"), "Unshare this page", "check tooltip text is correct");
-      is(shareStatusLabel.getAttribute("value"), "This page has been shared", "check status label text is correct");
-      // Check the URL and offsets were applied correctly
-      is(shareButton.src, 'https://example.com/browser/browser/base/content/test/social/social_share_image.png', "check image url is correct");
-      executeSoon(testSecondClick.bind(window, testPopupOKButton));
-    });
-    shareButton.click();
-  }, "provider didn't provide user-recommend-prompt response");
-}
-
-function testSecondClick(nextTest) {
-  let {shareButton, unsharePopup} = SocialShareButton;
-  unsharePopup.addEventListener("popupshown", function listener() {
-    unsharePopup.removeEventListener("popupshown", listener);
-    ok(true, "popup was shown after second click");
-    executeSoon(nextTest);
-  });
-  shareButton.click();
-}
-
-function testPopupOKButton() {
-  let {shareButton, unsharePopup} = SocialShareButton;
-  let okButton = document.getElementById("unsharePopupContinueSharingButton");
-  unsharePopup.addEventListener("popuphidden", function listener() {
-    unsharePopup.removeEventListener("popuphidden", listener);
-    is(shareButton.hasAttribute("shared"), true, "Share button should still have 'shared' attribute after OK button is clicked");
-    executeSoon(testSecondClick.bind(window, testPopupUndoButton));
-  });
-  okButton.click();
-}
-
-function testPopupUndoButton() {
-  let {shareButton, unsharePopup} = SocialShareButton;
-  let undoButton = document.getElementById("unsharePopupStopSharingButton");
-  unsharePopup.addEventListener("popuphidden", function listener() {
-    unsharePopup.removeEventListener("popuphidden", listener);
-    is(shareButton.hasAttribute("shared"), false, "Share button should not have 'shared' attribute after Undo button is clicked");
-    executeSoon(testShortcut);
-  });
-  undoButton.click();
-}
-
-function testShortcut() {
-  let keyTarget = window;
-  keyTarget.addEventListener("keyup", function listener() {
-    keyTarget.removeEventListener("keyup", listener);
-    executeSoon(checkShortcutWorked.bind(window, keyTarget));
-  });
-  EventUtils.synthesizeKey("l", {accelKey: true, shiftKey: true}, keyTarget);
-}
-
-function checkShortcutWorked(keyTarget) {
-  let {unsharePopup, shareButton} = SocialShareButton;
-  is(shareButton.hasAttribute("shared"), true, "Share button should be in the 'shared' state after keyboard shortcut is used");
-
-  // Test a second invocation of the shortcut
-  unsharePopup.addEventListener("popupshown", function listener() {
-    unsharePopup.removeEventListener("popupshown", listener);
-    ok(true, "popup was shown after second use of keyboard shortcut");
-    executeSoon(checkOKButton);
-  });
-  EventUtils.synthesizeKey("l", {accelKey: true, shiftKey: true}, keyTarget);
-}
-
-function checkOKButton() {
-  let okButton = document.getElementById("unsharePopupContinueSharingButton");
-  let undoButton = document.getElementById("unsharePopupStopSharingButton");
-  is(document.activeElement, okButton, "ok button should be focused by default");
-
-  // the undo button text, label text, access keys, etc  should be as
-  // specified by the provider.
-  function isEltAttr(eltid, attr, expected) {
-    is(document.getElementById(eltid).getAttribute(attr), expected,
-       "element '" + eltid + "' has correct value for attribute '" + attr + "'");
-  }
-  isEltAttr("socialUserRecommendedText", "value", "You have already shared this page");
-  isEltAttr("unsharePopupContinueSharingButton", "label", "Got it!");
-  isEltAttr("unsharePopupContinueSharingButton", "accesskey", "G");
-  isEltAttr("unsharePopupStopSharingButton", "label", "Unshare it!");
-  isEltAttr("unsharePopupStopSharingButton", "accesskey", "U");
-  isEltAttr("socialUserPortrait", "aria-label", "Your pretty face");
-
-  // This rest of particular test doesn't really apply on Mac, since buttons
-  // aren't focusable by default.
-  if (navigator.platform.contains("Mac")) {
-    executeSoon(testCloseBySpace);
-    return;
-  }
-
-  let displayName = document.getElementById("socialUserDisplayName");
-
-  // Linux has the buttons in the [unshare] [ok] order, so displayName will come first.
-  if (navigator.platform.contains("Linux")) {
-    checkNextInTabOrder(displayName, function () {
-      checkNextInTabOrder(undoButton, function () {
-        checkNextInTabOrder(okButton, testCloseBySpace);
-      });
-    });
-  } else {
-    checkNextInTabOrder(undoButton, function () {
-      checkNextInTabOrder(displayName, function () {
-        checkNextInTabOrder(okButton, testCloseBySpace);
-      });
-    });
-  }
-}
-
-function checkNextInTabOrder(element, next) {
-  function listener() {
-    element.removeEventListener("focus", listener);
-    is(document.activeElement, element, element.id + " should be next in tab order");
-    executeSoon(next);
-  }
-  element.addEventListener("focus", listener);
-  // Register a cleanup function to remove the listener in case this test fails
-  registerCleanupFunction(function () {
-    element.removeEventListener("focus", listener);
-  });
-  EventUtils.synthesizeKey("VK_TAB", {});
-}
-
-function testCloseBySpace() {
-  let unsharePopup = SocialShareButton.unsharePopup;
-  is(document.activeElement.id, "unsharePopupContinueSharingButton", "testCloseBySpace, the ok button should be focused");
-  unsharePopup.addEventListener("popuphidden", function listener() {
-    unsharePopup.removeEventListener("popuphidden", listener);
-    ok(true, "space closed the share popup");
-    executeSoon(testStillSharedIn2Tabs);
-  });
-  EventUtils.synthesizeKey("VK_SPACE", {});
-}
-
-function testStillSharedIn2Tabs() {
-  let toShare = "http://example.com";
-  let {shareButton} = SocialShareButton;
-  let initialTab = gBrowser.selectedTab;
-  if (shareButton.hasAttribute("shared")) {
-    SocialShareButton.unsharePage();
-  }
-  is(shareButton.hasAttribute("shared"), false, "Share button should not have 'shared' for the initial tab");
-  let tab1 = gBrowser.selectedTab = gBrowser.addTab(toShare);
-  let tab1b = gBrowser.getBrowserForTab(tab1);
-
-  tab1b.addEventListener("load", function tabLoad(event) {
-    tab1b.removeEventListener("load", tabLoad, true);
-    let tab2 = gBrowser.selectedTab = gBrowser.addTab(toShare);
-    let tab2b = gBrowser.getBrowserForTab(tab2);
-    tab2b.addEventListener("load", function tabLoad(event) {
-      tab2b.removeEventListener("load", tabLoad, true);
-      // should start without either page being shared.
-      is(shareButton.hasAttribute("shared"), false, "Share button should not have 'shared' before we've done anything");
-      shareButton.click();
-      is(shareButton.hasAttribute("shared"), true, "Share button should reflect the share");
-      // and switching to the first tab (with the same URL) should still reflect shared.
-      gBrowser.selectedTab = tab1;
-      is(shareButton.hasAttribute("shared"), true, "Share button should reflect the share");
-      // but switching back the initial one should reflect not shared.
-      gBrowser.selectedTab = initialTab;
-      is(shareButton.hasAttribute("shared"), false, "Initial tab should not reflect shared");
-
-      gBrowser.selectedTab = tab1;
-      SocialShareButton.unsharePage();
-      gBrowser.removeTab(tab1);
-      gBrowser.removeTab(tab2);
-      executeSoon(testStillSharedAfterReopen);
-    }, true);
-  }, true);
-}
-
-function testStillSharedAfterReopen() {
-  let toShare = "http://example.com";
-  let {shareButton} = SocialShareButton;
-
-  is(shareButton.hasAttribute("shared"), false, "Reopen: Share button should not have 'shared' for the initial tab");
-  let tab = gBrowser.selectedTab = gBrowser.addTab(toShare);
-  let tabb = gBrowser.getBrowserForTab(tab);
-  tabb.addEventListener("load", function tabLoad(event) {
-    tabb.removeEventListener("load", tabLoad, true);
-    SocialShareButton.sharePage();
-    is(shareButton.hasAttribute("shared"), true, "Share button should reflect the share");
-    gBrowser.removeTab(tab);
-    // should be on the initial unshared tab now.
-    is(shareButton.hasAttribute("shared"), false, "Initial tab should be selected and be unshared.");
-    // now open the same URL - should be back to shared.
-    tab = gBrowser.selectedTab = gBrowser.addTab(toShare, {skipAnimation: true});
-    tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
-      tab.linkedBrowser.removeEventListener("load", tabLoad, true);
-      executeSoon(function() {
-        is(shareButton.hasAttribute("shared"), true, "New tab to previously shared URL should reflect shared");
-        SocialShareButton.unsharePage();
-        gBrowser.removeTab(tab);
-        executeSoon(testOnlyShareCertainUrlsTabSwitch);
-      });
-    }, true);
-  }, true);
-}
-
-function testOnlyShareCertainUrlsTabSwitch() {
-  let toShare = "http://example.com";
-  let notSharable = "about:blank";
-  let {shareButton} = SocialShareButton;
-  let tab = gBrowser.selectedTab = gBrowser.addTab(toShare);
-  let tabb = gBrowser.getBrowserForTab(tab);
-  tabb.addEventListener("load", function tabLoad(event) {
-    tabb.removeEventListener("load", tabLoad, true);
-    ok(!shareButton.hidden, "share button not hidden for http url");
-    let tab2 = gBrowser.selectedTab = gBrowser.addTab(notSharable);
-    let tabb2 = gBrowser.getBrowserForTab(tab2);
-    tabb2.addEventListener("load", function tabLoad(event) {
-      tabb2.removeEventListener("load", tabLoad, true);
-      ok(shareButton.hidden, "share button hidden for about:blank");
-      gBrowser.selectedTab = tab;
-      ok(!shareButton.hidden, "share button re-shown when switching back to http: url");
-      gBrowser.selectedTab = tab2;
-      ok(shareButton.hidden, "share button re-hidden when switching back to about:blank");
-      gBrowser.removeTab(tab);
-      gBrowser.removeTab(tab2);
-      executeSoon(testOnlyShareCertainUrlsSameTab);
-    }, true);
-  }, true);
-}
-
-function testOnlyShareCertainUrlsSameTab() {
-  let toShare = "http://example.com";
-  let notSharable = "about:blank";
-  let {shareButton} = SocialShareButton;
-  let tab = gBrowser.selectedTab = gBrowser.addTab(toShare);
-  let tabb = gBrowser.getBrowserForTab(tab);
-  tabb.addEventListener("load", function tabLoad(event) {
-    tabb.removeEventListener("load", tabLoad, true);
-    ok(!shareButton.hidden, "share button not hidden for http url");
-    tabb.addEventListener("load", function tabLoad(event) {
-      tabb.removeEventListener("load", tabLoad, true);
-      ok(shareButton.hidden, "share button hidden for about:blank");
-      tabb.addEventListener("load", function tabLoad(event) {
-        tabb.removeEventListener("load", tabLoad, true);
-        ok(!shareButton.hidden, "share button re-enabled http url");
-        gBrowser.removeTab(tab);
-        executeSoon(testDisable);
-      }, true);
-      tabb.loadURI(toShare);
-    }, true);
-    tabb.loadURI(notSharable);
-  }, true);
-}
-
-function testDisable() {
-  let shareButton = SocialShareButton.shareButton;
-  Services.prefs.setBoolPref(prefName, false);
-  is(shareButton.hidden, true, "Share button should be hidden when pref is disabled");
-  gFinishCB();
-}
--- a/browser/base/content/test/social/head.js
+++ b/browser/base/content/test/social/head.js
@@ -180,33 +180,35 @@ function checkSocialUI(win) {
     is(!!a, !!b, msg);
   }
   isbool(win.SocialSidebar.canShow, enabled, "social sidebar active?");
   if (enabled)
     isbool(win.SocialSidebar.opened, enabled, "social sidebar open?");
   isbool(win.SocialChatBar.isAvailable, enabled && Social.haveLoggedInUser(), "chatbar available?");
   isbool(!win.SocialChatBar.chatbar.hidden, enabled && Social.haveLoggedInUser(), "chatbar visible?");
 
-  let canShare = enabled && provider.recommendInfo && Social.haveLoggedInUser() && win.SocialShareButton.canSharePage(win.gBrowser.currentURI)
-  isbool(!win.SocialShareButton.shareButton.hidden, canShare, "share button visible?");
+  let markVisible = enabled && provider.pageMarkInfo;
+  let canMark = markVisible && win.SocialMark.canMarkPage(win.gBrowser.currentURI);
+  isbool(!win.SocialMark.button.hidden, markVisible, "SocialMark button visible?");
+  isbool(!win.SocialMark.button.disabled, canMark, "SocialMark button enabled?");
   isbool(!doc.getElementById("social-toolbar-item").hidden, active, "toolbar items visible?");
   if (active)
     is(win.SocialToolbar.button.style.listStyleImage, 'url("' + Social.defaultProvider.iconURL + '")', "toolbar button has provider icon");
   // the menus should always have the provider name
   if (provider) {
     for (let id of ["menu_socialSidebar", "menu_socialAmbientMenu"])
       is(document.getElementById(id).getAttribute("label"), Social.provider.name, "element has the provider name");
   }
 
   // and for good measure, check all the social commands.
   isbool(!doc.getElementById("Social:Toggle").hidden, active, "Social:Toggle visible?");
   isbool(!doc.getElementById("Social:ToggleNotifications").hidden, enabled, "Social:ToggleNotifications visible?");
   isbool(!doc.getElementById("Social:FocusChat").hidden, enabled && Social.haveLoggedInUser(), "Social:FocusChat visible?");
   isbool(doc.getElementById("Social:FocusChat").getAttribute("disabled"), enabled ? "false" : "true", "Social:FocusChat disabled?");
-  is(doc.getElementById("Social:SharePage").getAttribute("disabled"), canShare ? "false" : "true", "Social:SharePage visible?");
+  is(doc.getElementById("Social:TogglePageMark").getAttribute("disabled"), canMark ? "false" : "true", "Social:TogglePageMark enabled?");
 
   // broadcasters.
   isbool(!doc.getElementById("socialActiveBroadcaster").hidden, active, "socialActiveBroadcaster hidden?");
 }
 
 // blocklist testing
 function updateBlocklist(aCallback) {
   var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
rename from browser/base/content/test/social/social_share_image.png
rename to browser/base/content/test/social/social_mark_image.png
--- a/browser/base/content/test/social/social_worker.js
+++ b/browser/base/content/test/social/social_worker.js
@@ -95,52 +95,44 @@ onconnect = function(e) {
           profile = {
             portrait: "https://example.com/portrait.jpg",
             userName: "trickster",
             displayName: "Kuma Lisa",
             profileURL: "http://en.wikipedia.org/wiki/Kuma_Lisa"
           };
         }
         port.postMessage({topic: "social.user-profile", data: profile});
+        port.postMessage({
+          topic: "social.page-mark-config",
+          data: {
+            images: {
+              // this one is relative to test we handle relative ones.
+              marked: "/browser/browser/base/content/test/social/social_mark_image.png",
+              // absolute to check we handle them too.
+              unmarked: "https://example.com/browser/browser/base/content/test/social/social_mark_image.png"
+            },
+            messages: {
+              unmarkedTooltip: "Mark this page",
+              markedTooltip: "Unmark this page",
+              unmarkedLabel: "Mark",
+              markedLabel: "Unmark",
+            }
+          }
+        });
         break;
       case "test-ambient-notification":
         let icon = {
           name: "testIcon",
           iconURL: "chrome://browser/skin/Info.png",
           contentPanel: "https://example.com/browser/browser/base/content/test/social/social_panel.html",
           counter: 1
         };
         apiPort.postMessage({topic: "social.ambient-notification", data: icon});
         break;
       case "test-isVisible":
         sidebarPort.postMessage({topic: "test-isVisible"});
         break;
       case "test-isVisible-response":
         testPort.postMessage({topic: "got-isVisible-response", result: event.data.result});
         break;
-      case "social.user-recommend-prompt":
-        port.postMessage({
-          topic: "social.user-recommend-prompt-response",
-          data: {
-            images: {
-              // this one is relative to test we handle relative ones.
-              share: "browser/browser/base/content/test/social/social_share_image.png",
-              // absolute to check we handle them too.
-              unshare: "https://example.com/browser/browser/base/content/test/social/social_share_image.png"
-            },
-            messages: {
-              shareTooltip: "Share this page",
-              unshareTooltip: "Unshare this page",
-              sharedLabel: "This page has been shared",
-              unsharedLabel: "This page is no longer shared",
-              unshareLabel: "You have already shared this page",
-              portraitLabel: "Your pretty face",
-              unshareConfirmLabel: "Unshare it!",
-              unshareConfirmAccessKey: "U",
-              unshareCancelLabel: "Got it!",
-              unshareCancelAccessKey: "G"
-            }
-          }
-        });
-        break;
     }
   }
 }
--- a/browser/base/content/test/test_contextmenu.html
+++ b/browser/base/content/test/test_contextmenu.html
@@ -303,16 +303,17 @@ function runTest(testNum) {
                             "context-savelink",      true,
                             "context-copylink",      true
                            ].concat(inspectItems));
         } else {
           checkContextMenu(["context-openlinkintab", true,
                             "context-openlink",      true,
                             "---",                   null,
                             "context-bookmarklink",  true,
+                            "context-marklink",      true,
                             "context-savelink",      true,
                             "context-copylink",      true
                            ].concat(inspectItems));
         }
         closeContextMenu();
         openContextMenuFor(mailto); // Invoke context menu for next test.
         break;
 
@@ -803,16 +804,17 @@ function runTest(testNum) {
                               "context-viewpartialsource-selection", true
                              ].concat(inspectItems));
           } else {
             checkContextMenu(["context-openlinkincurrent",           true,
                               "context-openlinkintab",               true,
                               "context-openlink",                    true,
                               "---",                                 null,
                               "context-bookmarklink",                true,
+                              "context-marklink",                    true,
                               "context-savelink",                    true,
                               "context-copy",                        true,
                               "context-selectall",                   true,
                               "---",                                 null,
                               "context-searchselect",                true,
                               "context-viewpartialsource-selection", true
                              ].concat(inspectItems));
           }
@@ -844,16 +846,17 @@ function runTest(testNum) {
                             "context-setDesktopBackground", true,
                             "context-viewimageinfo",        true
                            ].concat(inspectItems));
         } else {
           checkContextMenu(["context-openlinkintab", true,
                             "context-openlink",      true,
                             "---",                   null,
                             "context-bookmarklink",  true,
+                            "context-marklink",      true,
                             "context-savelink",      true,
                             "context-copylink",      true,
                             "---",                   null,
                             "context-viewimage",            true,
                             "context-copyimage-contents",   true,
                             "context-copyimage",            true,
                             "---",                          null,
                             "context-saveimage",            true,
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -110,17 +110,17 @@ These should match what Safari and other
 
 <!ENTITY closeWindow.label "Close Window">
 <!ENTITY closeWindow.accesskey "d">
 
 <!ENTITY bookmarksMenu.label "Bookmarks">
 <!ENTITY bookmarksMenu.accesskey "B">
 <!ENTITY bookmarkThisPageCmd.label "Bookmark This Page">
 <!ENTITY bookmarkThisPageCmd.commandkey "d">
-<!ENTITY sharePageCmd.commandkey "l">
+<!ENTITY markPageCmd.commandkey "l">
 <!ENTITY subscribeToPageMenupopup.label "Subscribe to This Page">
 <!ENTITY subscribeToPageMenuitem.label "Subscribe to This Page…">
 <!ENTITY addCurPagesCmd.label "Bookmark All Tabs…">
 <!ENTITY showAllBookmarks2.label "Show All Bookmarks">
 <!ENTITY unsortedBookmarksCmd.label "Unsorted Bookmarks">
 <!ENTITY bookmarksToolbarChevron.tooltip "Show more bookmarks">
 
 <!ENTITY backCmd.label                "Back">
@@ -638,16 +638,21 @@ just addresses the organization to follo
 <!ENTITY social.learnMore.label "Learn more…">
 <!ENTITY social.learnMore.accesskey "l">
 <!ENTITY social.closeNotificationItem.label "Not Now">
 
 <!ENTITY social.chatBar.commandkey "c">
 <!ENTITY social.chatBar.label "Focus chats">
 <!ENTITY social.chatBar.accesskey "c">
 
+<!ENTITY social.markpage.label "Mark This Page">
+<!ENTITY social.markpage.accesskey "m">
+<!ENTITY social.marklink.label "Unmark This Page">
+<!ENTITY social.marklink.accesskey "M">
+
 <!ENTITY getUserMedia.selectCamera.label "Camera to share:">
 <!ENTITY getUserMedia.selectCamera.accesskey "C">
 <!ENTITY getUserMedia.selectMicrophone.label "Microphone to share:">
 <!ENTITY getUserMedia.selectMicrophone.accesskey "M">
 
 <!ENTITY webrtcIndicatorButton.label "Camera / Microphone Access">
 <!ENTITY webrtcIndicatorButton.tooltip "Display sites you are currently sharing your camera or microphone with">
 
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -381,16 +381,23 @@ service.install.learnmore=Learn More…
 
 # LOCALIZATION NOTE (social.turnOff.label): %S is the name of the social provider
 social.turnOff.label=Turn off %S
 social.turnOff.accesskey=T
 # LOCALIZATION NOTE (social.turnOn.label): %S is the name of the social provider
 social.turnOn.label=Turn on %S
 social.turnOn.accesskey=T
 
+# LOCALIZATION NOTE (social.markpage.label): %S is the name of the social provider
+social.markpage.label=Send Page to %S
+social.unmarkpage.label=Remove Page from %S
+# LOCALIZATION NOTE (social.marklink.label): %S is the name of the social provider
+social.marklink.label=Send Link to %S
+social.unmarklink.label=Remove Link from %S
+
 # LOCALIZATION NOTE (social.error.message): %1$S is brandShortName (e.g. Firefox), %2$S is the name of the social provider
 social.error.message=%1$S is unable to connect with %2$S right now.
 social.error.tryAgain.label=Try Again
 social.error.tryAgain.accesskey=T
 social.error.closeSidebar.label=Close This Sidebar
 social.error.closeSidebar.accesskey=C
 
 # LOCALIZATION NOTE: %1$S is the label for the toolbar button, %2$S is the associated badge numbering that the social provider may provide.
--- a/browser/modules/Social.jsm
+++ b/browser/modules/Social.jsm
@@ -10,16 +10,20 @@ const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "SocialService",
   "resource://gre/modules/SocialService.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
+  "resource://gre/modules/PlacesUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Promise",
+  "resource://gre/modules/commonjs/sdk/core/promise.js");
 
 // Add a pref observer for the enabled state
 function prefObserver(subject, topic, data) {
   let enable = Services.prefs.getBoolPref("social.enabled");
   if (enable && !Social.provider) {
     Social.provider = Social.defaultProvider;
   } else if (!enable && Social.provider) {
     Social.provider = null;
@@ -27,16 +31,56 @@ function prefObserver(subject, topic, da
 }
 
 Services.prefs.addObserver("social.enabled", prefObserver, false);
 Services.obs.addObserver(function xpcomShutdown() {
   Services.obs.removeObserver(xpcomShutdown, "xpcom-shutdown");
   Services.prefs.removeObserver("social.enabled", prefObserver);
 }, "xpcom-shutdown", false);
 
+function promiseSetAnnotation(aURI, providerList) {
+  let deferred = Promise.defer();
+
+  // Delaying to catch issues with asynchronous behavior while waiting
+  // to implement asynchronous annotations in bug 699844.
+  Services.tm.mainThread.dispatch(function() {
+    try {
+      if (providerList && providerList.length > 0) {
+        PlacesUtils.annotations.setPageAnnotation(
+          aURI, "social/mark", JSON.stringify(providerList), 0,
+          PlacesUtils.annotations.EXPIRE_WITH_HISTORY);
+      } else {
+        PlacesUtils.annotations.removePageAnnotation(aURI, "social/mark");
+      }
+    } catch(e) {
+      Cu.reportError("SocialAnnotation failed: " + e);
+    }
+    deferred.resolve();
+  }, Ci.nsIThread.DISPATCH_NORMAL);
+
+  return deferred.promise;
+}
+
+function promiseGetAnnotation(aURI) {
+  let deferred = Promise.defer();
+
+  // Delaying to catch issues with asynchronous behavior while waiting
+  // to implement asynchronous annotations in bug 699844.
+  Services.tm.mainThread.dispatch(function() {
+    let val = null;
+    try {
+      val = PlacesUtils.annotations.getPageAnnotation(aURI, "social/mark");
+    } catch (ex) { }
+
+    deferred.resolve(val);
+  }, Ci.nsIThread.DISPATCH_NORMAL);
+
+  return deferred.promise;
+}
+
 this.Social = {
   initialized: false,
   lastEventReceived: 0,
   providers: null,
   _disabledForSafeMode: false,
 
   get _currentProviderPref() {
     try {
@@ -208,73 +252,117 @@ this.Social = {
     let oldProvider = this._getProviderFromOrigin(oldOrigin);
     if (!oldProvider && this.providers.length)
       oldProvider = this.providers[0];
     this.provider = oldProvider;
     if (provider)
       SocialService.removeProvider(origin);
   },
 
-  // Sharing functionality
-  _getShareablePageUrl: function Social_getShareablePageUrl(aURI) {
+  // Page Marking functionality
+  _getMarkablePageUrl: function Social_getMarkablePageUrl(aURI) {
     let uri = aURI.clone();
     try {
       // Setting userPass on about:config throws.
       uri.userPass = "";
     } catch (e) {}
     return uri.spec;
   },
 
-  isPageShared: function Social_isPageShared(aURI) {
-    let url = this._getShareablePageUrl(aURI);
-    return this._sharedUrls.hasOwnProperty(url);
+  isURIMarked: function(aURI, aCallback) {
+    promiseGetAnnotation(aURI).then(function(val) {
+      if (val) {
+        let providerList = JSON.parse(val);
+        val = providerList.indexOf(this.provider.origin) >= 0;
+      }
+      aCallback(!!val);
+    }.bind(this));
   },
 
-  sharePage: function Social_sharePage(aURI) {
+  markURI: function(aURI, aCallback) {
     // this should not be called if this.provider or the port is null
     if (!this.provider) {
-      Cu.reportError("Can't share a page when no provider is current");
+      Cu.reportError("Can't mark a page when no provider is current");
       return;
     }
     let port = this.provider.getWorkerPort();
     if (!port) {
-      Cu.reportError("Can't share page as no provider port is available");
+      Cu.reportError("Can't mark page as no provider port is available");
       return;
     }
-    let url = this._getShareablePageUrl(aURI);
-    this._sharedUrls[url] = true;
-    port.postMessage({
-      topic: "social.user-recommend",
-      data: { url: url }
-    });
-    port.close();
+
+    // update or set our annotation
+    promiseGetAnnotation(aURI).then(function(val) {
+
+      let providerList = val ? JSON.parse(val) : [];
+      let marked = providerList.indexOf(this.provider.origin) >= 0;
+      if (marked)
+        return;
+      providerList.push(this.provider.origin);
+      // we allow marking links in a page that may not have been visited yet.
+      // make sure there is a history entry for the uri, then annotate it.
+      let place = {
+        uri: aURI,
+        visits: [{
+          visitDate: Date.now() + 1000,
+          transitionType: Ci.nsINavHistoryService.TRANSITION_LINK
+        }]
+      };
+      PlacesUtils.asyncHistory.updatePlaces(place, {
+        handleError: function () Cu.reportError("couldn't update history for socialmark annotation"),
+        handleResult: function () {},
+        handleCompletion: function () {
+          promiseSetAnnotation(aURI, providerList).then();
+          // post to the provider
+          let url = this._getMarkablePageUrl(aURI);
+          port.postMessage({
+            topic: "social.page-mark",
+            data: { url: url, 'marked': true }
+          });
+          port.close();
+          if (aCallback)
+            aCallback(true);
+        }.bind(this)
+      });
+    }.bind(this));
   },
-
-  unsharePage: function Social_unsharePage(aURI) {
+  
+  unmarkURI: function(aURI, aCallback) {
     // this should not be called if this.provider or the port is null
     if (!this.provider) {
-      Cu.reportError("Can't unshare a page when no provider is current");
+      Cu.reportError("Can't mark a page when no provider is current");
       return;
     }
     let port = this.provider.getWorkerPort();
     if (!port) {
-      Cu.reportError("Can't unshare page as no provider port is available");
+      Cu.reportError("Can't mark page as no provider port is available");
       return;
     }
-    let url = this._getShareablePageUrl(aURI);
-    delete this._sharedUrls[url];
-    port.postMessage({
-      topic: "social.user-unrecommend",
-      data: { url: url }
-    });
-    port.close();
+
+    // set our annotation
+    promiseGetAnnotation(aURI).then(function(val) {
+      let providerList = val ? JSON.parse(val) : [];
+      let marked = providerList.indexOf(this.provider.origin) >= 0;
+      if (marked) {
+        // remove the annotation
+        providerList.splice(providerList.indexOf(this.provider.origin), 1);
+        promiseSetAnnotation(aURI, providerList).then();
+      }
+      // post to the provider regardless
+      let url = this._getMarkablePageUrl(aURI);
+      port.postMessage({
+        topic: "social.page-mark",
+        data: { url: url, 'marked': false }
+      });
+      port.close();
+      if (aCallback)
+        aCallback(false);
+    }.bind(this));
   },
 
-  _sharedUrls: {},
-
   setErrorListener: function(iframe, errorHandler) {
     if (iframe.socialErrorListener)
       return iframe.socialErrorListener;
     return new SocialErrorListener(iframe, errorHandler);
   }
 };
 
 function schedule(callback) {
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -1429,90 +1429,20 @@ richlistitem[type~="action"][actiontype=
 
 /* Popup blocker button */
 #page-report-button {
   list-style-image: url("chrome://browser/skin/Info.png");
 }
 
 /* social recommending panel */
 
-#share-button {
+#social-mark-button {
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
-#socialUserPortrait {
-  width: 48px;
-  height: 48px;
-  list-style-image:url("chrome://global/skin/icons/information-32.png");
-}
-
-#socialUserDisplayName,
-#socialUserPortrait {
-  cursor: pointer;
-}
-
-#socialUserDisplayName {
-  -moz-appearance: none;
-  border: none;
-  background-color: transparent;
-  margin-top: 0;
-  padding-top: 0;
-  font-size: 130%;
-  font-weight: bold;
-}
-
-#socialUserDisplayName > .button-box {
-  -moz-padding-start: 0;
-  padding-top: 0;
-  border-top-width: 0;
-}
-
-#socialUserDisplayName:hover {
-  color: -moz-nativehyperlinktext;
-  text-decoration: underline;
-}
-
-#unsharePopupText {
-  height: 48px;
-}
-
-#unsharePopupBottomButtons {
-  margin-top: 1em;
-}
-
-/* bookmarks menu-button */
-
-#bookmarks-menu-button {
-  list-style-image: url("chrome://browser/skin/Toolbar.png");
-  -moz-image-region: rect(0px 216px 24px 192px);
-}
-
-#bookmarks-menu-button[starred] {
-  -moz-image-region: rect(24px 216px 48px 192px);
-}
-
-toolbar[iconsize="small"] #bookmarks-menu-button,
-#bookmarks-menu-button.bookmark-item {
-  list-style-image: url("chrome://browser/skin/Toolbar-small.png");
-  -moz-image-region: rect(0px 144px 16px 128px);
-}
-
-toolbar[iconsize="small"] #bookmarks-menu-button[starred],
-#bookmarks-menu-button.bookmark-item[starred] {
-  -moz-image-region: rect(16px 144px 32px 128px);
-}
-
-#bookmarks-menu-button[disabled] > .toolbarbutton-icon,
-#bookmarks-menu-button[disabled] > .toolbarbutton-menu-dropmarker,
-#bookmarks-menu-button[disabled] > .toolbarbutton-menubutton-dropmarker,
-#bookmarks-menu-button[disabled] > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
-#bookmarks-menu-button > .toolbarbutton-menubutton-button[disabled] > .toolbarbutton-icon {
-  opacity: .4;
-}
-
 /* Bookmarking panel */
 #editBookmarkPanelStarIcon {
   list-style-image: url("chrome://browser/skin/places/starred48.png");
   width: 48px;
   height: 48px;
 }
 
 #editBookmarkPanelStarIcon[unstarred] {
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -1652,75 +1652,20 @@ window[tabsontop="false"] richlistitem[t
   #page-report-button:hover:active,
   #page-report-button[open="true"] {
     -moz-image-region: rect(0, 64px, 32px, 32px);
   }
 }
 
 /* social recommending panel */
 
-#share-button {
+#social-mark-button {
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
-#socialUserPortrait {
-  width: 48px;
-  height: 48px;
-  list-style-image:url("chrome://global/skin/icons/information-32.png");
-}
-
-#socialUserDisplayName,
-#socialUserPortrait {
-  cursor: pointer;
-}
-
-#socialUserDisplayName {
-  -moz-appearance: none;
-  border: none;
-  background-color: transparent;
-  margin: 1px;
-  padding: 0;
-  font-size: 130%;
-  font-weight: bold;
-}
-
-#socialUserDisplayName > .button-box {
-  -moz-padding-start: 0;
-  padding-top: 0;
-  border-top-width: 0;
-}
-
-#socialUserDisplayName:hover {
-  color: -moz-nativehyperlinktext;
-  text-decoration: underline;
-}
-
-#unsharePopupText {
-  height: 48px;
-}
-
-#unsharePopupBottomButtons {
-  margin-top: 1em;
-}
-
-/* bookmarks menu-button */
-
-#bookmarks-menu-button {
-  -moz-image-region: rect(0px 500px 20px 480px);
-}
-
-#bookmarks-menu-button[starred] {
-  -moz-image-region: rect(20px 500px 40px 480px);
-}
-
-#bookmarks-menu-button.bookmark-item {
-  list-style-image: url("chrome://browser/skin/places/star-icons.png");
-  -moz-image-region: rect(0px 16px 16px 0px);
-}
-
 #bookmarks-menu-button.bookmark-item[starred] {
   -moz-image-region: rect(0px 32px 16px 16px);
 }
 
 #bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button {
   padding: 0;
 }
 
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -1701,75 +1701,20 @@ richlistitem[type~="action"][actiontype=
 
 #page-report-button:hover:active,
 #page-report-button[open="true"] {
   -moz-image-region: rect(0, 48px, 16px, 32px);
 }
 
 /* social recommending panel */
 
-#share-button {
+#social-mark-button {
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
-#socialUserPortrait {
-  width: 48px;
-  height: 48px;
-  list-style-image:url("chrome://global/skin/icons/information-32.png");
-}
-
-#socialUserDisplayName,
-#socialUserPortrait {
-  cursor: pointer;
-}
-
-#socialUserDisplayName {
-  -moz-appearance: none;
-  border: none;
-  background-color: transparent;
-  margin-top: 0;
-  padding-top: 0;
-  font-size: 130%;
-  font-weight: bold;
-}
-
-#socialUserDisplayName > .button-box {
-  -moz-padding-start: 0;
-  padding-top: 0;
-  border-top-width: 0;
-}
-
-#socialUserDisplayName:hover {
-  color: -moz-nativehyperlinktext;
-  text-decoration: underline;
-}
-
-#unsharePopupText {
-  height: 48px;
-}
-
-#unsharePopupBottomButtons {
-  margin-top: 1em;
-}
-
-/* bookmarks menu-button */
-
-#bookmarks-menu-button {
-  -moz-image-region: rect(0px 378px 18px 360px);
-}
-
-#bookmarks-menu-button[starred] {
-  -moz-image-region: rect(18px 378px 36px 360px);
-}
-
-#bookmarks-menu-button.bookmark-item {
-  list-style-image: url("chrome://browser/skin/places/bookmark.png");
-  -moz-image-region: rect(0px 16px 16px 0px);
-}
-
 #bookmarks-menu-button.bookmark-item[starred] {
   -moz-image-region: rect(0px 48px 16px 32px);
 }
 
 #bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button> .toolbarbutton-icon {
   -moz-margin-start: 5px;
 }
 
--- a/toolkit/components/social/SocialService.jsm
+++ b/toolkit/components/social/SocialService.jsm
@@ -622,72 +622,67 @@ SocialProvider.prototype = {
   // no FrameWorker)
   // This distinction might be used to cache certain data between runs - eg,
   // browser-social.js caches the notification icons so they can be displayed
   // quickly at startup without waiting for the provider to initialize -
   // 'undefined' means 'ok to use cached values' versus 'null' meaning 'cached
   // values aren't to be used as the user is logged out'.
   profile: undefined,
 
-  // Contains the information necessary to support our "recommend" feature.
+  // Contains the information necessary to support our page mark feature.
   // null means no info yet provided (which includes the case of the provider
   // not supporting the feature) or the provided data is invalid.  Updated via
-  // the 'recommendInfo' setter and returned via the getter.
-  _recommendInfo: null,
-  get recommendInfo() {
-    return this._recommendInfo;
+  // the 'pageMarkInfo' setter and returned via the getter.
+  _pageMarkInfo: null,
+  get pageMarkInfo() {
+    return this._pageMarkInfo;
   },
-  set recommendInfo(data) {
-    // Accept *and validate* the user-recommend-prompt-response message from
-    // the provider.
+  set pageMarkInfo(data) {
+    // Accept *and validate* the page-mark-config message from the provider.
     let promptImages = {};
     let promptMessages = {};
     function reportError(reason) {
-      Cu.reportError("Invalid recommend data from provider: " + reason + ": sharing is disabled for this provider");
-      // and we explicitly reset the recommend data to null to avoid stale
+      Cu.reportError("Invalid page-mark data from provider: " + reason + ": marking is disabled for this provider");
+      // and we explicitly reset the page-mark data to null to avoid stale
       // data being used and notify our observers.
-      this._recommendInfo = null;
-      Services.obs.notifyObservers(null, "social:recommend-info-changed", this.origin);
+      this._pageMarkInfo = null;
+      Services.obs.notifyObservers(null, "social:page-mark-config", this.origin);
     }
     if (!data ||
         !data.images || typeof data.images != "object" ||
         !data.messages || typeof data.messages != "object") {
       reportError("data is missing valid 'images' or 'messages' elements");
       return;
     }
-    for (let sub of ["share", "unshare"]) {
+    for (let sub of ["marked", "unmarked"]) {
       let url = data.images[sub];
       if (!url || typeof url != "string" || url.length == 0) {
-        reportError('images["' + sub + '"] is missing or not a non-empty string');
+        reportError('images["' + sub + '"] is not a valid string');
         return;
       }
       // resolve potentially relative URLs but there is no same-origin check
       // for images to help providers utilize content delivery networks...
       // Also note no scheme checks are necessary - even a javascript: URL
       // is safe as gecko evaluates them in a sandbox.
       let imgUri = this.resolveUri(url);
       if (!imgUri) {
         reportError('images["' + sub + '"] is an invalid URL');
         return;
       }
       promptImages[sub] = imgUri.spec;
     }
-    for (let sub of ["shareTooltip", "unshareTooltip",
-                     "sharedLabel", "unsharedLabel", "unshareLabel",
-                     "portraitLabel",
-                     "unshareConfirmLabel", "unshareConfirmAccessKey",
-                     "unshareCancelLabel", "unshareCancelAccessKey"]) {
+    for (let sub of ["markedTooltip", "unmarkedTooltip", "markedLabel", "unmarkedLabel"]) {
       if (typeof data.messages[sub] != "string" || data.messages[sub].length == 0) {
         reportError('messages["' + sub + '"] is not a valid string');
         return;
       }
       promptMessages[sub] = data.messages[sub];
     }
-    this._recommendInfo = {images: promptImages, messages: promptMessages};
-    Services.obs.notifyObservers(null, "social:recommend-info-changed", this.origin);
+    this._pageMarkInfo = {images: promptImages, messages: promptMessages};
+    Services.obs.notifyObservers(null, "social:page-mark-config", this.origin);
   },
 
   // Map of objects describing the provider's notification icons, whose
   // properties include:
   //   name, iconURL, counter, contentPanel
   // See https://developer.mozilla.org/en-US/docs/Social_API
   ambientNotificationIcons: null,
 
--- a/toolkit/components/social/WorkerAPI.jsm
+++ b/toolkit/components/social/WorkerAPI.jsm
@@ -53,24 +53,22 @@ WorkerAPI.prototype = {
       getFrameWorkerHandle(this._provider.workerURL, null)._worker.reload();
       // the frameworker is going to be reloaded, send the initialization
       // so it can have the same startup sequence as if it were loaded
       // the first time.  This will be queued until the frameworker is ready.
       this._port.postMessage({topic: "social.initialize"});
     },
     "social.user-profile": function (data) {
       this._provider.updateUserProfile(data);
-      // get the info we need for 'recommend' support.
-      this._port.postMessage({topic: "social.user-recommend-prompt"});
     },
     "social.ambient-notification": function (data) {
       this._provider.setAmbientNotification(data);
     },
-    "social.user-recommend-prompt-response": function(data) {
-      this._provider.recommendInfo = data;
+    "social.page-mark-config": function(data) {
+      this._provider.pageMarkInfo = data;
     },
     "social.cookies-get": function(data) {
       let document = this._port._window.document;
       let cookies = document.cookie.split(";");
       let results = [];
       cookies.forEach(function(aCookie) {
         let [name, value] = aCookie.split("=");
         results.push({name: unescape(name.trim()),