Bug 1014332 new about:providerdirectory page that appears in share panel, r=jaws
authorShane Caraveo <scaraveo@mozilla.com>
Thu, 09 Oct 2014 12:01:39 -0700
changeset 209694 63778f703ab45f0529ab099933d1ccd8fc1fcf5e
parent 209693 d09f5f86a80354563a0272758fd67ff84ef2501d
child 209695 1b1884049a6593a24c1981e31b4a44b51aecfc6e
push id27622
push userkwierso@gmail.com
push dateFri, 10 Oct 2014 04:19:07 +0000
treeherdermozilla-central@b91b22431613 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws
bugs1014332
milestone35.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 1014332 new about:providerdirectory page that appears in share panel, r=jaws
browser/app/profile/firefox.js
browser/base/content/aboutProviderDirectory.xhtml
browser/base/content/browser-social.js
browser/base/content/browser.xul
browser/base/jar.mn
browser/components/about/AboutRedirector.cpp
browser/components/build/nsModule.cpp
browser/locales/en-US/chrome/browser/browser.dtd
browser/themes/linux/aboutSocialError.css
browser/themes/linux/jar.mn
browser/themes/osx/aboutSocialError.css
browser/themes/osx/browser.css
browser/themes/osx/jar.mn
browser/themes/shared/aboutProviderDirectory.css
browser/themes/shared/aboutSocialError.css
browser/themes/shared/menupanel.inc.css
browser/themes/windows/aboutSocialError.css
browser/themes/windows/jar.mn
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1631,16 +1631,25 @@ pref("loop.rooms.enabled", false);
 pref("loop.fxa_oauth.tokendata", "");
 pref("loop.fxa_oauth.profile", "");
 
 // serverURL to be assigned by services team
 pref("services.push.serverURL", "wss://push.services.mozilla.com/");
 
 pref("social.sidebar.unload_timeout_ms", 10000);
 
+// activation from inside of share panel is possible if activationPanelEnabled
+// is true. Pref'd off for release while usage testing is done through beta.
+#ifdef EARLY_BETA_OR_EARLIER
+pref("social.share.activationPanelEnabled", true);
+#else
+pref("social.share.activationPanelEnabled", false);
+#endif
+pref("social.shareDirectory", "https://activations.cdn.mozilla.net/sharePanel.html");
+
 pref("dom.identity.enabled", false);
 
 // Block insecure active content on https pages
 pref("security.mixed_content.block_active_content", true);
 
 // 1 = allow MITM for certificate pinning checks.
 pref("security.cert_pinning.enforcement_level", 1);
 
new file mode 100644
--- /dev/null
+++ b/browser/base/content/aboutProviderDirectory.xhtml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- 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/. -->
+
+<!DOCTYPE html [
+  <!ENTITY % htmlDTD
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "DTD/xhtml1-strict.dtd">
+  %htmlDTD;
+  <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
+  %brandDTD;
+  <!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
+  %browserDTD;
+]>
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>&social.directory.label;</title>
+    <link rel="stylesheet" type="text/css" media="all"
+          href="chrome://browser/skin/aboutProviderDirectory.css"/>
+  </head>
+
+  <body>
+    <div id="activation-link" hidden="true">
+      <div id="message-box">
+        <p>&social.directory.text;</p>
+      </div>
+      <div id="button-box">
+        <button onclick="openDirectory()">&social.directory.button;</button>
+      </div>
+    </div>
+    <div id="activation" hidden="true">
+      <p>&social.directory.introText;</p>
+      <div><iframe id="activation-frame"/></div>
+      <p><a class="link" onclick="openDirectory()">&social.directory.viewmore.text;</a></p>
+    </div>
+  </body>
+
+  <script type="text/javascript;version=1.8"><![CDATA[
+    const Cu = Components.utils;
+
+    Cu.import("resource://gre/modules/Services.jsm");
+
+    function openDirectory() {
+      let url = Services.prefs.getCharPref("social.directories").split(',')[0];
+      window.open(url);
+      window.close();
+    }
+    
+    if (Services.prefs.getBoolPref("social.share.activationPanelEnabled")) {
+      let url = Services.prefs.getCharPref("social.shareDirectory");
+      document.getElementById("activation-frame").setAttribute("src", url);
+      document.getElementById("activation").removeAttribute("hidden");
+    } else {
+      document.getElementById("activation-link").removeAttribute("hidden");
+    }
+  ]]></script>
+</html>
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -43,16 +43,22 @@ XPCOMUtils.defineLazyGetter(this, "Creat
 });
 
 XPCOMUtils.defineLazyGetter(this, "CreateSocialMarkWidget", function() {
   let tmp = {};
   Cu.import("resource:///modules/Social.jsm", tmp);
   return tmp.CreateSocialMarkWidget;
 });
 
+XPCOMUtils.defineLazyGetter(this, "hookWindowCloseForPanelClose", function() {
+  let tmp = {};
+  Cu.import("resource://gre/modules/MozSocialAPI.jsm", tmp);
+  return tmp.hookWindowCloseForPanelClose;
+});
+
 SocialUI = {
   _initialized: false,
 
   // Called on delayed startup to initialize the UI
   init: function SocialUI_init() {
     if (this._initialized) {
       return;
     }
@@ -428,16 +434,22 @@ SocialFlyout = {
           Cu.reportError(e);
         }
       }
     });
   }
 }
 
 SocialShare = {
+  get _dynamicResizer() {
+    delete this._dynamicResizer;
+    this._dynamicResizer = new DynamicResizeWatcher();
+    return this._dynamicResizer;
+  },
+
   // Share panel may be attached to the overflow or menu button depending on
   // customization, we need to manage open state of the anchor.
   get anchor() {
     let widget = CustomizableUI.getWidget("social-share-button");
     return widget.forWindow(window).anchor;
   },
   get panel() {
     return document.getElementById("social-share-panel");
@@ -454,17 +466,17 @@ SocialShare = {
   uninit: function () {
     if (this.iframe) {
       this.iframe.remove();
     }
   },
 
   _createFrame: function() {
     let panel = this.panel;
-    if (!SocialUI.enabled || this.iframe)
+    if (this.iframe)
       return;
     this.panel.hidden = false;
     // create and initialize the panel for this window
     let iframe = document.createElement("browser");
     iframe.setAttribute("type", "content");
     iframe.setAttribute("class", "social-share-frame");
     iframe.setAttribute("context", "contentAreaContextMenu");
     iframe.setAttribute("tooltip", "aHTMLTooltip");
@@ -475,64 +487,49 @@ SocialShare = {
   },
 
   getSelectedProvider: function() {
     let provider;
     let lastProviderOrigin = this.iframe && this.iframe.getAttribute("origin");
     if (lastProviderOrigin) {
       provider = Social._getProviderFromOrigin(lastProviderOrigin);
     }
-    // if they have a provider selected in the sidebar use that for the initial
-    // default in share
-    if (!provider)
-      provider = SocialSidebar.provider;
-    // if our provider has no shareURL, select the first one that does
-    if (!provider || !provider.shareURL) {
-      let providers = [p for (p of Social.providers) if (p.shareURL)];
-      provider = providers.length > 0  && providers[0];
-    }
     return provider;
   },
 
   populateProviderMenu: function() {
     if (!this.iframe)
       return;
     let providers = [p for (p of Social.providers) if (p.shareURL)];
     let hbox = document.getElementById("social-share-provider-buttons");
-    // selectable providers are inserted before the provider-menu seperator,
-    // remove any menuitems in that area
-    while (hbox.firstChild) {
+    // remove everything before the add-share-provider button (which should also
+    // be lastChild if any share providers were added)
+    let addButton = document.getElementById("add-share-provider");
+    while (hbox.firstChild != addButton) {
       hbox.removeChild(hbox.firstChild);
     }
-    // reset our share toolbar
-    // only show a selection if there is more than one
-    if (!SocialUI.enabled || providers.length < 2) {
-      this.panel.firstChild.hidden = true;
-      return;
-    }
     let selectedProvider = this.getSelectedProvider();
     for (let provider of providers) {
       let button = document.createElement("toolbarbutton");
       button.setAttribute("class", "toolbarbutton share-provider-button");
       button.setAttribute("type", "radio");
       button.setAttribute("group", "share-providers");
       button.setAttribute("image", provider.iconURL);
       button.setAttribute("tooltiptext", provider.name);
       button.setAttribute("origin", provider.origin);
-      button.setAttribute("oncommand", "SocialShare.sharePage(this.getAttribute('origin')); this.checked=true;");
+      button.setAttribute("oncommand", "SocialShare.sharePage(this.getAttribute('origin'));");
       if (provider == selectedProvider) {
         this.defaultButton = button;
       }
-      hbox.appendChild(button);
+      hbox.insertBefore(button, addButton);
     }
     if (!this.defaultButton) {
-      this.defaultButton = hbox.firstChild
+      this.defaultButton = addButton;
     }
     this.defaultButton.setAttribute("checked", "true");
-    this.panel.firstChild.hidden = false;
   },
 
   get shareButton() {
     // web-panels (bookmark/sidebar) don't include customizableui, so
     // nsContextMenu fails when accessing shareButton, breaking
     // browser_bug409481.js.
     if (!window.CustomizableUI)
       return null;
@@ -615,23 +612,16 @@ SocialShare = {
   },
 
   sharePage: function(providerOrigin, graphData, target) {
     // if providerOrigin is undefined, we use the last-used provider, or the
     // current/default provider.  The provider selection in the share panel
     // will call sharePage with an origin for us to switch to.
     this._createFrame();
     let iframe = this.iframe;
-    let provider;
-    if (providerOrigin)
-      provider = Social._getProviderFromOrigin(providerOrigin);
-    else
-      provider = this.getSelectedProvider();
-    if (!provider || !provider.shareURL)
-      return;
 
     // graphData is an optional param that either defines the full set of data
     // to be shared, or partial data about the current page. It is set by a call
     // in mozSocial API, or via nsContentMenu calls. If it is present, it MUST
     // define at least url. If it is undefined, we're sharing the current url in
     // the browser tab.
     let pageData = graphData ? graphData : this.currentShare;
     let sharedURI = pageData ? Services.io.newURI(pageData.url, null, null) :
@@ -653,42 +643,48 @@ SocialShare = {
       }
     }
     // if this is a share of a selected item, get any microdata
     if (!pageData.microdata && target) {
       pageData.microdata = OpenGraphBuilder.getMicrodata(gBrowser, target);
     }
     this.currentShare = pageData;
 
+    let provider;
+    if (providerOrigin)
+      provider = Social._getProviderFromOrigin(providerOrigin);
+    else
+      provider = this.getSelectedProvider();
+    if (!provider || !provider.shareURL) {
+      this.showDirectory();
+      return;
+    }
+    // check the menu button
+    let hbox = document.getElementById("social-share-provider-buttons");
+    let btn = hbox.querySelector("[origin='" + provider.origin + "']");
+    if (btn)
+      btn.checked = true;
+
     let shareEndpoint = OpenGraphBuilder.generateEndpointURL(provider.shareURL, pageData);
 
     let size = provider.getPageSize("share");
     if (size) {
-      if (this._dynamicResizer) {
-        this._dynamicResizer.stop();
-        this._dynamicResizer = null;
-      }
-      let {width, height} = size;
-      width += this.panel.boxObject.width - iframe.boxObject.width;
-      height += this.panel.boxObject.height - iframe.boxObject.height;
-      this.panel.sizeTo(width, height);
-    } else {
-      this._dynamicResizer = new DynamicResizeWatcher();
+      this._dynamicResizer.stop();
     }
 
     // if we've already loaded this provider/page share endpoint, we don't want
     // to add another load event listener.
     let reload = true;
     let endpointMatch = shareEndpoint == iframe.getAttribute("src");
     let docLoaded = iframe.contentDocument && iframe.contentDocument.readyState == "complete";
     if (endpointMatch && docLoaded) {
       reload = shareEndpoint != iframe.contentDocument.location.spec;
     }
     if (!reload) {
-      if (this._dynamicResizer)
+      if (!size)
         this._dynamicResizer.start(this.panel, iframe);
       iframe.docShell.isActive = true;
       iframe.docShell.isAppTab = true;
       let evt = iframe.contentDocument.createEvent("CustomEvent");
       evt.initCustomEvent("OpenGraphData", true, true, JSON.stringify(pageData));
       iframe.contentDocument.documentElement.dispatchEvent(evt);
     } else {
       // first time load, wait for load and dispatch after load
@@ -696,17 +692,23 @@ SocialShare = {
         iframe.removeEventListener("load", panelBrowserOnload, true);
         iframe.docShell.isActive = true;
         iframe.docShell.isAppTab = true;
         // to support standard share endpoints mimick window.open by setting
         // window.opener, some share endpoints rely on w.opener to know they
         // should close the window when done.
         iframe.contentWindow.opener = iframe.contentWindow;
         setTimeout(function() {
-          if (SocialShare._dynamicResizer) { // may go null if hidden quickly
+          if (size) {
+            let panel = SocialShare.panel;
+            let {width, height} = size;
+            width += panel.boxObject.width - iframe.boxObject.width;
+            height += panel.boxObject.height - iframe.boxObject.height;
+            panel.sizeTo(width, height);
+          } else {
             SocialShare._dynamicResizer.start(iframe.parentNode, iframe);
           }
         }, 0);
         let evt = iframe.contentDocument.createEvent("CustomEvent");
         evt.initCustomEvent("OpenGraphData", true, true, JSON.stringify(pageData));
         iframe.contentDocument.documentElement.dispatchEvent(evt);
       }, true);
     }
@@ -717,20 +719,41 @@ SocialShare = {
       if (purge > 0)
         iframe.sessionHistory.PurgeHistory(purge);
     }
 
     // always ensure that origin belongs to the endpoint
     let uri = Services.io.newURI(shareEndpoint, null, null);
     iframe.setAttribute("origin", provider.origin);
     iframe.setAttribute("src", shareEndpoint);
+    this._openPanel();
+  },
 
+  showDirectory: function() {
+    this._createFrame();
+    let iframe = this.iframe;
+    iframe.removeAttribute("origin");
+    iframe.addEventListener("load", function panelBrowserOnload(e) {
+      iframe.removeEventListener("load", panelBrowserOnload, true);
+      hookWindowCloseForPanelClose(iframe.contentWindow);
+      SocialShare._dynamicResizer.start(iframe.parentNode, iframe);
+
+      iframe.addEventListener("unload", function panelBrowserOnload(e) {
+        iframe.removeEventListener("unload", panelBrowserOnload, true);
+        SocialShare._dynamicResizer.stop();
+      }, true);
+    }, true);
+    iframe.setAttribute("src", "about:providerdirectory");
+    this._openPanel();
+  },
+
+  _openPanel: function() {
     let anchor = document.getAnonymousElementByAttribute(this.anchor, "class", "toolbarbutton-icon");
     this.panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
-    Social.setErrorListener(iframe, this.setErrorMessage.bind(this));
+    Social.setErrorListener(this.iframe, this.setErrorMessage.bind(this));
     Services.telemetry.getHistogramById("SOCIAL_TOOLBAR_BUTTONS").add(0);
   }
 };
 
 SocialSidebar = {
   _openStartTime: 0,
 
   // Whether the sidebar can be shown for this window.
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -241,17 +241,21 @@
     <panel id="social-share-panel"
            class="social-panel"
            type="arrow"
            orient="horizontal"
            onpopupshowing="SocialShare.onShowing()"
            onpopuphidden="SocialShare.onHidden()"
            hidden="true">
       <vbox class="social-share-toolbar">
-        <arrowscrollbox id="social-share-provider-buttons" orient="vertical" flex="1"/>
+        <arrowscrollbox id="social-share-provider-buttons" orient="vertical" flex="1">
+          <toolbarbutton id="add-share-provider" class="toolbarbutton share-provider-button" type="radio"
+                         group="share-providers" tooltiptext="&findShareServices.label;"
+                         oncommand="SocialShare.showDirectory()"/>
+        </arrowscrollbox>
       </vbox>
     </panel>
 
     <panel id="social-notification-panel"
            class="social-panel"
            type="arrow"
            hidden="true"
            noautofocus="true"/>
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -63,16 +63,17 @@ browser.jar:
         content/browser/aboutaccounts/images/graphic_sync_intro@2x.png        (content/aboutaccounts/images/graphic_sync_intro@2x.png)
 
         content/browser/certerror/aboutCertError.xhtml     (content/aboutcerterror/aboutCertError.xhtml)
         content/browser/certerror/aboutCertError.css       (content/aboutcerterror/aboutCertError.css)
 
         content/browser/aboutRobots-icon.png          (content/aboutRobots-icon.png)
         content/browser/aboutRobots-widget-left.png   (content/aboutRobots-widget-left.png)
         content/browser/aboutSocialError.xhtml        (content/aboutSocialError.xhtml)
+        content/browser/aboutProviderDirectory.xhtml  (content/aboutProviderDirectory.xhtml)
         content/browser/aboutTabCrashed.js            (content/aboutTabCrashed.js)
         content/browser/aboutTabCrashed.xhtml         (content/aboutTabCrashed.xhtml)
 *       content/browser/browser.css                   (content/browser.css)
 *       content/browser/browser.js                    (content/browser.js)
 *       content/browser/browser.xul                   (content/browser.xul)
 *       content/browser/browser-tabPreviews.xml       (content/browser-tabPreviews.xml)
 *       content/browser/chatWindow.xul                (content/chatWindow.xul)
         content/browser/content.js                    (content/content.js)
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -42,16 +42,19 @@ static RedirEntry kRedirMap[] = {
 #endif
   { "certerror", "chrome://browser/content/certerror/aboutCertError.xhtml",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::ALLOW_SCRIPT |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT },
   { "socialerror", "chrome://browser/content/aboutSocialError.xhtml",
     nsIAboutModule::ALLOW_SCRIPT |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT },
+  { "providerdirectory", "chrome://browser/content/aboutProviderDirectory.xhtml",
+    nsIAboutModule::ALLOW_SCRIPT |
+    nsIAboutModule::HIDE_FROM_ABOUTABOUT },
   { "tabcrashed", "chrome://browser/content/aboutTabCrashed.xhtml",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::ALLOW_SCRIPT |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT },
   { "feeds", "chrome://browser/content/feeds/subscribe.xhtml",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::ALLOW_SCRIPT |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT },
--- a/browser/components/build/nsModule.cpp
+++ b/browser/components/build/nsModule.cpp
@@ -85,16 +85,17 @@ static const mozilla::Module::ContractID
     { NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
 #endif
     { NS_FEEDSNIFFER_CONTRACTID, &kNS_FEEDSNIFFER_CID },
 #ifdef MOZ_SAFE_BROWSING
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "blocked", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
 #endif
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "certerror", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "socialerror", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
+    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "providerdirectory", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "tabcrashed", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "feeds", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "privatebrowsing", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "rights", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "robots", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "sessionrestore", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "welcomeback", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
 #ifdef MOZ_SERVICES_SYNC
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -135,16 +135,20 @@ These should match what Safari and other
 <!ENTITY closeWindow.accesskey "d">
 
 <!ENTITY bookmarksMenu.label "Bookmarks">
 <!ENTITY bookmarksMenu.accesskey "B">
 <!ENTITY bookmarkThisPageCmd.label "Bookmark This Page">
 <!ENTITY editThisBookmarkCmd.label "Edit This Bookmark">
 <!ENTITY bookmarkThisPageCmd.commandkey "d">
 <!ENTITY markPageCmd.commandkey "l">
+<!-- LOCALIZATION NOTE (findShareServices.label):
+  -  Use the unicode ellipsis char, \u2026,
+  -  or use "..." if \u2026 doesn't suit traditions in your locale. -->
+<!ENTITY findShareServices.label "Find more Share services…">
 <!ENTITY sharePageCmd.label "Share This Page">
 <!ENTITY sharePageCmd.commandkey "S">
 <!ENTITY sharePageCmd.accesskey "s">
 <!ENTITY shareLinkCmd.label "Share This Link">
 <!ENTITY shareLinkCmd.accesskey "s">
 <!ENTITY shareImageCmd.label "Share This Image">
 <!ENTITY shareImageCmd.accesskey "s">
 <!ENTITY shareSelectCmd.label "Share Selection">
@@ -687,17 +691,21 @@ just addresses the organization to follo
 
 <!ENTITY social.activated.description "Services from <label/> have been enabled. You can change your settings for services in the <label class='text-link'>Add-on Manager</label>.">
 <!ENTITY social.activated.undo.label "Oops, undo this!">
 <!ENTITY social.activated.undo.accesskey "U">
 <!ENTITY social.learnMore.label "Learn more…">
 <!ENTITY social.learnMore.accesskey "l">
 <!ENTITY social.closeNotificationItem.label "Not Now">
 
-
+<!ENTITY social.directory.label "Activations Directory">
+<!ENTITY social.directory.text "You can activate Share services from the directory.">
+<!ENTITY social.directory.button "Take me there!">
+<!ENTITY social.directory.introText "Click on a service to add it to &brandShortName;.">
+<!ENTITY social.directory.viewmore.text "View More">
 
 <!ENTITY customizeMode.tabTitle "Customize &brandShortName;">
 <!ENTITY customizeMode.menuAndToolbars.header2 "Additional Tools and Features">
 <!ENTITY customizeMode.menuAndToolbars.empty "Want more tools?">
 <!ENTITY customizeMode.menuAndToolbars.emptyLink "Choose from thousands of add-ons">
 <!ENTITY customizeMode.restoreDefaults "Restore Defaults">
 <!ENTITY customizeMode.toolbars "Show / Hide Toolbars">
 <!ENTITY customizeMode.titlebar "Title Bar">
deleted file mode 100644
--- a/browser/themes/linux/aboutSocialError.css
+++ /dev/null
@@ -1,98 +0,0 @@
-body {
-  background-color: rgb(241, 244, 248);
-  margin-top: 2em;
-  font: message-box;
-  font-size: 100%;
-}
-
-p {
-  font-size: .8em;
-}
-
-#error-box {
-  background: url('chrome://global/skin/icons/information-24.png') no-repeat left 4px;
-  -moz-padding-start: 30px;
-}
-
-#error-box:-moz-locale-dir(rtl) {
-  background-position: right 4px;
-}
-
-#main-error-msg {
-  color: #4b4b4b;
-  font-weight: bold;
-}
-
-
-#button-box {
-  text-align: center;
-  width: 75%;
-  margin: 0 auto;
-}
-
-@media all and (min-width: 300px) {
-  #error-box {
-    max-width: 50%;
-    margin: 0 auto;
-    background-image: url('chrome://global/skin/icons/information-32.png');
-    min-height: 36px;
-    -moz-padding-start: 38px;
-  }
-
-  button {
-    width: auto !important;
-    min-width: 150px;
-  }
-}
-
-@media all and (min-width: 780px) {
-  #error-box {
-    max-width: 30%;
-  }
-}
-
-button {
-  font: message-box;
-  font-size: 0.6875em;
-  -moz-appearance: none;
-  -moz-user-select: none;
-  width: 100%;
-  margin: 2px 0;
-  padding: 2px 6px;
-  line-height: 1.2;
-  background-color: hsla(210,30%,95%,.1);
-  background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
-  background-clip: padding-box;
-  border: 1px solid hsla(210,15%,25%,.4);
-  border-color: hsla(210,15%,25%,.3) hsla(210,15%,25%,.35) hsla(210,15%,25%,.4);
-  border-radius: 3px;
-  box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
-              0 0 0 1px hsla(0,0%,100%,.3) inset,
-              0 1px 0 hsla(0,0%,100%,.1);
-
-  transition-property: background-color, border-color, box-shadow;
-  transition-duration: 150ms;
-  transition-timing-function: ease;
-
-}
-
-button:hover {
-  background-color: hsla(210,30%,95%,.8);
-  border-color: hsla(210,15%,25%,.45) hsla(210,15%,25%,.5) hsla(210,15%,25%,.55);
-  box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
-              0 0 0 1px hsla(0,0%,100%,.3) inset,
-              0 1px 0 hsla(0,0%,100%,.1),
-              0 0 3px hsla(210,15%,25%,.1);
-  transition-property: background-color, border-color, box-shadow;
-  transition-duration: 150ms;
-  transition-timing-function: ease;
-}
-
-button:hover:active {
-  background-color: hsla(210,15%,25%,.2);
-  box-shadow: 0 1px 1px hsla(210,15%,25%,.2) inset,
-              0 0 2px hsla(210,15%,25%,.4) inset;
-  transition-property: background-color, border-color, box-shadow;
-  transition-duration: 10ms;
-  transition-timing-function: linear;
-}
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -10,17 +10,18 @@ browser.jar:
   skin/classic/browser/aboutSessionRestore-window-icon.png
   skin/classic/browser/aboutWelcomeBack.css                     (../shared/aboutWelcomeBack.css)
   skin/classic/browser/aboutCertError.css
   skin/classic/browser/aboutCertError_sectionCollapsed.png
   skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
   skin/classic/browser/aboutCertError_sectionExpanded.png
   skin/classic/browser/aboutNetError.css                        (../shared/aboutNetError.css)
   skin/classic/browser/aboutNetError_info.svg                   (../shared/aboutNetError_info.svg)
-  skin/classic/browser/aboutSocialError.css
+  skin/classic/browser/aboutSocialError.css                     (../shared/aboutSocialError.css)
+* skin/classic/browser/aboutProviderDirectory.css               (../shared/aboutProviderDirectory.css)
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/aboutSyncTabs.css
 #endif
   skin/classic/browser/aboutTabCrashed.css
   skin/classic/browser/actionicon-tab.png
 * skin/classic/browser/browser.css
 * skin/classic/browser/devedition.css
 * skin/classic/browser/browser-lightweightTheme.css
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -1363,16 +1363,21 @@ toolbar .toolbarbutton-1 > .toolbarbutto
 
   #PanelUI-fxa-status > .toolbarbutton-icon,
   #PanelUI-quit > .toolbarbutton-icon,
   #PanelUI-customize > .toolbarbutton-icon,
   #PanelUI-help > .toolbarbutton-icon {
     width: 16px;
   }
 
+  #add-share-provider {
+    list-style-image: url(chrome://browser/skin/menuPanel-small@2x.png);
+    -moz-image-region: rect(0px, 192px, 32px, 160px);
+  }
+
   #loop-call-button > .toolbarbutton-badge-container {
     list-style-image: url("chrome://browser/skin/loop/toolbar@2x.png");
     -moz-image-region: rect(0, 36px, 36px, 0);
   }
 
   toolbar[brighttext] #loop-call-button > .toolbarbutton-badge-container {
     list-style-image: url("chrome://browser/skin/loop/toolbar-inverted@2x.png");
   }
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -9,17 +9,18 @@ browser.jar:
   skin/classic/browser/aboutNetError_info.svg               (../shared/aboutNetError_info.svg)
 * skin/classic/browser/aboutSessionRestore.css              (aboutSessionRestore.css)
   skin/classic/browser/aboutSessionRestore-window-icon.png
   skin/classic/browser/aboutWelcomeBack.css                 (../shared/aboutWelcomeBack.css)
   skin/classic/browser/aboutCertError.css
   skin/classic/browser/aboutCertError_sectionCollapsed.png
   skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
   skin/classic/browser/aboutCertError_sectionExpanded.png
-  skin/classic/browser/aboutSocialError.css
+  skin/classic/browser/aboutSocialError.css                 (../shared/aboutSocialError.css)
+* skin/classic/browser/aboutProviderDirectory.css           (../shared/aboutProviderDirectory.css)
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/aboutSyncTabs.css
 #endif
   skin/classic/browser/aboutTabCrashed.css
   skin/classic/browser/actionicon-tab.png
   skin/classic/browser/actionicon-tab@2x.png
 * skin/classic/browser/browser.css                          (browser.css)
 * skin/classic/browser/devedition.css
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/aboutProviderDirectory.css
@@ -0,0 +1,30 @@
+%include aboutSocialError.css
+
+body {
+  width: 310px;
+  margin: 1em auto;
+}
+
+#message-box {
+  margin-top: 2em;
+  background: url('chrome://global/skin/icons/information-24.png') no-repeat left 4px;
+  -moz-padding-start: 30px;
+}
+
+#activation-frame {
+  border: none;
+  margin: 0;
+  width: 310px;
+  height: 200px;
+}
+#activation > p {
+  width: 100%;
+  text-align: center;
+  margin: 0;
+  line-height: 2em;
+}
+.link {
+  text-decoration: none;
+  color: -moz-nativehyperlinktext;
+  cursor: pointer;
+}
rename from browser/themes/osx/aboutSocialError.css
rename to browser/themes/shared/aboutSocialError.css
--- a/browser/themes/shared/menupanel.inc.css
+++ b/browser/themes/shared/menupanel.inc.css
@@ -229,8 +229,13 @@ toolbarpaletteitem[place="palette"] > #e
 toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-out-button {
   -moz-image-region: rect(0px, 80px, 16px, 64px);
 }
 
 #zoom-controls@inAnyPanel@ > #zoom-in-button,
 toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-in-button {
   -moz-image-region: rect(0px, 96px, 16px, 80px);
 }
+
+#add-share-provider {
+  list-style-image: url(chrome://browser/skin/menuPanel-small.png);
+  -moz-image-region: rect(0px, 96px, 16px, 80px);
+}
\ No newline at end of file
deleted file mode 100644
--- a/browser/themes/windows/aboutSocialError.css
+++ /dev/null
@@ -1,98 +0,0 @@
-body {
-  background-color: rgb(241, 244, 248);
-  margin-top: 2em;
-  font: message-box;
-  font-size: 100%;
-}
-
-p {
-  font-size: .8em;
-}
-
-#error-box {
-  background: url('chrome://global/skin/icons/information-24.png') no-repeat left 4px;
-  -moz-padding-start: 30px;
-}
-
-#error-box:-moz-locale-dir(rtl) {
-  background-position: right 4px;
-}
-
-#main-error-msg {
-  color: #4b4b4b;
-  font-weight: bold;
-}
-
-
-#button-box {
-  text-align: center;
-  width: 75%;
-  margin: 0 auto;
-}
-
-@media all and (min-width: 300px) {
-  #error-box {
-    max-width: 50%;
-    margin: 0 auto;
-    background-image: url('chrome://global/skin/icons/information-32.png');
-    min-height: 36px;
-    -moz-padding-start: 38px;
-  }
-
-  button {
-    width: auto !important;
-    min-width: 150px;
-  }
-}
-
-@media all and (min-width: 780px) {
-  #error-box {
-    max-width: 30%;
-  }
-}
-
-button {
-  font: message-box;
-  font-size: 0.6875em;
-  -moz-appearance: none;
-  -moz-user-select: none;
-  width: 100%;
-  margin: 2px 0;
-  padding: 2px 6px;
-  line-height: 1.2;
-  background-color: hsla(210,30%,95%,.1);
-  background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
-  background-clip: padding-box;
-  border: 1px solid hsla(210,15%,25%,.4);
-  border-color: hsla(210,15%,25%,.3) hsla(210,15%,25%,.35) hsla(210,15%,25%,.4);
-  border-radius: 3px;
-  box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
-              0 0 0 1px hsla(0,0%,100%,.3) inset,
-              0 1px 0 hsla(0,0%,100%,.1);
-
-  transition-property: background-color, border-color, box-shadow;
-  transition-duration: 150ms;
-  transition-timing-function: ease;
-
-}
-
-button:hover {
-  background-color: hsla(210,30%,95%,.8);
-  border-color: hsla(210,15%,25%,.45) hsla(210,15%,25%,.5) hsla(210,15%,25%,.55);
-  box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
-              0 0 0 1px hsla(0,0%,100%,.3) inset,
-              0 1px 0 hsla(0,0%,100%,.1),
-              0 0 3px hsla(210,15%,25%,.1);
-  transition-property: background-color, border-color, box-shadow;
-  transition-duration: 150ms;
-  transition-timing-function: ease;
-}
-
-button:hover:active {
-  background-color: hsla(210,15%,25%,.2);
-  box-shadow: 0 1px 1px hsla(210,15%,25%,.2) inset,
-              0 0 2px hsla(210,15%,25%,.4) inset;
-  transition-property: background-color, border-color, box-shadow;
-  transition-duration: 10ms;
-  transition-timing-function: linear;
-}
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -12,17 +12,18 @@ browser.jar:
         skin/classic/browser/aboutSessionRestore-window-icon.png     (preferences/application.png)
         skin/classic/browser/aboutWelcomeBack.css                    (../shared/aboutWelcomeBack.css)
         skin/classic/browser/aboutCertError.css
         skin/classic/browser/aboutCertError_sectionCollapsed.png
         skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
         skin/classic/browser/aboutCertError_sectionExpanded.png
         skin/classic/browser/aboutNetError.css                       (../shared/aboutNetError.css)
         skin/classic/browser/aboutNetError_info.svg                  (../shared/aboutNetError_info.svg)
-        skin/classic/browser/aboutSocialError.css
+        skin/classic/browser/aboutSocialError.css                    (../shared/aboutSocialError.css)
+*       skin/classic/browser/aboutProviderDirectory.css              (../shared/aboutProviderDirectory.css)
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/browser/aboutSyncTabs.css
 #endif
         skin/classic/browser/aboutTabCrashed.css
         skin/classic/browser/actionicon-tab.png
 *       skin/classic/browser/browser.css
 *       skin/classic/browser/devedition.css
 *       skin/classic/browser/browser-lightweightTheme.css
@@ -434,17 +435,18 @@ browser.jar:
 *       skin/classic/aero/browser/aboutSessionRestore.css            (aboutSessionRestore.css)
         skin/classic/aero/browser/aboutSessionRestore-window-icon.png (aboutSessionRestore-window-icon-aero.png)
         skin/classic/aero/browser/aboutCertError.css
         skin/classic/aero/browser/aboutCertError_sectionCollapsed.png
         skin/classic/aero/browser/aboutCertError_sectionCollapsed-rtl.png
         skin/classic/aero/browser/aboutCertError_sectionExpanded.png
         skin/classic/aero/browser/aboutNetError.css                   (../shared/aboutNetError.css)
         skin/classic/aero/browser/aboutNetError_info.svg              (../shared/aboutNetError_info.svg)
-        skin/classic/aero/browser/aboutSocialError.css
+        skin/classic/aero/browser/aboutSocialError.css                (../shared/aboutSocialError.css)
+*       skin/classic/aero/browser/aboutProviderDirectory.css          (../shared/aboutProviderDirectory.css)
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/aero/browser/aboutSyncTabs.css
 #endif
         skin/classic/aero/browser/aboutTabCrashed.css
         skin/classic/aero/browser/aboutWelcomeBack.css               (../shared/aboutWelcomeBack.css)
         skin/classic/aero/browser/actionicon-tab.png
 *       skin/classic/aero/browser/browser.css                        (browser-aero.css)
 *       skin/classic/aero/browser/devedition.css                     (devedition-aero.css)